[Checkins] SVN: zopeorg.buildout/branches/beta.zope.org/ ADDED
Andreas Jung
andreas at andreas-jung.com
Mon May 9 08:32:57 EDT 2011
Log message for revision 121636:
ADDED
Changed:
A zopeorg.buildout/branches/beta.zope.org/README.txt
A zopeorg.buildout/branches/beta.zope.org/bin/
A zopeorg.buildout/branches/beta.zope.org/bin/activate
A zopeorg.buildout/branches/beta.zope.org/bin/activate_this.py
A zopeorg.buildout/branches/beta.zope.org/bin/cheetah
A zopeorg.buildout/branches/beta.zope.org/bin/cheetah-compile
A zopeorg.buildout/branches/beta.zope.org/bin/easy_install
A zopeorg.buildout/branches/beta.zope.org/bin/easy_install-2.6
A zopeorg.buildout/branches/beta.zope.org/bin/paster
A zopeorg.buildout/branches/beta.zope.org/bin/pip
A zopeorg.buildout/branches/beta.zope.org/bin/python
A zopeorg.buildout/branches/beta.zope.org/bin/zopeskel
A zopeorg.buildout/branches/beta.zope.org/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/buildout.cfg
A zopeorg.buildout/branches/beta.zope.org/include/
A zopeorg.buildout/branches/beta.zope.org/include/python2.6
A zopeorg.buildout/branches/beta.zope.org/lib/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/UserDict.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/_abcoll.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/abc.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/codecs.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/config
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/copy_reg.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/distutils.cfg
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/encodings
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/fnmatch.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/genericpath.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/lib-dynload
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/linecache.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/locale.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/no-global-site-packages.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/ntpath.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/orig-prefix.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/os.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/posixpath.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/re.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheRegion.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheStore.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CheetahWrapper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Compiler.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Django.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/DummyTransaction.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ErrorCatchers.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/FileUtils.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Filters.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportHooks.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportManager.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/I18n.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/NameMapper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Parser.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Servlet.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SettingsManager.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SourceReader.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Template.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/TemplateCmdLineIface.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/_SkeletonPage.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/CheetahWrapper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Filters.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/NameMapper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Regressions.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/SyntaxAndOutput.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Template.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Test.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Unicode.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/unittest_local_copy.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/xmlrunner.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/CGITemplate.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReport.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReportDoc.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/RecursiveNull.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/SiteHierarchy.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Unspecified.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Indenter.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Misc.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/VerifyType.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/WebInputMixin.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlDecode.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlEncode.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/memcache.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/statprof.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Version.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.so
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockparser.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockprocessors.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/commandline.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/etree_loader.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/html4.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/inlinepatterns.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/odict.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/postprocessors.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/preprocessors.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/treeprocessors.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/convertTmplPathToModuleName.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/native_libs.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah-compile
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/entry_points.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/namespace_packages.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/requires.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/auth_tkt.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/basic.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cas.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cookie.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/digest.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/form.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/grantip.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/multi.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/open_id.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cascade.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgiapp.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgitb_catcher.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/config.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cowbell/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cowbell/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/debugapp.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/doctest_webapp.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/fsdiff.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/prints.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/profile.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/testserver.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/watchthreads.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/wdg_validate.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/errordocument.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/evalcontext.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/MochiKit.packed.js
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/debug.js
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/minus.jpg
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/plus.jpg
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/middleware.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/collector.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/errormiddleware.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/formatter.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/reporter.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/serial_number_generator.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fileapp.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fixture.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/flup_session.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/gzipper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpexceptions.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpheaders.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpserver.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/lint.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/modpython.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/pony.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/progress.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/proxy.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/recursive.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/reloader.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/request.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/response.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/session.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/transaction.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/translogger.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/url.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlmap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlparser.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/PySourceColor.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/UserDict24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinit.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinstance.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/converters.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/dateinterval.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/datetimeutil.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/doctest24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/filemixin.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/finddata.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/findpackage.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/import_string.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/intset.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/ip4.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/killthread.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/looper.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/mimeparse.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/multidict.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/quoting.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/scgiserver.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/string24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/subprocess24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/template.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadedprint.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadinglocal.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgilib.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgiwrappers.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/entry_points.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/namespace_packages.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/requires.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/config.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/converters.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/epdesc.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/interfaces.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/loadwsgi.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/paster_templates.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/fixtypeerror.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/threadinglocal.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/finddata.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/fixture.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_basic_app.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config_middleware.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_filter.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_load_package.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/entry_points.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/namespace_packages.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/requires.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/scripts/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/scripts/paster
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/appinstall.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/bool_optparse.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cgi_server.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/checkperms.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cherrypy_server.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/command.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/copydir.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/create_distro.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/default_sysconfig.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/entrypoints.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/epdesc.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/exe.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/filemaker.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/flup_server.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/grep.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/help.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/interfaces.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/+package+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.cfg
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/pluginlib.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/request.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/serve.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/templates.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/testapp.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/twisted_web2_server.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/logging_config.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/secret.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/string24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/subprocess24.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/uuid.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiutils_server.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/entry_points.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/requires.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_zope.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/archetype.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/base.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_namespace.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_zope.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/archetypes.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/atschema.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_namespace.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_zope.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/kss_plugin.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/localcommands.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/nested_namespace.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_buildout.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_theme.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone2_theme.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_buildout.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_portlet.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_theme.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone4_buildout.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_app.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_pas.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/recipe.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/silva_buildout.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/hosting.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/interfaces.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/kss_plugin.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/archetype.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone_pas.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/+content_class_filename+.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/messagefactory_insert.txt_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/schema_field_bridge.txt_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/+interface_name+.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/additional_imports.txt_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/README.txt_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/config.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/+content_class_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/+content_class_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/factorytool.xml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/rolemap.xml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/+types_xml_filename+.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types.xml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/+interface_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/default/browserlayer.xml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/+form_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/form.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/browser/+form_filename+.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.pt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/metadata.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/portlets.xml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/base_+portlet_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/test_+portlet_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.pt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/configure.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/meta.zcml_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metaconfigure.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metadirectives.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/anonymous_user_factory.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/authentication.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/challenge.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/credentials_reset.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/credentials_update.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/extraction.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/group_enumeration.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/groups.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/properties.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/role_assigner.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/role_enumeration.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/roles.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/update.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/user_adder.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/user_enumeration.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/user_factory.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/interface.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugin.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/__init__.py_insert
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/validation.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/nested_namespace.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_theme.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone2_theme.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_portlet.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_theme.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone4_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_app.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_pas.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/recipe.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/silva_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/config.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/factorytool.xml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/portlets.xml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/types.xml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/base.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/test_doctest.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CHANGES.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CONTRIBUTORS.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/MANIFEST.in_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/docs/HISTORY.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/tests.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/zope2.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+project+-configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/+namespace_package+.+namespace_package2+.+package+-configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.kss
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.pt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/zopeconfig.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/+package+.js_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/docs/HISTORY.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/docs/HISTORY.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/INSTALL.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.GPL
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_buildout/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_buildout/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/Install.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/config.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/import_steps.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/setuphandlers.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base_properties.props_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/generated.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/portlets.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/public.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/CONTENT.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/+package+.css.dtml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/CONTENT.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/version.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/MANIFEST.in_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/Install.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/utils.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/HISTORY.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/config.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/+package+.css.dtml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base_properties.props_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/generated.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/portlets.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/public.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/framework.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/runalltests.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testSkeleton.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testStyleInstallation.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/version.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/products/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/products/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/src/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/var/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/var/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.pt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/metadata.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/portlets.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/base.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/test_portlet.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/INSTALL.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.GPL
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/interfaces.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/main.css_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlet.pt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlets.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/+namespace_package+.+package+_various.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/viewlets.xml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/setuphandlers.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/CONTENT.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base_properties.props_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/portlets.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/public.css.dtml
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/version.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+project+-configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/MANIFEST.in_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/src/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/var/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/var/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/INSTALL.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.GPL
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/base.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/etc/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/etc/supervisord.conf_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/products/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/products/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/src/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/templates/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/templates/logrotate.conf
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/var/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/var/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/add_plugin.zpt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/icon.gif
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/install.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/interface.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugin.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CHANGES.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CONTRIBUTORS.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/INSTALL.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.GPL
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/test_docs.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/__init__.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CHANGES.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CONTRIBUTORS.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/README.txt_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/setup.py_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/products/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/products/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/src/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/var/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/var/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/bootstrap.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/buildout.cfg_tmpl
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/products/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/products/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/src/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/var/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/var/README.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_all.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_base.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_vars.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskel_script.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskeldocs.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/ui.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/vars.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zope2_buildout.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zopeskel_script.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/easy-install.pth
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/PKG-INFO
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/SOURCES.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/dependency_links.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/entry_points.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/not-zip-safe
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/top_level.txt
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools.pth
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_compile.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_constants.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_parse.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/stat.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/types.py
A zopeorg.buildout/branches/beta.zope.org/lib/python2.6/warnings.py
A zopeorg.buildout/branches/beta.zope.org/src/
A zopeorg.buildout/branches/beta.zope.org/src/README.txt
A zopeorg.buildout/branches/beta.zope.org/var/
A zopeorg.buildout/branches/beta.zope.org/var/README.txt
-=-
Added: zopeorg.buildout/branches/beta.zope.org/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,173 @@
+================================
+Plone 4 buildout for developers
+================================
+
+.. contents ::
+
+Introduction
+------------
+
+`Buildout <http://www.buildout.org>`_ is a tool which automatically downloads, installs and configures Python software.
+Plone developers prefer uses buildout based installation method - it makes it easy to work with source code and developing your own Plone add-ons.
+
+For production site installations please use `standard Plone installer <http://plone.org/download>`_.
+
+Prerequisitements
+-----------------
+
+What you need in order to use developer buildout with Plone 4
+
+* Experience using command line tools
+
+* Experience using a text editor to work with configuration files (``buildout.cfg``)
+
+* GCC compiler suite to build native Python extensions (Zope contains C code for optimized parts)
+
+* Python 2.6 (other versions are *not* ok for Plone 4)
+
+* Python Imaging Library installed for your Python interpreter (more below)
+
+* Python `Distribute <http://pypi.python.org/pypi/distribute>`_ installation tool, provided by your operating system
+ or installed by hand
+
+Read below from operating system specific instructions how to install these dependencies.
+
+Features
+--------
+
+This buildout provides
+
+* Zope start up scripts (one instance)
+
+* ``paster`` command for creating Plone add-ons (different from system-wide installation)
+
+* `test <http://plone.org/documentation/manual/plone-community-developer-documentation/testing-and-debugging/unit-testing>`_ command for running automatic test suites
+
+* `i18ndude <http://pypi.python.org/pypi/i18ndude>`_ for managing text string translations in Python source code
+
+* `omelette <http://pypi.python.org/pypi/collective.recipe.omelette>`_ buildout recipe which makes Python egg source code more browseable by using symlinks
+
+* `mr.developer <http://pypi.python.org/pypi/mr.developer>`_ command for managing source code checkouts and updates with buildout repeatable manner
+
+* `collective.developermanual <http://plone.org/documentation/manual/plone-community-developer-documentation>`_ - community managed developer manual for Plone
+ in source code form, ready for contributions
+
+Creating Plone 4 buildout installation
+------------------------------------------
+
+Install ZopeSkel template package for your system-wide Python using Distribute::
+
+ easy_install ZopeSkel
+
+... or upgrade existing installation::
+
+ easy_install -U ZopeSkel
+
+You probably got here by running something like (replace *myplonefoldername* with the target folder where you want to Plone to be installed)::
+
+ zopeskel plone4_buildout myplonefoldername
+
+Now, you need to run (please see remarks regarding your operating system below)::
+
+ python bootstrap.py
+
+This will create ``bin`` folder and ``bin/buildout`` script. If you any time want to change Python interpreter
+associated with buildout, or you need to update ``buildout`` script itself to newer version please rerun ``bootsrap.py``.
+
+Now you can run buildout script which will download all Python packages
+(.egg files) and create ``parts/`` and ``var/`` folder structure ::
+
+ bin/buildout
+
+If this succesfully completes you can start buildout in foreground mode (Press *CTRL+C* to terminate)::
+
+ bin/instance fg
+
+Now you can login to your site
+
+ http://localhost:8080
+
+The default user is ``admin`` with password ``admin``.
+After initial start-up admin password is stored in Data.fs databse file and value in ``buildout.cfg`` is ignored.
+Please follow `these instructions to change admin password <http://manage.plone.org/documentation/kb/changing-the-admin-password>`_.
+
+Next steps
+----------
+
+Creating your first add-on
+==========================
+
+Plone 4 buildout comes with ``bin/paster`` command for creating Plone add-ons.
+
+.. note ::
+
+ When working with Plone add-ons, use paster command from buildout bin folder, not the system wide paster command.
+
+Create theme (applies for Plone 4 also)::
+
+ bin/zopeskel plone3_theme plonetheme.mythemeid
+
+Create Archetypes based content types package::
+
+ bin/zopeskel archetype mycompanyid.content
+
+Create other Plone customizations::
+
+ bin/zopeskel plone mycompanyid.mypackageid
+
+More info
+
+* `Instructions how to use Paster command to create your own add-ons <http://collective-docs.plone.org/tutorials/paste.html>`_
+
+Managing source code checkouts with buildout
+=============================================
+
+`mr.developer buildout extension <http://pypi.python.org/pypi/mr.developer>`_ command which can be used with buildout to manage your source code repositories
+*mr.developer* makes source code checkout from multiple repositores a repeatable task.
+
+Operating system specific instructions
+-------------------------------------------
+
+Ubuntu/Debian
+==============
+
+Tested for Ubuntu 10.10.
+
+Install prerequisitements::
+
+ sudo apt-get install python2.6 python-imaging wget build-essential python2.6-dev python-setuptools
+ easy_install ZopeSkel
+
+OSX
+====
+
+Install `OSX development tools (XCode) <http://developer.apple.com/>`_ from Apple.
+
+Install `Macports <http://www.macports.org/>`_.
+
+Then the following installs dependencies::
+
+ sudo port install python26 py26-pil py26-distribute wget
+ easy_install ZopeSkel
+
+When you run ``bootstrap.py``use the following command to make sure you are using Python interpreter from Macports::
+
+ python2.6 bootstrap.py
+
+Windows
+========
+
+Microsoft Windows systems is problematic because
+it does not provide to Microsoft Visual C compiler (commercial) which is
+required to build native Python extensions.
+
+Please read
+
+* http://plone.org/documentation/kb/using-buildout-on-windows
+
+Other
+-----
+
+The orignal copy of these instructions is available at
+
+* https://svn.plone.org/svn/collective/ZopeSkel/trunk/zopeskel/templates/plone4_buildout/README.txt
Added: zopeorg.buildout/branches/beta.zope.org/bin/activate
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/activate (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/activate 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,72 @@
+# This file must be used with "source bin/activate" *from bash*
+# you cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
+ PATH="$_OLD_VIRTUAL_PATH"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then
+ PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # This should detect bash and zsh, which have a hash command that must
+ # be called to get it to forget past commands. Without forgetting
+ # past commands the $PATH changes we made may not be respected
+ if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
+ hash -r
+ fi
+
+ if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
+ PS1="$_OLD_VIRTUAL_PS1"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ if [ ! "$1" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelavent variables
+deactivate nondestructive
+
+VIRTUAL_ENV="/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org"
+export VIRTUAL_ENV
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/bin:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "$PYTHONHOME" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
+ unset PYTHONHOME
+fi
+
+if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
+ _OLD_VIRTUAL_PS1="$PS1"
+ if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
+ # special case for Aspen magic directories
+ # see http://www.zetadev.com/software/aspen/
+ PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
+ else
+ PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
+ fi
+ export PS1
+fi
+
+# This should detect bash and zsh, which have a hash command that must
+# be called to get it to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
+ hash -r
+fi
Added: zopeorg.buildout/branches/beta.zope.org/bin/activate_this.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/activate_this.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/activate_this.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+"""By using execfile(this_file, dict(__file__=this_file)) you will
+activate this virtualenv environment.
+
+This can be used when you must use an existing Python interpreter, not
+the virtualenv bin/python
+"""
+
+try:
+ __file__
+except NameError:
+ raise AssertionError(
+ "You must run this like execfile('path/to/active_this.py', dict(__file__='path/to/activate_this.py'))")
+import sys
+import os
+
+base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if sys.platform == 'win32':
+ site_packages = os.path.join(base, 'Lib', 'site-packages')
+else:
+ site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
+prev_sys_path = list(sys.path)
+import site
+site.addsitedir(site_packages)
+sys.real_prefix = sys.prefix
+sys.prefix = base
+# Move the added items to the front of the path:
+new_sys_path = []
+for item in list(sys.path):
+ if item not in prev_sys_path:
+ new_sys_path.append(item)
+ sys.path.remove(item)
+sys.path[:0] = new_sys_path
Added: zopeorg.buildout/branches/beta.zope.org/bin/cheetah
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/cheetah (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/cheetah 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-SCRIPT: 'Cheetah==2.2.1','cheetah'
+__requires__ = 'Cheetah==2.2.1'
+import pkg_resources
+pkg_resources.run_script('Cheetah==2.2.1', 'cheetah')
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/cheetah
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/cheetah-compile
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/cheetah-compile (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/cheetah-compile 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-SCRIPT: 'Cheetah==2.2.1','cheetah-compile'
+__requires__ = 'Cheetah==2.2.1'
+import pkg_resources
+pkg_resources.run_script('Cheetah==2.2.1', 'cheetah-compile')
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/cheetah-compile
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/easy_install
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/easy_install (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/easy_install 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==0.6c11','console_scripts','easy_install'
+__requires__ = 'setuptools==0.6c11'
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+ load_entry_point('setuptools==0.6c11', 'console_scripts', 'easy_install')()
+)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/easy_install
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/easy_install-2.6
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/easy_install-2.6 (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/easy_install-2.6 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==0.6c11','console_scripts','easy_install-2.6'
+__requires__ = 'setuptools==0.6c11'
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+ load_entry_point('setuptools==0.6c11', 'console_scripts', 'easy_install-2.6')()
+)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/easy_install-2.6
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/paster
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/paster (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/paster 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'PasteScript==1.7.3','console_scripts','paster'
+__requires__ = 'PasteScript==1.7.3'
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+ load_entry_point('PasteScript==1.7.3', 'console_scripts', 'paster')()
+)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/paster
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/pip
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/pip (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/pip 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'pip==0.7.2','console_scripts','pip'
+__requires__ = 'pip==0.7.2'
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+ load_entry_point('pip==0.7.2', 'console_scripts', 'pip')()
+)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/pip
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bin/python
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/python
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/bin/zopeskel
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bin/zopeskel (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bin/zopeskel 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'ZopeSkel==2.19','console_scripts','zopeskel'
+__requires__ = 'ZopeSkel==2.19'
+import sys
+from pkg_resources import load_entry_point
+
+sys.exit(
+ load_entry_point('ZopeSkel==2.19', 'console_scripts', 'zopeskel')()
+)
Property changes on: zopeorg.buildout/branches/beta.zope.org/bin/zopeskel
___________________________________________________________________
Added: svn:executable
+ *
Added: zopeorg.buildout/branches/beta.zope.org/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+import urllib2
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="distribute", default=False,
+ help="Use Disribute rather than Setuptools.")
+
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.version is not None:
+ VERSION = '==%s' % options.version
+else:
+ VERSION = ''
+
+# We decided to always use distribute, make sure this is the default for us
+# USE_DISTRIBUTE = options.distribute
+USE_DISTRIBUTE = True
+args = args + ['bootstrap']
+
+to_reload = False
+try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ to_reload = True
+ raise ImportError
+except ImportError:
+ ez = {}
+ if USE_DISTRIBUTE:
+ setup_url = 'http://python-distribute.org/distribute_setup.py'
+ exec urllib2.urlopen(setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+ else:
+ ez_setup_url = 'http://peak.telecommunity.com/dist/ez_setup.py'
+ exec urllib2.urlopen(ez_setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ if to_reload:
+ reload(pkg_resources)
+ else:
+ import pkg_resources
+
+
+def quote(c):
+ if sys.platform == 'win32':
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+
+if USE_DISTRIBUTE:
+ requirement = 'distribute'
+else:
+ requirement = 'setuptools'
+
+pythonpath = ws.find(pkg_resources.Requirement.parse(requirement)).location
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout' + VERSION],
+ env=dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote(sys.executable),
+ '-c', quote(cmd), '-mqNxd', quote(tmpeggs), 'zc.buildout' + VERSION,
+ dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/buildout.cfg
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/buildout.cfg (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/buildout.cfg 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,101 @@
+# buildout.cfg file for Plone 4 development work
+# - for production installations please use http://plone.org/download
+# Each part has more information about its recipe on PyPi
+# http://pypi.python.org/pypi
+# ... just reach by the recipe name
+[buildout]
+parts =
+ instance
+ zopepy
+ i18ndude
+ zopeskel
+ test
+# omelette
+
+extends =
+ http://dist.plone.org/release/4.0.5/versions.cfg
+
+# Add additional egg download sources here. dist.plone.org contains archives
+# of Plone packages.
+find-links =
+ http://dist.plone.org/release/4.0.5
+ http://dist.plone.org/thirdparty
+
+extensions =
+ mr.developer
+ buildout.dumppickedversions
+ buildout.threatlevel
+
+sources = sources
+
+versions = versions
+
+# Reference any folders where you have Python egg source code under development here
+# e.g.: develop = src/my.package
+# If you are using the mr.developer extension and have the source code in a
+# repository mr.developer will handle this automatically for you
+develop =
+
+
+# Create bin/instance command to manage Zope start up and shutdown
+[instance]
+recipe = plone.recipe.zope2instance
+user = admin:admin
+http-address = 8080
+debug-mode = off
+verbose-security = on
+blob-storage = var/blobstorage
+
+eggs =
+ Plone
+
+# Some pre-Plone 3.3 packages may need you to register the package name here in
+# order their configure.zcml to be run (http://plone.org/products/plone/roadmap/247)
+# - this is never required for packages in the Products namespace (Products.*)
+zcml =
+
+
+# zopepy commands allows you to execute Python scripts using a PYTHONPATH
+# including all the configured eggs
+[zopepy]
+recipe = zc.recipe.egg
+eggs = ${instance:eggs}
+interpreter = zopepy
+scripts = zopepy
+
+# create bin/i18ndude command
+[i18ndude]
+unzip = true
+recipe = zc.recipe.egg
+eggs = i18ndude
+
+# create bin/test command
+[test]
+recipe = zc.recipe.testrunner
+defaults = ['--auto-color', '--auto-progress']
+eggs =
+ ${instance:eggs}
+
+# create ZopeSkel command
+[zopeskel]
+unzip = true
+recipe = zc.recipe.egg
+eggs =
+ ZopeSkel
+ ${instance:eggs}
+
+# symlinks all Python source code to parts/omelette folder when buildout is run
+# windows users will need to install additional software for this part to build
+# correctly. See http://pypi.python.org/pypi/collective.recipe.omelette for
+# relevant details.
+# [omelette]
+# recipe = collective.recipe.omelette
+# eggs = ${instance:eggs}
+
+# Put your mr.developer managed source code repositories here, see
+# http://pypi.python.org/pypi/mr.developer for details on format for this part
+[sources]
+collective.developermanual = svn http://svn.plone.org/svn/collective/collective.developermanual
+
+# Version pindowns for new style products go here - this section extends one provided in http://dist.plone.org/release/
+[versions]
Added: zopeorg.buildout/branches/beta.zope.org/include/python2.6
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/include/python2.6 (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/include/python2.6 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/include/python2.6
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/include/python2.6
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/UserDict.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/UserDict.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/UserDict.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/UserDict.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/UserDict.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/_abcoll.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/_abcoll.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/_abcoll.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/_abcoll.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/_abcoll.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/abc.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/abc.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/abc.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/abc.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/abc.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/codecs.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/codecs.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/codecs.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/codecs.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/codecs.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/config
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/config (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/config 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/config
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/config
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/copy_reg.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/copy_reg.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/copy_reg.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/copy_reg.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/copy_reg.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,87 @@
+import os
+import sys
+import warnings
+import ConfigParser # ConfigParser is not a virtualenv module, so we can use it to find the stdlib
+
+dirname = os.path.dirname
+
+distutils_path = os.path.join(os.path.dirname(ConfigParser.__file__), 'distutils')
+if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)):
+ warnings.warn(
+ "The virtualenv distutils package at %s appears to be in the same location as the system distutils?")
+else:
+ __path__.insert(0, distutils_path)
+ exec open(os.path.join(distutils_path, '__init__.py')).read()
+
+import dist
+import sysconfig
+
+
+## patch build_ext (distutils doesn't know how to get the libs directory
+## path on windows - it hardcodes the paths around the patched sys.prefix)
+
+if sys.platform == 'win32':
+ from distutils.command.build_ext import build_ext as old_build_ext
+ class build_ext(old_build_ext):
+ def finalize_options (self):
+ if self.library_dirs is None:
+ self.library_dirs = []
+
+ self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
+ old_build_ext.finalize_options(self)
+
+ from distutils.command import build_ext as build_ext_module
+ build_ext_module.build_ext = build_ext
+
+## distutils.dist patches:
+
+old_find_config_files = dist.Distribution.find_config_files
+def find_config_files(self):
+ found = old_find_config_files(self)
+ system_distutils = os.path.join(distutils_path, 'distutils.cfg')
+ #if os.path.exists(system_distutils):
+ # found.insert(0, system_distutils)
+ # What to call the per-user config file
+ if os.name == 'posix':
+ user_filename = ".pydistutils.cfg"
+ else:
+ user_filename = "pydistutils.cfg"
+ user_filename = os.path.join(sys.prefix, user_filename)
+ if os.path.isfile(user_filename):
+ for item in list(found):
+ if item.endswith('pydistutils.cfg'):
+ found.remove(item)
+ found.append(user_filename)
+ return found
+dist.Distribution.find_config_files = find_config_files
+
+## distutils.sysconfig patches:
+
+old_get_python_inc = sysconfig.get_python_inc
+def sysconfig_get_python_inc(plat_specific=0, prefix=None):
+ if prefix is None:
+ prefix = sys.real_prefix
+ return old_get_python_inc(plat_specific, prefix)
+sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__
+sysconfig.get_python_inc = sysconfig_get_python_inc
+
+old_get_python_lib = sysconfig.get_python_lib
+def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
+ if standard_lib and prefix is None:
+ prefix = sys.real_prefix
+ return old_get_python_lib(plat_specific, standard_lib, prefix)
+sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__
+sysconfig.get_python_lib = sysconfig_get_python_lib
+
+old_get_config_vars = sysconfig.get_config_vars
+def sysconfig_get_config_vars(*args):
+ real_vars = old_get_config_vars(*args)
+ if sys.platform == 'win32':
+ lib_dir = os.path.join(sys.real_prefix, "libs")
+ if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars:
+ real_vars['LIBDIR'] = lib_dir # asked for all
+ elif isinstance(real_vars, list) and 'LIBDIR' in args:
+ real_vars = real_vars + [lib_dir] # asked for list
+ return real_vars
+sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__
+sysconfig.get_config_vars = sysconfig_get_config_vars
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/distutils.cfg
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/distutils.cfg (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/distutils/distutils.cfg 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# This is a config file local to this virtualenv installation
+# You may include options that will be used by all distutils commands,
+# and by easy_install. For instance:
+#
+# [easy_install]
+# find_links = http://mylocalsite
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/encodings
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/encodings (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/encodings 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/encodings
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/encodings
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/fnmatch.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/fnmatch.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/fnmatch.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/fnmatch.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/fnmatch.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/genericpath.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/genericpath.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/genericpath.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/genericpath.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/genericpath.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/lib-dynload
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/lib-dynload (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/lib-dynload 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/lib-dynload
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/lib-dynload
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/linecache.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/linecache.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/linecache.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/linecache.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/linecache.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/locale.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/locale.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/locale.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/locale.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/locale.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/ntpath.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/ntpath.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/ntpath.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/ntpath.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/ntpath.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/orig-prefix.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/orig-prefix.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/orig-prefix.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+/opt/python-2.6.4
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/os.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/os.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/os.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/os.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/os.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/posixpath.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/posixpath.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/posixpath.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/posixpath.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/posixpath.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/re.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/re.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/re.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/re.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/re.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheRegion.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheRegion.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheRegion.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,136 @@
+# $Id: CacheRegion.py,v 1.3 2006/01/28 04:19:30 tavis_rudd Exp $
+'''
+Cache holder classes for Cheetah:
+
+Cache regions are defined using the #cache Cheetah directive. Each
+cache region can be viewed as a dictionary (keyed by cacheRegionID)
+handling at least one cache item (the default one). It's possible to add
+cacheItems in a region by using the `varyBy` #cache directive parameter as
+in the following example::
+ #def getArticle
+ this is the article content.
+ #end def
+
+ #cache varyBy=$getArticleID()
+ $getArticle($getArticleID())
+ #end cache
+
+The code above will generate a CacheRegion and add new cacheItem for each value
+of $getArticleID().
+'''
+
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+
+import time
+import Cheetah.CacheStore
+
+class CacheItem(object):
+ '''
+ A CacheItem is a container storing:
+
+ - cacheID (string)
+ - refreshTime (timestamp or None) : last time the cache was refreshed
+ - data (string) : the content of the cache
+ '''
+
+ def __init__(self, cacheItemID, cacheStore):
+ self._cacheItemID = cacheItemID
+ self._cacheStore = cacheStore
+ self._refreshTime = None
+ self._expiryTime = 0
+
+ def hasExpired(self):
+ return (self._expiryTime and time.time() > self._expiryTime)
+
+ def setExpiryTime(self, time):
+ self._expiryTime = time
+
+ def getExpiryTime(self):
+ return self._expiryTime
+
+ def setData(self, data):
+ self._refreshTime = time.time()
+ self._cacheStore.set(self._cacheItemID, data, self._expiryTime)
+
+ def getRefreshTime(self):
+ return self._refreshTime
+
+ def getData(self):
+ assert self._refreshTime
+ return self._cacheStore.get(self._cacheItemID)
+
+ def renderOutput(self):
+ """Can be overridden to implement edge-caching"""
+ return self.getData() or ""
+
+ def clear(self):
+ self._cacheStore.delete(self._cacheItemID)
+ self._refreshTime = None
+
+class _CacheDataStoreWrapper(object):
+ def __init__(self, dataStore, keyPrefix):
+ self._dataStore = dataStore
+ self._keyPrefix = keyPrefix
+
+ def get(self, key):
+ return self._dataStore.get(self._keyPrefix+key)
+
+ def delete(self, key):
+ self._dataStore.delete(self._keyPrefix+key)
+
+ def set(self, key, val, time=0):
+ self._dataStore.set(self._keyPrefix+key, val, time=time)
+
+class CacheRegion(object):
+ '''
+ A `CacheRegion` stores some `CacheItem` instances.
+
+ This implementation stores the data in the memory of the current process.
+ If you need a more advanced data store, create a cacheStore class that works
+ with Cheetah's CacheStore protocol and provide it as the cacheStore argument
+ to __init__. For example you could use
+ Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python
+ memcached API (http://www.danga.com/memcached).
+ '''
+ _cacheItemClass = CacheItem
+
+ def __init__(self, regionID, templateCacheIdPrefix='', cacheStore=None):
+ self._isNew = True
+ self._regionID = regionID
+ self._templateCacheIdPrefix = templateCacheIdPrefix
+ if not cacheStore:
+ cacheStore = Cheetah.CacheStore.MemoryCacheStore()
+ self._cacheStore = cacheStore
+ self._wrappedCacheDataStore = _CacheDataStoreWrapper(
+ cacheStore, keyPrefix=templateCacheIdPrefix+':'+regionID+':')
+ self._cacheItems = {}
+
+ def isNew(self):
+ return self._isNew
+
+ def clear(self):
+ " drop all the caches stored in this cache region "
+ for cacheItemId in self._cacheItems.keys():
+ cacheItem = self._cacheItems[cacheItemId]
+ cacheItem.clear()
+ del self._cacheItems[cacheItemId]
+
+ def getCacheItem(self, cacheItemID):
+ """ Lazy access to a cacheItem
+
+ Try to find a cache in the stored caches. If it doesn't
+ exist, it's created.
+
+ Returns a `CacheItem` instance.
+ """
+ cacheItemID = md5(str(cacheItemID)).hexdigest()
+
+ if not self._cacheItems.has_key(cacheItemID):
+ cacheItem = self._cacheItemClass(
+ cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore)
+ self._cacheItems[cacheItemID] = cacheItem
+ self._isNew = False
+ return self._cacheItems[cacheItemID]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheStore.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheStore.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CacheStore.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,108 @@
+'''
+Provides several CacheStore backends for Cheetah's caching framework. The
+methods provided by these classes have the same semantics as those in the
+python-memcached API, except for their return values:
+
+set(key, val, time=0)
+ set the value unconditionally
+add(key, val, time=0)
+ set only if the server doesn't already have this key
+replace(key, val, time=0)
+ set only if the server already have this key
+get(key, val)
+ returns val or raises a KeyError
+delete(key)
+ deletes or raises a KeyError
+'''
+import time
+
+from Cheetah.Utils.memcache import Client as MemcachedClient
+
+class Error(Exception):
+ pass
+
+class AbstractCacheStore(object):
+
+ def set(self, key, val, time=None):
+ raise NotImplementedError
+
+ def add(self, key, val, time=None):
+ raise NotImplementedError
+
+ def replace(self, key, val, time=None):
+ raise NotImplementedError
+
+ def delete(self, key):
+ raise NotImplementedError
+
+ def get(self, key):
+ raise NotImplementedError
+
+class MemoryCacheStore(AbstractCacheStore):
+ def __init__(self):
+ self._data = {}
+
+ def set(self, key, val, time=0):
+ self._data[key] = (val, time)
+
+ def add(self, key, val, time=0):
+ if self._data.has_key(key):
+ raise Error('a value for key %r is already in the cache'%key)
+ self._data[key] = (val, time)
+
+ def replace(self, key, val, time=0):
+ if self._data.has_key(key):
+ raise Error('a value for key %r is already in the cache'%key)
+ self._data[key] = (val, time)
+
+ def delete(self, key):
+ del self._data[key]
+
+ def get(self, key):
+ (val, exptime) = self._data[key]
+ if exptime and time.time() > exptime:
+ del self._data[key]
+ raise KeyError(key)
+ else:
+ return val
+
+ def clear(self):
+ self._data.clear()
+
+class MemcachedCacheStore(AbstractCacheStore):
+ servers = ('127.0.0.1:11211')
+ def __init__(self, servers=None, debug=False):
+ if servers is None:
+ servers = self.servers
+
+ self._client = MemcachedClient(servers, debug)
+
+ def set(self, key, val, time=0):
+ self._client.set(key, val, time)
+
+ def add(self, key, val, time=0):
+ res = self._client.add(key, val, time)
+ if not res:
+ raise Error('a value for key %r is already in the cache'%key)
+ self._data[key] = (val, time)
+
+ def replace(self, key, val, time=0):
+ res = self._client.replace(key, val, time)
+ if not res:
+ raise Error('a value for key %r is already in the cache'%key)
+ self._data[key] = (val, time)
+
+ def delete(self, key):
+ res = self._client.delete(key, time=0)
+ if not res:
+ raise KeyError(key)
+
+ def get(self, key):
+ val = self._client.get(key)
+ if val is None:
+ raise KeyError(key)
+ else:
+ return val
+
+ def clear(self):
+ self._client.flush_all()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CheetahWrapper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CheetahWrapper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/CheetahWrapper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,610 @@
+#!/usr/bin/env python
+# $Id: CheetahWrapper.py,v 1.26 2007/10/02 01:22:04 tavis_rudd Exp $
+"""Cheetah command-line interface.
+
+2002-09-03 MSO: Total rewrite.
+2002-09-04 MSO: Bugfix, compile command was using wrong output ext.
+2002-11-08 MSO: Another rewrite.
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com> and Mike Orr <sluggoster at gmail.com>>
+Version: $Revision: 1.26 $
+Start Date: 2001/03/30
+Last Revision Date: $Date: 2007/10/02 01:22:04 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com> and Mike Orr <sluggoster at gmail.com>"
+__revision__ = "$Revision: 1.26 $"[11:-2]
+
+import getopt, glob, os, pprint, re, shutil, sys
+import cPickle as pickle
+from optparse import OptionParser
+
+from Cheetah.Version import Version
+from Cheetah.Template import Template, DEFAULT_COMPILER_SETTINGS
+from Cheetah.Utils.Misc import mkdirsWithPyInitFiles
+
+optionDashesRE = re.compile( R"^-{1,2}" )
+moduleNameRE = re.compile( R"^[a-zA-Z_][a-zA-Z_0-9]*$" )
+
+def fprintfMessage(stream, format, *args):
+ if format[-1:] == '^':
+ format = format[:-1]
+ else:
+ format += '\n'
+ if args:
+ message = format % args
+ else:
+ message = format
+ stream.write(message)
+
+class Error(Exception):
+ pass
+
+
+class Bundle:
+ """Wrap the source, destination and backup paths in one neat little class.
+ Used by CheetahWrapper.getBundles().
+ """
+ def __init__(self, **kw):
+ self.__dict__.update(kw)
+
+ def __repr__(self):
+ return "<Bundle %r>" % self.__dict__
+
+
+##################################################
+## USAGE FUNCTION & MESSAGES
+
+def usage(usageMessage, errorMessage="", out=sys.stderr):
+ """Write help text, an optional error message, and abort the program.
+ """
+ out.write(WRAPPER_TOP)
+ out.write(usageMessage)
+ exitStatus = 0
+ if errorMessage:
+ out.write('\n')
+ out.write("*** USAGE ERROR ***: %s\n" % errorMessage)
+ exitStatus = 1
+ sys.exit(exitStatus)
+
+
+WRAPPER_TOP = """\
+ __ ____________ __
+ \ \/ \/ /
+ \/ * * \/ CHEETAH %(Version)s Command-Line Tool
+ \ | /
+ \ ==----== / by Tavis Rudd <tavis at damnsimple.com>
+ \__________/ and Mike Orr <sluggoster at gmail.com>
+
+""" % globals()
+
+
+HELP_PAGE1 = """\
+USAGE:
+------
+ cheetah compile [options] [FILES ...] : Compile template definitions
+ cheetah fill [options] [FILES ...] : Fill template definitions
+ cheetah help : Print this help message
+ cheetah options : Print options help message
+ cheetah test [options] : Run Cheetah's regression tests
+ : (same as for unittest)
+ cheetah version : Print Cheetah version number
+
+You may abbreviate the command to the first letter; e.g., 'h' == 'help'.
+If FILES is a single "-", read standard input and write standard output.
+Run "cheetah options" for the list of valid options.
+"""
+
+##################################################
+## CheetahWrapper CLASS
+
+class CheetahWrapper(object):
+ MAKE_BACKUPS = True
+ BACKUP_SUFFIX = ".bak"
+ _templateClass = None
+ _compilerSettings = None
+
+ def __init__(self):
+ self.progName = None
+ self.command = None
+ self.opts = None
+ self.pathArgs = None
+ self.sourceFiles = []
+ self.searchList = []
+ self.parser = None
+
+ ##################################################
+ ## MAIN ROUTINE
+
+ def main(self, argv=None):
+ """The main program controller."""
+
+ if argv is None:
+ argv = sys.argv
+
+ # Step 1: Determine the command and arguments.
+ try:
+ self.progName = progName = os.path.basename(argv[0])
+ self.command = command = optionDashesRE.sub("", argv[1])
+ if command == 'test':
+ self.testOpts = argv[2:]
+ else:
+ self.parseOpts(argv[2:])
+ except IndexError:
+ usage(HELP_PAGE1, "not enough command-line arguments")
+
+ # Step 2: Call the command
+ meths = (self.compile, self.fill, self.help, self.options,
+ self.test, self.version)
+ for meth in meths:
+ methName = meth.__name__
+ # Or meth.im_func.func_name
+ # Or meth.func_name (Python >= 2.1 only, sometimes works on 2.0)
+ methInitial = methName[0]
+ if command in (methName, methInitial):
+ sys.argv[0] += (" " + methName)
+ # @@MO: I don't necessarily agree sys.argv[0] should be
+ # modified.
+ meth()
+ return
+ # If none of the commands matched.
+ usage(HELP_PAGE1, "unknown command '%s'" % command)
+
+ def parseOpts(self, args):
+ C, D, W = self.chatter, self.debug, self.warn
+ self.isCompile = isCompile = self.command[0] == 'c'
+ defaultOext = isCompile and ".py" or ".html"
+ self.parser = OptionParser()
+ pao = self.parser.add_option
+ pao("--idir", action="store", dest="idir", default='', help='Input directory (defaults to current directory)')
+ pao("--odir", action="store", dest="odir", default="", help='Output directory (defaults to current directory)')
+ pao("--iext", action="store", dest="iext", default=".tmpl", help='File input extension (defaults: compile: .tmpl, fill: .tmpl)')
+ pao("--oext", action="store", dest="oext", default=defaultOext, help='File output extension (defaults: compile: .py, fill: .html)')
+ pao("-R", action="store_true", dest="recurse", default=False, help='Recurse through subdirectories looking for input files')
+ pao("--stdout", "-p", action="store_true", dest="stdout", default=False, help='Verbosely print informational messages to stdout')
+ pao("--debug", action="store_true", dest="debug", default=False, help='Print diagnostic/debug information to stderr')
+ pao("--env", action="store_true", dest="env", default=False, help='Pass the environment into the search list')
+ pao("--pickle", action="store", dest="pickle", default="", help='Unpickle FILE and pass it through in the search list')
+ pao("--flat", action="store_true", dest="flat", default=False, help='Do not build destination subdirectories')
+ pao("--nobackup", action="store_true", dest="nobackup", default=False, help='Do not make backup files when generating new ones')
+ pao("--settings", action="store", dest="compilerSettingsString", default=None, help='String of compiler settings to pass through, e.g. --settings="useNameMapper=False,useFilters=False"')
+ pao('--print-settings', action='store_true', dest='print_settings', help='Print out the list of available compiler settings')
+ pao("--templateAPIClass", action="store", dest="templateClassName", default=None, help='Name of a subclass of Cheetah.Template.Template to use for compilation, e.g. MyTemplateClass')
+ pao("--parallel", action="store", type="int", dest="parallel", default=1, help='Compile/fill templates in parallel, e.g. --parallel=4')
+ pao('--shbang', dest='shbang', default='#!/usr/bin/env python', help='Specify the shbang to place at the top of compiled templates, e.g. --shbang="#!/usr/bin/python2.6"')
+
+ self.opts, self.pathArgs = opts, files = self.parser.parse_args(args)
+ D("""\
+cheetah compile %s
+Options are
+%s
+Files are %s""", args, pprint.pformat(vars(opts)), files)
+
+
+ if opts.print_settings:
+ print
+ print '>> Available Cheetah compiler settings:'
+ from Cheetah.Compiler import _DEFAULT_COMPILER_SETTINGS
+ listing = _DEFAULT_COMPILER_SETTINGS
+ listing.sort(key=lambda l: l[0][0].lower())
+
+ for l in listing:
+ print '\t%s (default: "%s")\t%s' % l
+ sys.exit(0)
+
+ #cleanup trailing path separators
+ seps = [sep for sep in [os.sep, os.altsep] if sep]
+ for attr in ['idir', 'odir']:
+ for sep in seps:
+ path = getattr(opts, attr, None)
+ if path and path.endswith(sep):
+ path = path[:-len(sep)]
+ setattr(opts, attr, path)
+ break
+
+ self._fixExts()
+ if opts.env:
+ self.searchList.insert(0, os.environ)
+ if opts.pickle:
+ f = open(opts.pickle, 'rb')
+ unpickled = pickle.load(f)
+ f.close()
+ self.searchList.insert(0, unpickled)
+ opts.verbose = not opts.stdout
+
+ ##################################################
+ ## COMMAND METHODS
+
+ def compile(self):
+ self._compileOrFill()
+
+ def fill(self):
+ from Cheetah.ImportHooks import install
+ install()
+ self._compileOrFill()
+
+ def help(self):
+ usage(HELP_PAGE1, "", sys.stdout)
+
+ def options(self):
+ return self.parser.print_help()
+
+ def test(self):
+ # @@MO: Ugly kludge.
+ TEST_WRITE_FILENAME = 'cheetah_test_file_creation_ability.tmp'
+ try:
+ f = open(TEST_WRITE_FILENAME, 'w')
+ except:
+ sys.exit("""\
+Cannot run the tests because you don't have write permission in the current
+directory. The tests need to create temporary files. Change to a directory
+you do have write permission to and re-run the tests.""")
+ else:
+ f.close()
+ os.remove(TEST_WRITE_FILENAME)
+ # @@MO: End ugly kludge.
+ from Cheetah.Tests import Test
+ import Cheetah.Tests.unittest_local_copy as unittest
+ del sys.argv[1:] # Prevent unittest from misinterpreting options.
+ sys.argv.extend(self.testOpts)
+ #unittest.main(testSuite=Test.testSuite)
+ #unittest.main(testSuite=Test.testSuite)
+ unittest.main(module=Test)
+
+ def version(self):
+ print Version
+
+ # If you add a command, also add it to the 'meths' variable in main().
+
+ ##################################################
+ ## LOGGING METHODS
+
+ def chatter(self, format, *args):
+ """Print a verbose message to stdout. But don't if .opts.stdout is
+ true or .opts.verbose is false.
+ """
+ if self.opts.stdout or not self.opts.verbose:
+ return
+ fprintfMessage(sys.stdout, format, *args)
+
+
+ def debug(self, format, *args):
+ """Print a debugging message to stderr, but don't if .debug is
+ false.
+ """
+ if self.opts.debug:
+ fprintfMessage(sys.stderr, format, *args)
+
+ def warn(self, format, *args):
+ """Always print a warning message to stderr.
+ """
+ fprintfMessage(sys.stderr, format, *args)
+
+ def error(self, format, *args):
+ """Always print a warning message to stderr and exit with an error code.
+ """
+ fprintfMessage(sys.stderr, format, *args)
+ sys.exit(1)
+
+ ##################################################
+ ## HELPER METHODS
+
+
+ def _fixExts(self):
+ assert self.opts.oext, "oext is empty!"
+ iext, oext = self.opts.iext, self.opts.oext
+ if iext and not iext.startswith("."):
+ self.opts.iext = "." + iext
+ if oext and not oext.startswith("."):
+ self.opts.oext = "." + oext
+
+
+
+ def _compileOrFill(self):
+ C, D, W = self.chatter, self.debug, self.warn
+ opts, files = self.opts, self.pathArgs
+ if files == ["-"]:
+ self._compileOrFillStdin()
+ return
+ elif not files and opts.recurse:
+ which = opts.idir and "idir" or "current"
+ C("Drilling down recursively from %s directory.", which)
+ sourceFiles = []
+ dir = os.path.join(self.opts.idir, os.curdir)
+ os.path.walk(dir, self._expandSourceFilesWalk, sourceFiles)
+ elif not files:
+ usage(HELP_PAGE1, "Neither files nor -R specified!")
+ else:
+ sourceFiles = self._expandSourceFiles(files, opts.recurse, True)
+ sourceFiles = [os.path.normpath(x) for x in sourceFiles]
+ D("All source files found: %s", sourceFiles)
+ bundles = self._getBundles(sourceFiles)
+ D("All bundles: %s", pprint.pformat(bundles))
+ if self.opts.flat:
+ self._checkForCollisions(bundles)
+
+ # In parallel mode a new process is forked for each template
+ # compilation, out of a pool of size self.opts.parallel. This is not
+ # really optimal in all cases (e.g. probably wasteful for small
+ # templates), but seems to work well in real life for me.
+ #
+ # It also won't work for Windows users, but I'm not going to lose any
+ # sleep over that.
+ if self.opts.parallel > 1:
+ bad_child_exit = 0
+ pid_pool = set()
+
+ def child_wait():
+ pid, status = os.wait()
+ pid_pool.remove(pid)
+ return os.WEXITSTATUS(status)
+
+ while bundles:
+ b = bundles.pop()
+ pid = os.fork()
+ if pid:
+ pid_pool.add(pid)
+ else:
+ self._compileOrFillBundle(b)
+ sys.exit(0)
+
+ if len(pid_pool) == self.opts.parallel:
+ bad_child_exit = child_wait()
+ if bad_child_exit:
+ break
+
+ while pid_pool:
+ child_exit = child_wait()
+ if not bad_child_exit:
+ bad_child_exit = child_exit
+
+ if bad_child_exit:
+ sys.exit("Child process failed, exited with code %d" % bad_child_exit)
+
+ else:
+ for b in bundles:
+ self._compileOrFillBundle(b)
+
+ def _checkForCollisions(self, bundles):
+ """Check for multiple source paths writing to the same destination
+ path.
+ """
+ C, D, W = self.chatter, self.debug, self.warn
+ isError = False
+ dstSources = {}
+ for b in bundles:
+ if dstSources.has_key(b.dst):
+ dstSources[b.dst].append(b.src)
+ else:
+ dstSources[b.dst] = [b.src]
+ keys = dstSources.keys()
+ keys.sort()
+ for dst in keys:
+ sources = dstSources[dst]
+ if len(sources) > 1:
+ isError = True
+ sources.sort()
+ fmt = "Collision: multiple source files %s map to one destination file %s"
+ W(fmt, sources, dst)
+ if isError:
+ what = self.isCompile and "Compilation" or "Filling"
+ sys.exit("%s aborted due to collisions" % what)
+
+
+ def _expandSourceFilesWalk(self, arg, dir, files):
+ """Recursion extension for .expandSourceFiles().
+ This method is a callback for os.path.walk().
+ 'arg' is a list to which successful paths will be appended.
+ """
+ iext = self.opts.iext
+ for f in files:
+ path = os.path.join(dir, f)
+ if path.endswith(iext) and os.path.isfile(path):
+ arg.append(path)
+ elif os.path.islink(path) and os.path.isdir(path):
+ os.path.walk(path, self._expandSourceFilesWalk, arg)
+ # If is directory, do nothing; 'walk' will eventually get it.
+
+
+ def _expandSourceFiles(self, files, recurse, addIextIfMissing):
+ """Calculate source paths from 'files' by applying the
+ command-line options.
+ """
+ C, D, W = self.chatter, self.debug, self.warn
+ idir = self.opts.idir
+ iext = self.opts.iext
+ files = []
+ for f in self.pathArgs:
+ oldFilesLen = len(files)
+ D("Expanding %s", f)
+ path = os.path.join(idir, f)
+ pathWithExt = path + iext # May or may not be valid.
+ if os.path.isdir(path):
+ if recurse:
+ os.path.walk(path, self._expandSourceFilesWalk, files)
+ else:
+ raise Error("source file '%s' is a directory" % path)
+ elif os.path.isfile(path):
+ files.append(path)
+ elif (addIextIfMissing and not path.endswith(iext) and
+ os.path.isfile(pathWithExt)):
+ files.append(pathWithExt)
+ # Do not recurse directories discovered by iext appending.
+ elif os.path.exists(path):
+ W("Skipping source file '%s', not a plain file.", path)
+ else:
+ W("Skipping source file '%s', not found.", path)
+ if len(files) > oldFilesLen:
+ D(" ... found %s", files[oldFilesLen:])
+ return files
+
+
+ def _getBundles(self, sourceFiles):
+ flat = self.opts.flat
+ idir = self.opts.idir
+ iext = self.opts.iext
+ nobackup = self.opts.nobackup
+ odir = self.opts.odir
+ oext = self.opts.oext
+ idirSlash = idir + os.sep
+ bundles = []
+ for src in sourceFiles:
+ # 'base' is the subdirectory plus basename.
+ base = src
+ if idir and src.startswith(idirSlash):
+ base = src[len(idirSlash):]
+ if iext and base.endswith(iext):
+ base = base[:-len(iext)]
+ basename = os.path.basename(base)
+ if flat:
+ dst = os.path.join(odir, basename + oext)
+ else:
+ dbn = basename
+ if odir and base.startswith(os.sep):
+ odd = odir
+ while odd != '':
+ idx = base.find(odd)
+ if idx == 0:
+ dbn = base[len(odd):]
+ if dbn[0] == '/':
+ dbn = dbn[1:]
+ break
+ odd = os.path.dirname(odd)
+ if odd == '/':
+ break
+ dst = os.path.join(odir, dbn + oext)
+ else:
+ dst = os.path.join(odir, base + oext)
+ bak = dst + self.BACKUP_SUFFIX
+ b = Bundle(src=src, dst=dst, bak=bak, base=base, basename=basename)
+ bundles.append(b)
+ return bundles
+
+
+ def _getTemplateClass(self):
+ C, D, W = self.chatter, self.debug, self.warn
+ modname = None
+ if self._templateClass:
+ return self._templateClass
+
+ modname = self.opts.templateClassName
+
+ if not modname:
+ return Template
+ p = modname.rfind('.')
+ if ':' not in modname:
+ self.error('The value of option --templateAPIClass is invalid\n'
+ 'It must be in the form "module:class", '
+ 'e.g. "Cheetah.Template:Template"')
+
+ modname, classname = modname.split(':')
+
+ C('using --templateAPIClass=%s:%s'%(modname, classname))
+
+ if p >= 0:
+ mod = getattr(__import__(modname[:p], {}, {}, [modname[p+1:]]), modname[p+1:])
+ else:
+ mod = __import__(modname, {}, {}, [])
+
+ klass = getattr(mod, classname, None)
+ if klass:
+ self._templateClass = klass
+ return klass
+ else:
+ self.error('**Template class specified in option --templateAPIClass not found\n'
+ '**Falling back on Cheetah.Template:Template')
+
+
+ def _getCompilerSettings(self):
+ if self._compilerSettings:
+ return self._compilerSettings
+
+ def getkws(**kws):
+ return kws
+ if self.opts.compilerSettingsString:
+ try:
+ exec 'settings = getkws(%s)'%self.opts.compilerSettingsString
+ except:
+ self.error("There's an error in your --settings option."
+ "It must be valid Python syntax.\n"
+ +" --settings='%s'\n"%self.opts.compilerSettingsString
+ +" %s: %s"%sys.exc_info()[:2]
+ )
+
+ validKeys = DEFAULT_COMPILER_SETTINGS.keys()
+ if [k for k in settings.keys() if k not in validKeys]:
+ self.error(
+ 'The --setting "%s" is not a valid compiler setting name.'%k)
+
+ self._compilerSettings = settings
+ return settings
+ else:
+ return {}
+
+ def _compileOrFillStdin(self):
+ TemplateClass = self._getTemplateClass()
+ compilerSettings = self._getCompilerSettings()
+ if self.isCompile:
+ pysrc = TemplateClass.compile(file=sys.stdin,
+ compilerSettings=compilerSettings,
+ returnAClass=False)
+ output = pysrc
+ else:
+ output = str(TemplateClass(file=sys.stdin, compilerSettings=compilerSettings))
+ sys.stdout.write(output)
+
+ def _compileOrFillBundle(self, b):
+ C, D, W = self.chatter, self.debug, self.warn
+ TemplateClass = self._getTemplateClass()
+ compilerSettings = self._getCompilerSettings()
+ src = b.src
+ dst = b.dst
+ base = b.base
+ basename = b.basename
+ dstDir = os.path.dirname(dst)
+ what = self.isCompile and "Compiling" or "Filling"
+ C("%s %s -> %s^", what, src, dst) # No trailing newline.
+ if os.path.exists(dst) and not self.opts.nobackup:
+ bak = b.bak
+ C(" (backup %s)", bak) # On same line as previous message.
+ else:
+ bak = None
+ C("")
+ if self.isCompile:
+ if not moduleNameRE.match(basename):
+ tup = basename, src
+ raise Error("""\
+%s: base name %s contains invalid characters. It must
+be named according to the same rules as Python modules.""" % tup)
+ pysrc = TemplateClass.compile(file=src, returnAClass=False,
+ moduleName=basename,
+ className=basename,
+ commandlineopts=self.opts,
+ compilerSettings=compilerSettings)
+ output = pysrc
+ else:
+ #output = str(TemplateClass(file=src, searchList=self.searchList))
+ tclass = TemplateClass.compile(file=src, compilerSettings=compilerSettings)
+ output = str(tclass(searchList=self.searchList))
+
+ if bak:
+ shutil.copyfile(dst, bak)
+ if dstDir and not os.path.exists(dstDir):
+ if self.isCompile:
+ mkdirsWithPyInitFiles(dstDir)
+ else:
+ os.makedirs(dstDir)
+ if self.opts.stdout:
+ sys.stdout.write(output)
+ else:
+ f = open(dst, 'w')
+ f.write(output)
+ f.close()
+
+
+##################################################
+## if run from the command line
+if __name__ == '__main__': CheetahWrapper().main()
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Compiler.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Compiler.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Compiler.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2011 @@
+#!/usr/bin/env python
+'''
+ Compiler classes for Cheetah:
+ ModuleCompiler aka 'Compiler'
+ ClassCompiler
+ MethodCompiler
+
+ If you are trying to grok this code start with ModuleCompiler.__init__,
+ ModuleCompiler.compile, and ModuleCompiler.__getattr__.
+'''
+
+import sys
+import os
+import os.path
+from os.path import getmtime, exists
+import re
+import types
+import time
+import random
+import warnings
+import copy
+
+from Cheetah.Version import Version, VersionTuple
+from Cheetah.SettingsManager import SettingsManager
+from Cheetah.Utils.Indenter import indentize # an undocumented preprocessor
+from Cheetah import ErrorCatchers
+from Cheetah import NameMapper
+from Cheetah.Parser import Parser, ParseError, specialVarRE, \
+ STATIC_CACHE, REFRESH_CACHE, SET_LOCAL, SET_GLOBAL,SET_MODULE, \
+ unicodeDirectiveRE, encodingDirectiveRE,escapedNewlineRE
+
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+
+class Error(Exception): pass
+
+# Settings format: (key, default, docstring)
+_DEFAULT_COMPILER_SETTINGS = [
+ ('useNameMapper', True, 'Enable NameMapper for dotted notation and searchList support'),
+ ('useSearchList', True, 'Enable the searchList, requires useNameMapper=True, if disabled, first portion of the $variable is a global, builtin, or local variable that doesn\'t need looking up in the searchList'),
+ ('allowSearchListAsMethArg', True, ''),
+ ('useAutocalling', True, 'Detect and call callable objects in searchList, requires useNameMapper=True'),
+ ('useStackFrames', True, 'Used for NameMapper.valueFromFrameOrSearchList rather than NameMapper.valueFromSearchList'),
+ ('useErrorCatcher', False, 'Turn on the #errorCatcher directive for catching NameMapper errors, etc'),
+ ('alwaysFilterNone', True, 'Filter out None prior to calling the #filter'),
+ ('useFilters', True, 'If False, pass output through str()'),
+ ('includeRawExprInFilterArgs', True, ''),
+ ('useLegacyImportMode', True, 'All #import statements are relocated to the top of the generated Python module'),
+ ('prioritizeSearchListOverSelf', False, 'When iterating the searchList, look into the searchList passed into the initializer instead of Template members first'),
+
+ ('autoAssignDummyTransactionToSelf', False, ''),
+ ('useKWsDictArgForPassingTrans', True, ''),
+
+ ('commentOffset', 1, ''),
+ ('outputRowColComments', True, ''),
+ ('includeBlockMarkers', False, 'Wrap #block\'s in a comment in the template\'s output'),
+ ('blockMarkerStart', ('\n<!-- START BLOCK: ',' -->\n'), ''),
+ ('blockMarkerEnd', ('\n<!-- END BLOCK: ',' -->\n'), ''),
+ ('defDocStrMsg', 'Autogenerated by Cheetah: The Python-Powered Template Engine', ''),
+ ('setup__str__method', False, ''),
+ ('mainMethodName', 'respond', ''),
+ ('mainMethodNameForSubclasses', 'writeBody', ''),
+ ('indentationStep', ' ' * 4, ''),
+ ('initialMethIndentLevel', 2, ''),
+ ('monitorSrcFile', False, ''),
+ ('outputMethodsBeforeAttributes', True, ''),
+ ('addTimestampsToCompilerOutput', True, ''),
+
+ ## Customizing the #extends directive
+ ('autoImportForExtendsDirective', True, ''),
+ ('handlerForExtendsDirective', None, ''),
+
+ ('disabledDirectives', [], 'List of directive keys to disable (without starting "#")'),
+ ('enabledDirectives', [], 'List of directive keys to enable (without starting "#")'),
+ ('disabledDirectiveHooks', [], 'callable(parser, directiveKey)'),
+ ('preparseDirectiveHooks', [], 'callable(parser, directiveKey)'),
+ ('postparseDirectiveHooks', [], 'callable(parser, directiveKey)'),
+ ('preparsePlaceholderHooks', [], 'callable(parser)'),
+ ('postparsePlaceholderHooks', [], 'callable(parser)'),
+ ('expressionFilterHooks', [], '''callable(parser, expr, exprType, rawExpr=None, startPos=None), exprType is the name of the directive, "psp" or "placeholder" The filters *must* return the expr or raise an expression, they can modify the expr if needed'''),
+ ('templateMetaclass', None, 'Strictly optional, only will work with new-style basecalsses as well'),
+ ('i18NFunctionName', 'self.i18n', ''),
+
+ ('cheetahVarStartToken', '$', ''),
+ ('commentStartToken', '##', ''),
+ ('multiLineCommentStartToken', '#*', ''),
+ ('multiLineCommentEndToken', '*#', ''),
+ ('gobbleWhitespaceAroundMultiLineComments', True, ''),
+ ('directiveStartToken', '#', ''),
+ ('directiveEndToken', '#', ''),
+ ('allowWhitespaceAfterDirectiveStartToken', False, ''),
+ ('PSPStartToken', '<%', ''),
+ ('PSPEndToken', '%>', ''),
+ ('EOLSlurpToken', '#', ''),
+ ('gettextTokens', ["_", "N_", "ngettext"], ''),
+ ('allowExpressionsInExtendsDirective', False, ''),
+ ('allowEmptySingleLineMethods', False, ''),
+ ('allowNestedDefScopes', True, ''),
+ ('allowPlaceholderFilterArgs', True, ''),
+]
+
+DEFAULT_COMPILER_SETTINGS = dict([(v[0], v[1]) for v in _DEFAULT_COMPILER_SETTINGS])
+
+
+
+class GenUtils:
+ """An abstract baseclass for the Compiler classes that provides methods that
+ perform generic utility functions or generate pieces of output code from
+ information passed in by the Parser baseclass. These methods don't do any
+ parsing themselves.
+ """
+
+ def genTimeInterval(self, timeString):
+ ##@@ TR: need to add some error handling here
+ if timeString[-1] == 's':
+ interval = float(timeString[:-1])
+ elif timeString[-1] == 'm':
+ interval = float(timeString[:-1])*60
+ elif timeString[-1] == 'h':
+ interval = float(timeString[:-1])*60*60
+ elif timeString[-1] == 'd':
+ interval = float(timeString[:-1])*60*60*24
+ elif timeString[-1] == 'w':
+ interval = float(timeString[:-1])*60*60*24*7
+ else: # default to minutes
+ interval = float(timeString)*60
+ return interval
+
+ def genCacheInfo(self, cacheTokenParts):
+ """Decipher a placeholder cachetoken
+ """
+ cacheInfo = {}
+ if cacheTokenParts['REFRESH_CACHE']:
+ cacheInfo['type'] = REFRESH_CACHE
+ cacheInfo['interval'] = self.genTimeInterval(cacheTokenParts['interval'])
+ elif cacheTokenParts['STATIC_CACHE']:
+ cacheInfo['type'] = STATIC_CACHE
+ return cacheInfo # is empty if no cache
+
+ def genCacheInfoFromArgList(self, argList):
+ cacheInfo = {'type':REFRESH_CACHE}
+ for key, val in argList:
+ if val[0] in '"\'':
+ val = val[1:-1]
+
+ if key == 'timer':
+ key = 'interval'
+ val = self.genTimeInterval(val)
+
+ cacheInfo[key] = val
+ return cacheInfo
+
+ def genCheetahVar(self, nameChunks, plain=False):
+ if nameChunks[0][0] in self.setting('gettextTokens'):
+ self.addGetTextVar(nameChunks)
+ if self.setting('useNameMapper') and not plain:
+ return self.genNameMapperVar(nameChunks)
+ else:
+ return self.genPlainVar(nameChunks)
+
+ def addGetTextVar(self, nameChunks):
+ """Output something that gettext can recognize.
+
+ This is a harmless side effect necessary to make gettext work when it
+ is scanning compiled templates for strings marked for translation.
+
+ @@TR: another marginally more efficient approach would be to put the
+ output in a dummy method that is never called.
+ """
+ # @@TR: this should be in the compiler not here
+ self.addChunk("if False:")
+ self.indent()
+ self.addChunk(self.genPlainVar(nameChunks[:]))
+ self.dedent()
+
+ def genPlainVar(self, nameChunks):
+ """Generate Python code for a Cheetah $var without using NameMapper
+ (Unified Dotted Notation with the SearchList).
+ """
+ nameChunks.reverse()
+ chunk = nameChunks.pop()
+ pythonCode = chunk[0] + chunk[2]
+ while nameChunks:
+ chunk = nameChunks.pop()
+ pythonCode = (pythonCode + '.' + chunk[0] + chunk[2])
+ return pythonCode
+
+ def genNameMapperVar(self, nameChunks):
+ """Generate valid Python code for a Cheetah $var, using NameMapper
+ (Unified Dotted Notation with the SearchList).
+
+ nameChunks = list of var subcomponents represented as tuples
+ [ (name,useAC,remainderOfExpr),
+ ]
+ where:
+ name = the dotted name base
+ useAC = where NameMapper should use autocalling on namemapperPart
+ remainderOfExpr = any arglist, index, or slice
+
+ If remainderOfExpr contains a call arglist (e.g. '(1234)') then useAC
+ is False, otherwise it defaults to True. It is overridden by the global
+ setting 'useAutocalling' if this setting is False.
+
+ EXAMPLE
+ ------------------------------------------------------------------------
+ if the raw Cheetah Var is
+ $a.b.c[1].d().x.y.z
+
+ nameChunks is the list
+ [ ('a.b.c',True,'[1]'), # A
+ ('d',False,'()'), # B
+ ('x.y.z',True,''), # C
+ ]
+
+ When this method is fed the list above it returns
+ VFN(VFN(VFFSL(SL, 'a.b.c',True)[1], 'd',False)(), 'x.y.z',True)
+ which can be represented as
+ VFN(B`, name=C[0], executeCallables=(useAC and C[1]))C[2]
+ where:
+ VFN = NameMapper.valueForName
+ VFFSL = NameMapper.valueFromFrameOrSearchList
+ VFSL = NameMapper.valueFromSearchList # optionally used instead of VFFSL
+ SL = self.searchList()
+ useAC = self.setting('useAutocalling') # True in this example
+
+ A = ('a.b.c',True,'[1]')
+ B = ('d',False,'()')
+ C = ('x.y.z',True,'')
+
+ C` = VFN( VFN( VFFSL(SL, 'a.b.c',True)[1],
+ 'd',False)(),
+ 'x.y.z',True)
+ = VFN(B`, name='x.y.z', executeCallables=True)
+
+ B` = VFN(A`, name=B[0], executeCallables=(useAC and B[1]))B[2]
+ A` = VFFSL(SL, name=A[0], executeCallables=(useAC and A[1]))A[2]
+
+
+ Note, if the compiler setting useStackFrames=False (default is true)
+ then
+ A` = VFSL([locals()]+SL+[globals(), __builtin__], name=A[0], executeCallables=(useAC and A[1]))A[2]
+ This option allows Cheetah to be used with Psyco, which doesn't support
+ stack frame introspection.
+ """
+ defaultUseAC = self.setting('useAutocalling')
+ useSearchList = self.setting('useSearchList')
+
+ nameChunks.reverse()
+ name, useAC, remainder = nameChunks.pop()
+
+ if not useSearchList:
+ firstDotIdx = name.find('.')
+ if firstDotIdx != -1 and firstDotIdx < len(name):
+ beforeFirstDot, afterDot = name[:firstDotIdx], name[firstDotIdx+1:]
+ pythonCode = ('VFN(' + beforeFirstDot +
+ ',"' + afterDot +
+ '",' + repr(defaultUseAC and useAC) + ')'
+ + remainder)
+ else:
+ pythonCode = name+remainder
+ elif self.setting('useStackFrames'):
+ pythonCode = ('VFFSL(SL,'
+ '"'+ name + '",'
+ + repr(defaultUseAC and useAC) + ')'
+ + remainder)
+ else:
+ pythonCode = ('VFSL([locals()]+SL+[globals(), __builtin__],'
+ '"'+ name + '",'
+ + repr(defaultUseAC and useAC) + ')'
+ + remainder)
+ ##
+ while nameChunks:
+ name, useAC, remainder = nameChunks.pop()
+ pythonCode = ('VFN(' + pythonCode +
+ ',"' + name +
+ '",' + repr(defaultUseAC and useAC) + ')'
+ + remainder)
+ return pythonCode
+
+##################################################
+## METHOD COMPILERS
+
+class MethodCompiler(GenUtils):
+ def __init__(self, methodName, classCompiler,
+ initialMethodComment=None,
+ decorators=None):
+ self._settingsManager = classCompiler
+ self._classCompiler = classCompiler
+ self._moduleCompiler = classCompiler._moduleCompiler
+ self._methodName = methodName
+ self._initialMethodComment = initialMethodComment
+ self._setupState()
+ self._decorators = decorators or []
+
+ def setting(self, key):
+ return self._settingsManager.setting(key)
+
+ def _setupState(self):
+ self._indent = self.setting('indentationStep')
+ self._indentLev = self.setting('initialMethIndentLevel')
+ self._pendingStrConstChunks = []
+ self._methodSignature = None
+ self._methodDef = None
+ self._docStringLines = []
+ self._methodBodyChunks = []
+
+ self._cacheRegionsStack = []
+ self._callRegionsStack = []
+ self._captureRegionsStack = []
+ self._filterRegionsStack = []
+
+ self._isErrorCatcherOn = False
+
+ self._hasReturnStatement = False
+ self._isGenerator = False
+
+
+ def cleanupState(self):
+ """Called by the containing class compiler instance
+ """
+ pass
+
+ def methodName(self):
+ return self._methodName
+
+ def setMethodName(self, name):
+ self._methodName = name
+
+ ## methods for managing indentation
+
+ def indentation(self):
+ return self._indent * self._indentLev
+
+ def indent(self):
+ self._indentLev +=1
+
+ def dedent(self):
+ if self._indentLev:
+ self._indentLev -=1
+ else:
+ raise Error('Attempt to dedent when the indentLev is 0')
+
+ ## methods for final code wrapping
+
+ def methodDef(self):
+ if self._methodDef:
+ return self._methodDef
+ else:
+ return self.wrapCode()
+
+ __str__ = methodDef
+ __unicode__ = methodDef
+
+ def wrapCode(self):
+ self.commitStrConst()
+ methodDefChunks = (
+ self.methodSignature(),
+ '\n',
+ self.docString(),
+ self.methodBody() )
+ methodDef = ''.join(methodDefChunks)
+ self._methodDef = methodDef
+ return methodDef
+
+ def methodSignature(self):
+ return self._indent + self._methodSignature + ':'
+
+ def setMethodSignature(self, signature):
+ self._methodSignature = signature
+
+ def methodBody(self):
+ return ''.join( self._methodBodyChunks )
+
+ def docString(self):
+ if not self._docStringLines:
+ return ''
+
+ ind = self._indent*2
+ docStr = (ind + '"""\n' + ind +
+ ('\n' + ind).join([ln.replace('"""',"'''") for ln in self._docStringLines]) +
+ '\n' + ind + '"""\n')
+ return docStr
+
+ ## methods for adding code
+ def addMethDocString(self, line):
+ self._docStringLines.append(line.replace('%','%%'))
+
+ def addChunk(self, chunk):
+ self.commitStrConst()
+ chunk = "\n" + self.indentation() + chunk
+ self._methodBodyChunks.append(chunk)
+
+ def appendToPrevChunk(self, appendage):
+ self._methodBodyChunks[-1] = self._methodBodyChunks[-1] + appendage
+
+ def addWriteChunk(self, chunk):
+ self.addChunk('write(' + chunk + ')')
+
+ def addFilteredChunk(self, chunk, filterArgs=None, rawExpr=None, lineCol=None):
+ if filterArgs is None:
+ filterArgs = ''
+ if self.setting('includeRawExprInFilterArgs') and rawExpr:
+ filterArgs += ', rawExpr=%s'%repr(rawExpr)
+
+ if self.setting('alwaysFilterNone'):
+ if rawExpr and rawExpr.find('\n')==-1 and rawExpr.find('\r')==-1:
+ self.addChunk("_v = %s # %r"%(chunk, rawExpr))
+ if lineCol:
+ self.appendToPrevChunk(' on line %s, col %s'%lineCol)
+ else:
+ self.addChunk("_v = %s"%chunk)
+
+ if self.setting('useFilters'):
+ self.addChunk("if _v is not None: write(_filter(_v%s))"%filterArgs)
+ else:
+ self.addChunk("if _v is not None: write(str(_v))")
+ else:
+ if self.setting('useFilters'):
+ self.addChunk("write(_filter(%s%s))"%(chunk,filterArgs))
+ else:
+ self.addChunk("write(str(%s))"%chunk)
+
+ def _appendToPrevStrConst(self, strConst):
+ if self._pendingStrConstChunks:
+ self._pendingStrConstChunks.append(strConst)
+ else:
+ self._pendingStrConstChunks = [strConst]
+
+ def _unescapeCheetahVars(self, theString):
+ """Unescape any escaped Cheetah \$vars in the string.
+ """
+
+ token = self.setting('cheetahVarStartToken')
+ return theString.replace('\\' + token, token)
+
+ def _unescapeDirectives(self, theString):
+ """Unescape any escaped Cheetah \$vars in the string.
+ """
+
+ token = self.setting('directiveStartToken')
+ return theString.replace('\\' + token, token)
+
+ def commitStrConst(self):
+ """Add the code for outputting the pending strConst without chopping off
+ any whitespace from it.
+ """
+ if self._pendingStrConstChunks:
+ strConst = self._unescapeCheetahVars(''.join(self._pendingStrConstChunks))
+ strConst = self._unescapeDirectives(strConst)
+ self._pendingStrConstChunks = []
+ if not strConst:
+ return
+ else:
+ reprstr = repr(strConst).replace('\\012','\n')
+ i = 0
+ out = []
+ if reprstr.startswith('u'):
+ i = 1
+ out = ['u']
+ body = escapedNewlineRE.sub('\n', reprstr[i+1:-1])
+
+ if reprstr[i]=="'":
+ out.append("'''")
+ out.append(body)
+ out.append("'''")
+ else:
+ out.append('"""')
+ out.append(body)
+ out.append('"""')
+ self.addWriteChunk(''.join(out))
+
+ def handleWSBeforeDirective(self):
+ """Truncate the pending strCont to the beginning of the current line.
+ """
+ if self._pendingStrConstChunks:
+ src = self._pendingStrConstChunks[-1]
+ BOL = max(src.rfind('\n')+1, src.rfind('\r')+1, 0)
+ if BOL < len(src):
+ self._pendingStrConstChunks[-1] = src[:BOL]
+
+
+
+ def isErrorCatcherOn(self):
+ return self._isErrorCatcherOn
+
+ def turnErrorCatcherOn(self):
+ self._isErrorCatcherOn = True
+
+ def turnErrorCatcherOff(self):
+ self._isErrorCatcherOn = False
+
+ # @@TR: consider merging the next two methods into one
+ def addStrConst(self, strConst):
+ self._appendToPrevStrConst(strConst)
+
+ def addRawText(self, text):
+ self.addStrConst(text)
+
+ def addMethComment(self, comm):
+ offSet = self.setting('commentOffset')
+ self.addChunk('#' + ' '*offSet + comm)
+
+ def addPlaceholder(self, expr, filterArgs, rawPlaceholder,
+ cacheTokenParts, lineCol,
+ silentMode=False):
+ cacheInfo = self.genCacheInfo(cacheTokenParts)
+ if cacheInfo:
+ cacheInfo['ID'] = repr(rawPlaceholder)[1:-1]
+ self.startCacheRegion(cacheInfo, lineCol, rawPlaceholder=rawPlaceholder)
+
+ if self.isErrorCatcherOn():
+ methodName = self._classCompiler.addErrorCatcherCall(
+ expr, rawCode=rawPlaceholder, lineCol=lineCol)
+ expr = 'self.' + methodName + '(localsDict=locals())'
+
+ if silentMode:
+ self.addChunk('try:')
+ self.indent()
+ self.addFilteredChunk(expr, filterArgs, rawPlaceholder, lineCol=lineCol)
+ self.dedent()
+ self.addChunk('except NotFound: pass')
+ else:
+ self.addFilteredChunk(expr, filterArgs, rawPlaceholder, lineCol=lineCol)
+
+ if self.setting('outputRowColComments'):
+ self.appendToPrevChunk(' # from line %s, col %s' % lineCol + '.')
+ if cacheInfo:
+ self.endCacheRegion()
+
+ def addSilent(self, expr):
+ self.addChunk( expr )
+
+ def addEcho(self, expr, rawExpr=None):
+ self.addFilteredChunk(expr, rawExpr=rawExpr)
+
+ def addSet(self, expr, exprComponents, setStyle):
+ if setStyle is SET_GLOBAL:
+ (LVALUE, OP, RVALUE) = (exprComponents.LVALUE,
+ exprComponents.OP,
+ exprComponents.RVALUE)
+ # we need to split the LVALUE to deal with globalSetVars
+ splitPos1 = LVALUE.find('.')
+ splitPos2 = LVALUE.find('[')
+ if splitPos1 > 0 and splitPos2==-1:
+ splitPos = splitPos1
+ elif splitPos1 > 0 and splitPos1 < max(splitPos2,0):
+ splitPos = splitPos1
+ else:
+ splitPos = splitPos2
+
+ if splitPos >0:
+ primary = LVALUE[:splitPos]
+ secondary = LVALUE[splitPos:]
+ else:
+ primary = LVALUE
+ secondary = ''
+ LVALUE = 'self._CHEETAH__globalSetVars["' + primary + '"]' + secondary
+ expr = LVALUE + ' ' + OP + ' ' + RVALUE.strip()
+
+ if setStyle is SET_MODULE:
+ self._moduleCompiler.addModuleGlobal(expr)
+ else:
+ self.addChunk(expr)
+
+ def addInclude(self, sourceExpr, includeFrom, isRaw):
+ self.addChunk('self._handleCheetahInclude(' + sourceExpr +
+ ', trans=trans, ' +
+ 'includeFrom="' + includeFrom + '", raw=' +
+ repr(isRaw) + ')')
+
+ def addWhile(self, expr, lineCol=None):
+ self.addIndentingDirective(expr, lineCol=lineCol)
+
+ def addFor(self, expr, lineCol=None):
+ self.addIndentingDirective(expr, lineCol=lineCol)
+
+ def addRepeat(self, expr, lineCol=None):
+ #the _repeatCount stuff here allows nesting of #repeat directives
+ self._repeatCount = getattr(self, "_repeatCount", -1) + 1
+ self.addFor('for __i%s in range(%s)' % (self._repeatCount,expr), lineCol=lineCol)
+
+ def addIndentingDirective(self, expr, lineCol=None):
+ if expr and not expr[-1] == ':':
+ expr = expr + ':'
+ self.addChunk( expr )
+ if lineCol:
+ self.appendToPrevChunk(' # generated from line %s, col %s'%lineCol )
+ self.indent()
+
+ def addReIndentingDirective(self, expr, dedent=True, lineCol=None):
+ self.commitStrConst()
+ if dedent:
+ self.dedent()
+ if not expr[-1] == ':':
+ expr = expr + ':'
+
+ self.addChunk( expr )
+ if lineCol:
+ self.appendToPrevChunk(' # generated from line %s, col %s'%lineCol )
+ self.indent()
+
+ def addIf(self, expr, lineCol=None):
+ """For a full #if ... #end if directive
+ """
+ self.addIndentingDirective(expr, lineCol=lineCol)
+
+ def addOneLineIf(self, expr, lineCol=None):
+ """For a full #if ... #end if directive
+ """
+ self.addIndentingDirective(expr, lineCol=lineCol)
+
+ def addTernaryExpr(self, conditionExpr, trueExpr, falseExpr, lineCol=None):
+ """For a single-lie #if ... then .... else ... directive
+ <condition> then <trueExpr> else <falseExpr>
+ """
+ self.addIndentingDirective(conditionExpr, lineCol=lineCol)
+ self.addFilteredChunk(trueExpr)
+ self.dedent()
+ self.addIndentingDirective('else')
+ self.addFilteredChunk(falseExpr)
+ self.dedent()
+
+ def addElse(self, expr, dedent=True, lineCol=None):
+ expr = re.sub(r'else[ \f\t]+if','elif', expr)
+ self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol)
+
+ def addElif(self, expr, dedent=True, lineCol=None):
+ self.addElse(expr, dedent=dedent, lineCol=lineCol)
+
+ def addUnless(self, expr, lineCol=None):
+ self.addIf('if not (' + expr + ')')
+
+ def addClosure(self, functionName, argsList, parserComment):
+ argStringChunks = []
+ for arg in argsList:
+ chunk = arg[0]
+ if not arg[1] == None:
+ chunk += '=' + arg[1]
+ argStringChunks.append(chunk)
+ signature = "def " + functionName + "(" + ','.join(argStringChunks) + "):"
+ self.addIndentingDirective(signature)
+ self.addChunk('#'+parserComment)
+
+ def addTry(self, expr, lineCol=None):
+ self.addIndentingDirective(expr, lineCol=lineCol)
+
+ def addExcept(self, expr, dedent=True, lineCol=None):
+ self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol)
+
+ def addFinally(self, expr, dedent=True, lineCol=None):
+ self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol)
+
+ def addReturn(self, expr):
+ assert not self._isGenerator
+ self.addChunk(expr)
+ self._hasReturnStatement = True
+
+ def addYield(self, expr):
+ assert not self._hasReturnStatement
+ self._isGenerator = True
+ if expr.replace('yield','').strip():
+ self.addChunk(expr)
+ else:
+ self.addChunk('if _dummyTrans:')
+ self.indent()
+ self.addChunk('yield trans.response().getvalue()')
+ self.addChunk('trans = DummyTransaction()')
+ self.addChunk('write = trans.response().write')
+ self.dedent()
+ self.addChunk('else:')
+ self.indent()
+ self.addChunk(
+ 'raise TypeError("This method cannot be called with a trans arg")')
+ self.dedent()
+
+
+ def addPass(self, expr):
+ self.addChunk(expr)
+
+ def addDel(self, expr):
+ self.addChunk(expr)
+
+ def addAssert(self, expr):
+ self.addChunk(expr)
+
+ def addRaise(self, expr):
+ self.addChunk(expr)
+
+ def addBreak(self, expr):
+ self.addChunk(expr)
+
+ def addContinue(self, expr):
+ self.addChunk(expr)
+
+ def addPSP(self, PSP):
+ self.commitStrConst()
+ autoIndent = False
+ if PSP[0] == '=':
+ PSP = PSP[1:]
+ if PSP:
+ self.addWriteChunk('_filter(' + PSP + ')')
+ return
+
+ elif PSP.lower() == 'end':
+ self.dedent()
+ return
+ elif PSP[-1] == '$':
+ autoIndent = True
+ PSP = PSP[:-1]
+ elif PSP[-1] == ':':
+ autoIndent = True
+
+ for line in PSP.splitlines():
+ self.addChunk(line)
+
+ if autoIndent:
+ self.indent()
+
+ def nextCacheID(self):
+ return ('_'+str(random.randrange(100, 999))
+ + str(random.randrange(10000, 99999)))
+
+ def startCacheRegion(self, cacheInfo, lineCol, rawPlaceholder=None):
+
+ # @@TR: we should add some runtime logging to this
+
+ ID = self.nextCacheID()
+ interval = cacheInfo.get('interval',None)
+ test = cacheInfo.get('test',None)
+ customID = cacheInfo.get('id',None)
+ if customID:
+ ID = customID
+ varyBy = cacheInfo.get('varyBy', repr(ID))
+ self._cacheRegionsStack.append(ID) # attrib of current methodCompiler
+
+ # @@TR: add this to a special class var as well
+ self.addChunk('')
+
+ self.addChunk('## START CACHE REGION: ID='+ID+
+ '. line %s, col %s'%lineCol + ' in the source.')
+
+ self.addChunk('_RECACHE_%(ID)s = False'%locals())
+ self.addChunk('_cacheRegion_%(ID)s = self.getCacheRegion(regionID='%locals()
+ + repr(ID)
+ + ', cacheInfo=%r'%cacheInfo
+ + ')')
+ self.addChunk('if _cacheRegion_%(ID)s.isNew():'%locals())
+ self.indent()
+ self.addChunk('_RECACHE_%(ID)s = True'%locals())
+ self.dedent()
+
+ self.addChunk('_cacheItem_%(ID)s = _cacheRegion_%(ID)s.getCacheItem('%locals()
+ +varyBy+')')
+
+ self.addChunk('if _cacheItem_%(ID)s.hasExpired():'%locals())
+ self.indent()
+ self.addChunk('_RECACHE_%(ID)s = True'%locals())
+ self.dedent()
+
+ if test:
+ self.addChunk('if ' + test + ':')
+ self.indent()
+ self.addChunk('_RECACHE_%(ID)s = True'%locals())
+ self.dedent()
+
+ self.addChunk('if (not _RECACHE_%(ID)s) and _cacheItem_%(ID)s.getRefreshTime():'%locals())
+ self.indent()
+ #self.addChunk('print "DEBUG"+"-"*50')
+ self.addChunk('try:')
+ self.indent()
+ self.addChunk('_output = _cacheItem_%(ID)s.renderOutput()'%locals())
+ self.dedent()
+ self.addChunk('except KeyError:')
+ self.indent()
+ self.addChunk('_RECACHE_%(ID)s = True'%locals())
+ #self.addChunk('print "DEBUG"+"*"*50')
+ self.dedent()
+ self.addChunk('else:')
+ self.indent()
+ self.addWriteChunk('_output')
+ self.addChunk('del _output')
+ self.dedent()
+
+ self.dedent()
+
+ self.addChunk('if _RECACHE_%(ID)s or not _cacheItem_%(ID)s.getRefreshTime():'%locals())
+ self.indent()
+ self.addChunk('_orig_trans%(ID)s = trans'%locals())
+ self.addChunk('trans = _cacheCollector_%(ID)s = DummyTransaction()'%locals())
+ self.addChunk('write = _cacheCollector_%(ID)s.response().write'%locals())
+ if interval:
+ self.addChunk(("_cacheItem_%(ID)s.setExpiryTime(currentTime() +"%locals())
+ + str(interval) + ")")
+
+ def endCacheRegion(self):
+ ID = self._cacheRegionsStack.pop()
+ self.addChunk('trans = _orig_trans%(ID)s'%locals())
+ self.addChunk('write = trans.response().write')
+ self.addChunk('_cacheData = _cacheCollector_%(ID)s.response().getvalue()'%locals())
+ self.addChunk('_cacheItem_%(ID)s.setData(_cacheData)'%locals())
+ self.addWriteChunk('_cacheData')
+ self.addChunk('del _cacheData')
+ self.addChunk('del _cacheCollector_%(ID)s'%locals())
+ self.addChunk('del _orig_trans%(ID)s'%locals())
+ self.dedent()
+ self.addChunk('## END CACHE REGION: '+ID)
+ self.addChunk('')
+
+ def nextCallRegionID(self):
+ return self.nextCacheID()
+
+ def startCallRegion(self, functionName, args, lineCol, regionTitle='CALL'):
+ class CallDetails(object):
+ pass
+ callDetails = CallDetails()
+ callDetails.ID = ID = self.nextCallRegionID()
+ callDetails.functionName = functionName
+ callDetails.args = args
+ callDetails.lineCol = lineCol
+ callDetails.usesKeywordArgs = False
+ self._callRegionsStack.append((ID, callDetails)) # attrib of current methodCompiler
+
+ self.addChunk('## START %(regionTitle)s REGION: '%locals()
+ +ID
+ +' of '+functionName
+ +' at line %s, col %s'%lineCol + ' in the source.')
+ self.addChunk('_orig_trans%(ID)s = trans'%locals())
+ self.addChunk('_wasBuffering%(ID)s = self._CHEETAH__isBuffering'%locals())
+ self.addChunk('self._CHEETAH__isBuffering = True')
+ self.addChunk('trans = _callCollector%(ID)s = DummyTransaction()'%locals())
+ self.addChunk('write = _callCollector%(ID)s.response().write'%locals())
+
+ def setCallArg(self, argName, lineCol):
+ ID, callDetails = self._callRegionsStack[-1]
+ argName = str(argName)
+ if callDetails.usesKeywordArgs:
+ self._endCallArg()
+ else:
+ callDetails.usesKeywordArgs = True
+ self.addChunk('_callKws%(ID)s = {}'%locals())
+ self.addChunk('_currentCallArgname%(ID)s = %(argName)r'%locals())
+ callDetails.currentArgname = argName
+
+ def _endCallArg(self):
+ ID, callDetails = self._callRegionsStack[-1]
+ currCallArg = callDetails.currentArgname
+ self.addChunk(('_callKws%(ID)s[%(currCallArg)r] ='
+ ' _callCollector%(ID)s.response().getvalue()')%locals())
+ self.addChunk('del _callCollector%(ID)s'%locals())
+ self.addChunk('trans = _callCollector%(ID)s = DummyTransaction()'%locals())
+ self.addChunk('write = _callCollector%(ID)s.response().write'%locals())
+
+ def endCallRegion(self, regionTitle='CALL'):
+ ID, callDetails = self._callRegionsStack[-1]
+ functionName, initialKwArgs, lineCol = (
+ callDetails.functionName, callDetails.args, callDetails.lineCol)
+
+ def reset(ID=ID):
+ self.addChunk('trans = _orig_trans%(ID)s'%locals())
+ self.addChunk('write = trans.response().write')
+ self.addChunk('self._CHEETAH__isBuffering = _wasBuffering%(ID)s '%locals())
+ self.addChunk('del _wasBuffering%(ID)s'%locals())
+ self.addChunk('del _orig_trans%(ID)s'%locals())
+
+ if not callDetails.usesKeywordArgs:
+ reset()
+ self.addChunk('_callArgVal%(ID)s = _callCollector%(ID)s.response().getvalue()'%locals())
+ self.addChunk('del _callCollector%(ID)s'%locals())
+ if initialKwArgs:
+ initialKwArgs = ', '+initialKwArgs
+ self.addFilteredChunk('%(functionName)s(_callArgVal%(ID)s%(initialKwArgs)s)'%locals())
+ self.addChunk('del _callArgVal%(ID)s'%locals())
+ else:
+ if initialKwArgs:
+ initialKwArgs = initialKwArgs+', '
+ self._endCallArg()
+ reset()
+ self.addFilteredChunk('%(functionName)s(%(initialKwArgs)s**_callKws%(ID)s)'%locals())
+ self.addChunk('del _callKws%(ID)s'%locals())
+ self.addChunk('## END %(regionTitle)s REGION: '%locals()
+ +ID
+ +' of '+functionName
+ +' at line %s, col %s'%lineCol + ' in the source.')
+ self.addChunk('')
+ self._callRegionsStack.pop() # attrib of current methodCompiler
+
+ def nextCaptureRegionID(self):
+ return self.nextCacheID()
+
+ def startCaptureRegion(self, assignTo, lineCol):
+ class CaptureDetails: pass
+ captureDetails = CaptureDetails()
+ captureDetails.ID = ID = self.nextCaptureRegionID()
+ captureDetails.assignTo = assignTo
+ captureDetails.lineCol = lineCol
+
+ self._captureRegionsStack.append((ID,captureDetails)) # attrib of current methodCompiler
+ self.addChunk('## START CAPTURE REGION: '+ID
+ +' '+assignTo
+ +' at line %s, col %s'%lineCol + ' in the source.')
+ self.addChunk('_orig_trans%(ID)s = trans'%locals())
+ self.addChunk('_wasBuffering%(ID)s = self._CHEETAH__isBuffering'%locals())
+ self.addChunk('self._CHEETAH__isBuffering = True')
+ self.addChunk('trans = _captureCollector%(ID)s = DummyTransaction()'%locals())
+ self.addChunk('write = _captureCollector%(ID)s.response().write'%locals())
+
+ def endCaptureRegion(self):
+ ID, captureDetails = self._captureRegionsStack.pop()
+ assignTo, lineCol = (captureDetails.assignTo, captureDetails.lineCol)
+ self.addChunk('trans = _orig_trans%(ID)s'%locals())
+ self.addChunk('write = trans.response().write')
+ self.addChunk('self._CHEETAH__isBuffering = _wasBuffering%(ID)s '%locals())
+ self.addChunk('%(assignTo)s = _captureCollector%(ID)s.response().getvalue()'%locals())
+ self.addChunk('del _orig_trans%(ID)s'%locals())
+ self.addChunk('del _captureCollector%(ID)s'%locals())
+ self.addChunk('del _wasBuffering%(ID)s'%locals())
+
+ def setErrorCatcher(self, errorCatcherName):
+ self.turnErrorCatcherOn()
+
+ self.addChunk('if self._CHEETAH__errorCatchers.has_key("' + errorCatcherName + '"):')
+ self.indent()
+ self.addChunk('self._CHEETAH__errorCatcher = self._CHEETAH__errorCatchers["' +
+ errorCatcherName + '"]')
+ self.dedent()
+ self.addChunk('else:')
+ self.indent()
+ self.addChunk('self._CHEETAH__errorCatcher = self._CHEETAH__errorCatchers["'
+ + errorCatcherName + '"] = ErrorCatchers.'
+ + errorCatcherName + '(self)'
+ )
+ self.dedent()
+
+ def nextFilterRegionID(self):
+ return self.nextCacheID()
+
+ def setTransform(self, transformer, isKlass):
+ self.addChunk('trans = TransformerTransaction()')
+ self.addChunk('trans._response = trans.response()')
+ self.addChunk('trans._response._filter = %s' % transformer)
+ self.addChunk('write = trans._response.write')
+
+ def setFilter(self, theFilter, isKlass):
+ class FilterDetails:
+ pass
+ filterDetails = FilterDetails()
+ filterDetails.ID = ID = self.nextFilterRegionID()
+ filterDetails.theFilter = theFilter
+ filterDetails.isKlass = isKlass
+ self._filterRegionsStack.append((ID, filterDetails)) # attrib of current methodCompiler
+
+ self.addChunk('_orig_filter%(ID)s = _filter'%locals())
+ if isKlass:
+ self.addChunk('_filter = self._CHEETAH__currentFilter = ' + theFilter.strip() +
+ '(self).filter')
+ else:
+ if theFilter.lower() == 'none':
+ self.addChunk('_filter = self._CHEETAH__initialFilter')
+ else:
+ # is string representing the name of a builtin filter
+ self.addChunk('filterName = ' + repr(theFilter))
+ self.addChunk('if self._CHEETAH__filters.has_key("' + theFilter + '"):')
+ self.indent()
+ self.addChunk('_filter = self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName]')
+ self.dedent()
+ self.addChunk('else:')
+ self.indent()
+ self.addChunk('_filter = self._CHEETAH__currentFilter'
+ +' = \\\n\t\t\tself._CHEETAH__filters[filterName] = '
+ + 'getattr(self._CHEETAH__filtersLib, filterName)(self).filter')
+ self.dedent()
+
+ def closeFilterBlock(self):
+ ID, filterDetails = self._filterRegionsStack.pop()
+ #self.addChunk('_filter = self._CHEETAH__initialFilter')
+ #self.addChunk('_filter = _orig_filter%(ID)s'%locals())
+ self.addChunk('_filter = self._CHEETAH__currentFilter = _orig_filter%(ID)s'%locals())
+
+class AutoMethodCompiler(MethodCompiler):
+
+ def _setupState(self):
+ MethodCompiler._setupState(self)
+ self._argStringList = [ ("self",None) ]
+ self._streamingEnabled = True
+ self._isClassMethod = None
+ self._isStaticMethod = None
+
+ def _useKWsDictArgForPassingTrans(self):
+ alreadyHasTransArg = [argname for argname,defval in self._argStringList
+ if argname=='trans']
+ return (self.methodName()!='respond'
+ and not alreadyHasTransArg
+ and self.setting('useKWsDictArgForPassingTrans'))
+
+ def isClassMethod(self):
+ if self._isClassMethod is None:
+ self._isClassMethod = '@classmethod' in self._decorators
+ return self._isClassMethod
+
+ def isStaticMethod(self):
+ if self._isStaticMethod is None:
+ self._isStaticMethod = '@staticmethod' in self._decorators
+ return self._isStaticMethod
+
+ def cleanupState(self):
+ MethodCompiler.cleanupState(self)
+ self.commitStrConst()
+ if self._cacheRegionsStack:
+ self.endCacheRegion()
+ if self._callRegionsStack:
+ self.endCallRegion()
+
+ if self._streamingEnabled:
+ kwargsName = None
+ positionalArgsListName = None
+ for argname,defval in self._argStringList:
+ if argname.strip().startswith('**'):
+ kwargsName = argname.strip().replace('**','')
+ break
+ elif argname.strip().startswith('*'):
+ positionalArgsListName = argname.strip().replace('*','')
+
+ if not kwargsName and self._useKWsDictArgForPassingTrans():
+ kwargsName = 'KWS'
+ self.addMethArg('**KWS', None)
+ self._kwargsName = kwargsName
+
+ if not self._useKWsDictArgForPassingTrans():
+ if not kwargsName and not positionalArgsListName:
+ self.addMethArg('trans', 'None')
+ else:
+ self._streamingEnabled = False
+
+ self._indentLev = self.setting('initialMethIndentLevel')
+ mainBodyChunks = self._methodBodyChunks
+ self._methodBodyChunks = []
+ self._addAutoSetupCode()
+ self._methodBodyChunks.extend(mainBodyChunks)
+ self._addAutoCleanupCode()
+
+ def _addAutoSetupCode(self):
+ if self._initialMethodComment:
+ self.addChunk(self._initialMethodComment)
+
+ if self._streamingEnabled and not self.isClassMethod() and not self.isStaticMethod():
+ if self._useKWsDictArgForPassingTrans() and self._kwargsName:
+ self.addChunk('trans = %s.get("trans")'%self._kwargsName)
+ self.addChunk('if (not trans and not self._CHEETAH__isBuffering'
+ ' and not callable(self.transaction)):')
+ self.indent()
+ self.addChunk('trans = self.transaction'
+ ' # is None unless self.awake() was called')
+ self.dedent()
+ self.addChunk('if not trans:')
+ self.indent()
+ self.addChunk('trans = DummyTransaction()')
+ if self.setting('autoAssignDummyTransactionToSelf'):
+ self.addChunk('self.transaction = trans')
+ self.addChunk('_dummyTrans = True')
+ self.dedent()
+ self.addChunk('else: _dummyTrans = False')
+ else:
+ self.addChunk('trans = DummyTransaction()')
+ self.addChunk('_dummyTrans = True')
+ self.addChunk('write = trans.response().write')
+ if self.setting('useNameMapper'):
+ argNames = [arg[0] for arg in self._argStringList]
+ allowSearchListAsMethArg = self.setting('allowSearchListAsMethArg')
+ if allowSearchListAsMethArg and 'SL' in argNames:
+ pass
+ elif allowSearchListAsMethArg and 'searchList' in argNames:
+ self.addChunk('SL = searchList')
+ elif not self.isClassMethod() and not self.isStaticMethod():
+ self.addChunk('SL = self._CHEETAH__searchList')
+ else:
+ self.addChunk('SL = [KWS]')
+ if self.setting('useFilters'):
+ if self.isClassMethod() or self.isStaticMethod():
+ self.addChunk('_filter = lambda x, **kwargs: unicode(x)')
+ else:
+ self.addChunk('_filter = self._CHEETAH__currentFilter')
+ self.addChunk('')
+ self.addChunk("#" *40)
+ self.addChunk('## START - generated method body')
+ self.addChunk('')
+
+ def _addAutoCleanupCode(self):
+ self.addChunk('')
+ self.addChunk("#" *40)
+ self.addChunk('## END - generated method body')
+ self.addChunk('')
+
+ if not self._isGenerator:
+ self.addStop()
+ self.addChunk('')
+
+ def addStop(self, expr=None):
+ self.addChunk('return _dummyTrans and trans.response().getvalue() or ""')
+
+ def addMethArg(self, name, defVal=None):
+ self._argStringList.append( (name,defVal) )
+
+ def methodSignature(self):
+ argStringChunks = []
+ for arg in self._argStringList:
+ chunk = arg[0]
+ if chunk == 'self' and self.isClassMethod():
+ chunk = 'cls'
+ if chunk == 'self' and self.isStaticMethod():
+ # Skip the "self" method for @staticmethod decorators
+ continue
+ if not arg[1] == None:
+ chunk += '=' + arg[1]
+ argStringChunks.append(chunk)
+ argString = (', ').join(argStringChunks)
+
+ output = []
+ if self._decorators:
+ output.append(''.join([self._indent + decorator + '\n'
+ for decorator in self._decorators]))
+ output.append(self._indent + "def "
+ + self.methodName() + "(" +
+ argString + "):\n\n")
+ return ''.join(output)
+
+
+##################################################
+## CLASS COMPILERS
+
+_initMethod_initCheetah = """\
+if not self._CHEETAH__instanceInitialized:
+ cheetahKWArgs = {}
+ allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+ for k,v in KWs.items():
+ if k in allowedKWs: cheetahKWArgs[k] = v
+ self._initCheetahInstance(**cheetahKWArgs)
+""".replace('\n','\n'+' '*8)
+
+class ClassCompiler(GenUtils):
+ methodCompilerClass = AutoMethodCompiler
+ methodCompilerClassForInit = MethodCompiler
+
+ def __init__(self, className, mainMethodName='respond',
+ moduleCompiler=None,
+ fileName=None,
+ settingsManager=None):
+
+ self._settingsManager = settingsManager
+ self._fileName = fileName
+ self._className = className
+ self._moduleCompiler = moduleCompiler
+ self._mainMethodName = mainMethodName
+ self._setupState()
+ methodCompiler = self._spawnMethodCompiler(
+ mainMethodName,
+ initialMethodComment='## CHEETAH: main method generated for this template')
+
+ self._setActiveMethodCompiler(methodCompiler)
+ if fileName and self.setting('monitorSrcFile'):
+ self._addSourceFileMonitoring(fileName)
+
+ def setting(self, key):
+ return self._settingsManager.setting(key)
+
+ def __getattr__(self, name):
+ """Provide access to the methods and attributes of the MethodCompiler
+ at the top of the activeMethods stack: one-way namespace sharing
+
+
+ WARNING: Use .setMethods to assign the attributes of the MethodCompiler
+ from the methods of this class!!! or you will be assigning to attributes
+ of this object instead."""
+
+ if self.__dict__.has_key(name):
+ return self.__dict__[name]
+ elif hasattr(self.__class__, name):
+ return getattr(self.__class__, name)
+ elif self._activeMethodsList and hasattr(self._activeMethodsList[-1], name):
+ return getattr(self._activeMethodsList[-1], name)
+ else:
+ raise AttributeError, name
+
+ def _setupState(self):
+ self._classDef = None
+ self._decoratorsForNextMethod = []
+ self._activeMethodsList = [] # stack while parsing/generating
+ self._finishedMethodsList = [] # store by order
+ self._methodsIndex = {} # store by name
+ self._baseClass = 'Template'
+ self._classDocStringLines = []
+ # printed after methods in the gen class def:
+ self._generatedAttribs = ['_CHEETAH__instanceInitialized = False']
+ self._generatedAttribs.append('_CHEETAH_version = __CHEETAH_version__')
+ self._generatedAttribs.append(
+ '_CHEETAH_versionTuple = __CHEETAH_versionTuple__')
+
+ if self.setting('addTimestampsToCompilerOutput'):
+ self._generatedAttribs.append('_CHEETAH_genTime = __CHEETAH_genTime__')
+ self._generatedAttribs.append('_CHEETAH_genTimestamp = __CHEETAH_genTimestamp__')
+
+ self._generatedAttribs.append('_CHEETAH_src = __CHEETAH_src__')
+ self._generatedAttribs.append(
+ '_CHEETAH_srcLastModified = __CHEETAH_srcLastModified__')
+
+ if self.setting('templateMetaclass'):
+ self._generatedAttribs.append('__metaclass__ = '+self.setting('templateMetaclass'))
+ self._initMethChunks = []
+ self._blockMetaData = {}
+ self._errorCatcherCount = 0
+ self._placeholderToErrorCatcherMap = {}
+
+ def cleanupState(self):
+ while self._activeMethodsList:
+ methCompiler = self._popActiveMethodCompiler()
+ self._swallowMethodCompiler(methCompiler)
+ self._setupInitMethod()
+ if self._mainMethodName == 'respond':
+ if self.setting('setup__str__method'):
+ self._generatedAttribs.append('def __str__(self): return self.respond()')
+ self.addAttribute('_mainCheetahMethod_for_' + self._className +
+ '= ' + repr(self._mainMethodName) )
+
+ def _setupInitMethod(self):
+ __init__ = self._spawnMethodCompiler('__init__',
+ klass=self.methodCompilerClassForInit)
+ __init__.setMethodSignature("def __init__(self, *args, **KWs)")
+ __init__.addChunk('super(%s, self).__init__(*args, **KWs)' % self._className)
+ __init__.addChunk(_initMethod_initCheetah % {'className' : self._className})
+ for chunk in self._initMethChunks:
+ __init__.addChunk(chunk)
+ __init__.cleanupState()
+ self._swallowMethodCompiler(__init__, pos=0)
+
+ def _addSourceFileMonitoring(self, fileName):
+ # @@TR: this stuff needs auditing for Cheetah 2.0
+ # the first bit is added to init
+ self.addChunkToInit('self._filePath = ' + repr(fileName))
+ self.addChunkToInit('self._fileMtime = ' + str(getmtime(fileName)) )
+
+ # the rest is added to the main output method of the class ('mainMethod')
+ self.addChunk('if exists(self._filePath) and ' +
+ 'getmtime(self._filePath) > self._fileMtime:')
+ self.indent()
+ self.addChunk('self._compile(file=self._filePath, moduleName='+self._className + ')')
+ self.addChunk(
+ 'write(getattr(self, self._mainCheetahMethod_for_' + self._className +
+ ')(trans=trans))')
+ self.addStop()
+ self.dedent()
+
+ def setClassName(self, name):
+ self._className = name
+
+ def className(self):
+ return self._className
+
+ def setBaseClass(self, baseClassName):
+ self._baseClass = baseClassName
+
+ def setMainMethodName(self, methodName):
+ if methodName == self._mainMethodName:
+ return
+ ## change the name in the methodCompiler and add new reference
+ mainMethod = self._methodsIndex[self._mainMethodName]
+ mainMethod.setMethodName(methodName)
+ self._methodsIndex[methodName] = mainMethod
+
+ ## make sure that fileUpdate code still works properly:
+ chunkToChange = ('write(self.' + self._mainMethodName + '(trans=trans))')
+ chunks = mainMethod._methodBodyChunks
+ if chunkToChange in chunks:
+ for i in range(len(chunks)):
+ if chunks[i] == chunkToChange:
+ chunks[i] = ('write(self.' + methodName + '(trans=trans))')
+ ## get rid of the old reference and update self._mainMethodName
+ del self._methodsIndex[self._mainMethodName]
+ self._mainMethodName = methodName
+
+ def setMainMethodArgs(self, argsList):
+ mainMethodCompiler = self._methodsIndex[self._mainMethodName]
+ for argName, defVal in argsList:
+ mainMethodCompiler.addMethArg(argName, defVal)
+
+
+ def _spawnMethodCompiler(self, methodName, klass=None,
+ initialMethodComment=None):
+ if klass is None:
+ klass = self.methodCompilerClass
+
+ decorators = self._decoratorsForNextMethod or []
+ self._decoratorsForNextMethod = []
+ methodCompiler = klass(methodName, classCompiler=self,
+ decorators=decorators,
+ initialMethodComment=initialMethodComment)
+ self._methodsIndex[methodName] = methodCompiler
+ return methodCompiler
+
+ def _setActiveMethodCompiler(self, methodCompiler):
+ self._activeMethodsList.append(methodCompiler)
+
+ def _getActiveMethodCompiler(self):
+ return self._activeMethodsList[-1]
+
+ def _popActiveMethodCompiler(self):
+ return self._activeMethodsList.pop()
+
+ def _swallowMethodCompiler(self, methodCompiler, pos=None):
+ methodCompiler.cleanupState()
+ if pos==None:
+ self._finishedMethodsList.append( methodCompiler )
+ else:
+ self._finishedMethodsList.insert(pos, methodCompiler)
+ return methodCompiler
+
+ def startMethodDef(self, methodName, argsList, parserComment):
+ methodCompiler = self._spawnMethodCompiler(
+ methodName, initialMethodComment=parserComment)
+ self._setActiveMethodCompiler(methodCompiler)
+ for argName, defVal in argsList:
+ methodCompiler.addMethArg(argName, defVal)
+
+ def _finishedMethods(self):
+ return self._finishedMethodsList
+
+ def addDecorator(self, decoratorExpr):
+ """Set the decorator to be used with the next method in the source.
+
+ See _spawnMethodCompiler() and MethodCompiler for the details of how
+ this is used.
+ """
+ self._decoratorsForNextMethod.append(decoratorExpr)
+
+ def addClassDocString(self, line):
+ self._classDocStringLines.append( line.replace('%','%%'))
+
+ def addChunkToInit(self,chunk):
+ self._initMethChunks.append(chunk)
+
+ def addAttribute(self, attribExpr):
+ ## first test to make sure that the user hasn't used any fancy Cheetah syntax
+ # (placeholders, directives, etc.) inside the expression
+ if attribExpr.find('VFN(') != -1 or attribExpr.find('VFFSL(') != -1:
+ raise ParseError(self,
+ 'Invalid #attr directive.' +
+ ' It should only contain simple Python literals.')
+ ## now add the attribute
+ self._generatedAttribs.append(attribExpr)
+
+ def addSuper(self, argsList, parserComment=None):
+ className = self._className #self._baseClass
+ methodName = self._getActiveMethodCompiler().methodName()
+
+ argStringChunks = []
+ for arg in argsList:
+ chunk = arg[0]
+ if not arg[1] == None:
+ chunk += '=' + arg[1]
+ argStringChunks.append(chunk)
+ argString = ','.join(argStringChunks)
+
+ self.addFilteredChunk(
+ 'super(%(className)s, self).%(methodName)s(%(argString)s)'%locals())
+
+ def addErrorCatcherCall(self, codeChunk, rawCode='', lineCol=''):
+ if self._placeholderToErrorCatcherMap.has_key(rawCode):
+ methodName = self._placeholderToErrorCatcherMap[rawCode]
+ if not self.setting('outputRowColComments'):
+ self._methodsIndex[methodName].addMethDocString(
+ 'plus at line %s, col %s'%lineCol)
+ return methodName
+
+ self._errorCatcherCount += 1
+ methodName = '__errorCatcher' + str(self._errorCatcherCount)
+ self._placeholderToErrorCatcherMap[rawCode] = methodName
+
+ catcherMeth = self._spawnMethodCompiler(
+ methodName,
+ klass=MethodCompiler,
+ initialMethodComment=('## CHEETAH: Generated from ' + rawCode +
+ ' at line %s, col %s'%lineCol + '.')
+ )
+ catcherMeth.setMethodSignature('def ' + methodName +
+ '(self, localsDict={})')
+ # is this use of localsDict right?
+ catcherMeth.addChunk('try:')
+ catcherMeth.indent()
+ catcherMeth.addChunk("return eval('''" + codeChunk +
+ "''', globals(), localsDict)")
+ catcherMeth.dedent()
+ catcherMeth.addChunk('except self._CHEETAH__errorCatcher.exceptions(), e:')
+ catcherMeth.indent()
+ catcherMeth.addChunk("return self._CHEETAH__errorCatcher.warn(exc_val=e, code= " +
+ repr(codeChunk) + " , rawCode= " +
+ repr(rawCode) + " , lineCol=" + str(lineCol) +")")
+
+ catcherMeth.cleanupState()
+
+ self._swallowMethodCompiler(catcherMeth)
+ return methodName
+
+ def closeDef(self):
+ self.commitStrConst()
+ methCompiler = self._popActiveMethodCompiler()
+ self._swallowMethodCompiler(methCompiler)
+
+ def closeBlock(self):
+ self.commitStrConst()
+ methCompiler = self._popActiveMethodCompiler()
+ methodName = methCompiler.methodName()
+ if self.setting('includeBlockMarkers'):
+ endMarker = self.setting('blockMarkerEnd')
+ methCompiler.addStrConst(endMarker[0] + methodName + endMarker[1])
+ self._swallowMethodCompiler(methCompiler)
+
+ #metaData = self._blockMetaData[methodName]
+ #rawDirective = metaData['raw']
+ #lineCol = metaData['lineCol']
+
+ ## insert the code to call the block, caching if #cache directive is on
+ codeChunk = 'self.' + methodName + '(trans=trans)'
+ self.addChunk(codeChunk)
+
+ #self.appendToPrevChunk(' # generated from ' + repr(rawDirective) )
+ #if self.setting('outputRowColComments'):
+ # self.appendToPrevChunk(' at line %s, col %s' % lineCol + '.')
+
+
+ ## code wrapping methods
+
+ def classDef(self):
+ if self._classDef:
+ return self._classDef
+ else:
+ return self.wrapClassDef()
+
+ __str__ = classDef
+ __unicode__ = classDef
+
+ def wrapClassDef(self):
+ ind = self.setting('indentationStep')
+ classDefChunks = [self.classSignature(),
+ self.classDocstring(),
+ ]
+ def addMethods():
+ classDefChunks.extend([
+ ind + '#'*50,
+ ind + '## CHEETAH GENERATED METHODS',
+ '\n',
+ self.methodDefs(),
+ ])
+ def addAttributes():
+ classDefChunks.extend([
+ ind + '#'*50,
+ ind + '## CHEETAH GENERATED ATTRIBUTES',
+ '\n',
+ self.attributes(),
+ ])
+ if self.setting('outputMethodsBeforeAttributes'):
+ addMethods()
+ addAttributes()
+ else:
+ addAttributes()
+ addMethods()
+
+ classDef = '\n'.join(classDefChunks)
+ self._classDef = classDef
+ return classDef
+
+
+ def classSignature(self):
+ return "class %s(%s):" % (self.className(), self._baseClass)
+
+ def classDocstring(self):
+ if not self._classDocStringLines:
+ return ''
+ ind = self.setting('indentationStep')
+ docStr = ('%(ind)s"""\n%(ind)s' +
+ '\n%(ind)s'.join(self._classDocStringLines) +
+ '\n%(ind)s"""\n'
+ ) % {'ind':ind}
+ return docStr
+
+ def methodDefs(self):
+ methodDefs = [methGen.methodDef() for methGen in self._finishedMethods()]
+ return '\n\n'.join(methodDefs)
+
+ def attributes(self):
+ attribs = [self.setting('indentationStep') + str(attrib)
+ for attrib in self._generatedAttribs ]
+ return '\n\n'.join(attribs)
+
+class AutoClassCompiler(ClassCompiler):
+ pass
+
+##################################################
+## MODULE COMPILERS
+
+class ModuleCompiler(SettingsManager, GenUtils):
+
+ parserClass = Parser
+ classCompilerClass = AutoClassCompiler
+
+ def __init__(self, source=None, file=None,
+ moduleName='DynamicallyCompiledCheetahTemplate',
+ mainClassName=None, # string
+ mainMethodName=None, # string
+ baseclassName=None, # string
+ extraImportStatements=None, # list of strings
+ settings=None # dict
+ ):
+ SettingsManager.__init__(self)
+ if settings:
+ self.updateSettings(settings)
+ # disable useStackFrames if the C version of NameMapper isn't compiled
+ # it's painfully slow in the Python version and bites Windows users all
+ # the time:
+ if not NameMapper.C_VERSION:
+ if not sys.platform.startswith('java'):
+ warnings.warn(
+ "\nYou don't have the C version of NameMapper installed! "
+ "I'm disabling Cheetah's useStackFrames option as it is "
+ "painfully slow with the Python version of NameMapper. "
+ "You should get a copy of Cheetah with the compiled C version of NameMapper."
+ )
+ self.setSetting('useStackFrames', False)
+
+ self._compiled = False
+ self._moduleName = moduleName
+ if not mainClassName:
+ self._mainClassName = moduleName
+ else:
+ self._mainClassName = mainClassName
+ self._mainMethodNameArg = mainMethodName
+ if mainMethodName:
+ self.setSetting('mainMethodName', mainMethodName)
+ self._baseclassName = baseclassName
+
+ self._filePath = None
+ self._fileMtime = None
+
+ if source and file:
+ raise TypeError("Cannot compile from a source string AND file.")
+ elif isinstance(file, basestring): # it's a filename.
+ f = open(file) # Raises IOError.
+ source = f.read()
+ f.close()
+ self._filePath = file
+ self._fileMtime = os.path.getmtime(file)
+ elif hasattr(file, 'read'):
+ source = file.read() # Can't set filename or mtime--they're not accessible.
+ elif file:
+ raise TypeError("'file' argument must be a filename string or file-like object")
+
+ if self._filePath:
+ self._fileDirName, self._fileBaseName = os.path.split(self._filePath)
+ self._fileBaseNameRoot, self._fileBaseNameExt = os.path.splitext(self._fileBaseName)
+
+ if not isinstance(source, basestring):
+ source = unicode(source)
+ # by converting to string here we allow objects such as other Templates
+ # to be passed in
+
+ # Handle the #indent directive by converting it to other directives.
+ # (Over the long term we'll make it a real directive.)
+ if source == "":
+ warnings.warn("You supplied an empty string for the source!", )
+
+ else:
+ unicodeMatch = unicodeDirectiveRE.search(source)
+ encodingMatch = encodingDirectiveRE.match(source)
+ if unicodeMatch:
+ if encodingMatch:
+ raise ParseError(
+ self, "#encoding and #unicode are mutually exclusive! "
+ "Use one or the other.")
+ source = unicodeDirectiveRE.sub('', source)
+ if isinstance(source, str):
+ encoding = unicodeMatch.group(1) or 'ascii'
+ source = unicode(source, encoding)
+ elif encodingMatch:
+ encodings = encodingMatch.groups()
+ if len(encodings):
+ encoding = encodings[0]
+ source = source.decode(encoding)
+ else:
+ source = unicode(source)
+
+ if source.find('#indent') != -1: #@@TR: undocumented hack
+ source = indentize(source)
+
+ self._parser = self.parserClass(source, filename=self._filePath, compiler=self)
+ self._setupCompilerState()
+
+ def __getattr__(self, name):
+ """Provide one-way access to the methods and attributes of the
+ ClassCompiler, and thereby the MethodCompilers as well.
+
+ WARNING: Use .setMethods to assign the attributes of the ClassCompiler
+ from the methods of this class!!! or you will be assigning to attributes
+ of this object instead.
+ """
+ if self.__dict__.has_key(name):
+ return self.__dict__[name]
+ elif hasattr(self.__class__, name):
+ return getattr(self.__class__, name)
+ elif self._activeClassesList and hasattr(self._activeClassesList[-1], name):
+ return getattr(self._activeClassesList[-1], name)
+ else:
+ raise AttributeError, name
+
+ def _initializeSettings(self):
+ self.updateSettings(copy.deepcopy(DEFAULT_COMPILER_SETTINGS))
+
+ def _setupCompilerState(self):
+ self._activeClassesList = []
+ self._finishedClassesList = [] # listed by ordered
+ self._finishedClassIndex = {} # listed by name
+ self._moduleDef = None
+ self._moduleShBang = '#!/usr/bin/env python'
+ self._moduleEncoding = 'ascii'
+ self._moduleEncodingStr = ''
+ self._moduleHeaderLines = []
+ self._moduleDocStringLines = []
+ self._specialVars = {}
+ self._importStatements = [
+ "import sys",
+ "import os",
+ "import os.path",
+ "import __builtin__",
+ "from os.path import getmtime, exists",
+ "import time",
+ "import types",
+ "from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion",
+ "from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple",
+ "from Cheetah.Template import Template",
+ "from Cheetah.DummyTransaction import *",
+ "from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList",
+ "from Cheetah.CacheRegion import CacheRegion",
+ "import Cheetah.Filters as Filters",
+ "import Cheetah.ErrorCatchers as ErrorCatchers",
+ ]
+
+ self._importedVarNames = ['sys',
+ 'os',
+ 'os.path',
+ 'time',
+ 'types',
+ 'Template',
+ 'DummyTransaction',
+ 'NotFound',
+ 'Filters',
+ 'ErrorCatchers',
+ 'CacheRegion',
+ ]
+
+ self._moduleConstants = [
+ "VFFSL=valueFromFrameOrSearchList",
+ "VFSL=valueFromSearchList",
+ "VFN=valueForName",
+ "currentTime=time.time",
+ ]
+
+ def compile(self):
+ classCompiler = self._spawnClassCompiler(self._mainClassName)
+ if self._baseclassName:
+ classCompiler.setBaseClass(self._baseclassName)
+ self._addActiveClassCompiler(classCompiler)
+ self._parser.parse()
+ self._swallowClassCompiler(self._popActiveClassCompiler())
+ self._compiled = True
+ self._parser.cleanup()
+
+ def _spawnClassCompiler(self, className, klass=None):
+ if klass is None:
+ klass = self.classCompilerClass
+ classCompiler = klass(className,
+ moduleCompiler=self,
+ mainMethodName=self.setting('mainMethodName'),
+ fileName=self._filePath,
+ settingsManager=self,
+ )
+ return classCompiler
+
+ def _addActiveClassCompiler(self, classCompiler):
+ self._activeClassesList.append(classCompiler)
+
+ def _getActiveClassCompiler(self):
+ return self._activeClassesList[-1]
+
+ def _popActiveClassCompiler(self):
+ return self._activeClassesList.pop()
+
+ def _swallowClassCompiler(self, classCompiler):
+ classCompiler.cleanupState()
+ self._finishedClassesList.append( classCompiler )
+ self._finishedClassIndex[classCompiler.className()] = classCompiler
+ return classCompiler
+
+ def _finishedClasses(self):
+ return self._finishedClassesList
+
+ def importedVarNames(self):
+ return self._importedVarNames
+
+ def addImportedVarNames(self, varNames, raw_statement=None):
+ settings = self.settings()
+ if not varNames:
+ return
+ if self._methodBodyChunks and raw_statement and not settings.get('useLegacyImportMode'):
+ self.addChunk(raw_statement)
+ else:
+ self._importedVarNames.extend(varNames)
+
+ ## methods for adding stuff to the module and class definitions
+
+ def setBaseClass(self, baseClassName):
+ if self._mainMethodNameArg:
+ self.setMainMethodName(self._mainMethodNameArg)
+ else:
+ self.setMainMethodName(self.setting('mainMethodNameForSubclasses'))
+
+ if self.setting('handlerForExtendsDirective'):
+ handler = self.setting('handlerForExtendsDirective')
+ baseClassName = handler(compiler=self, baseClassName=baseClassName)
+ self._getActiveClassCompiler().setBaseClass(baseClassName)
+ elif (not self.setting('autoImportForExtendsDirective')
+ or baseClassName=='object' or baseClassName in self.importedVarNames()):
+ self._getActiveClassCompiler().setBaseClass(baseClassName)
+ # no need to import
+ else:
+ ##################################################
+ ## If the #extends directive contains a classname or modulename that isn't
+ # in self.importedVarNames() already, we assume that we need to add
+ # an implied 'from ModName import ClassName' where ModName == ClassName.
+ # - This is the case in WebKit servlet modules.
+ # - We also assume that the final . separates the classname from the
+ # module name. This might break if people do something really fancy
+ # with their dots and namespaces.
+ chunks = baseClassName.split('.')
+ if len(chunks)==1:
+ self._getActiveClassCompiler().setBaseClass(baseClassName)
+ if baseClassName not in self.importedVarNames():
+ modName = baseClassName
+ # we assume the class name to be the module name
+ # and that it's not a builtin:
+ importStatement = "from %s import %s" % (modName, baseClassName)
+ self.addImportStatement(importStatement)
+ self.addImportedVarNames( [baseClassName,] )
+ else:
+ needToAddImport = True
+ modName = chunks[0]
+ #print chunks, ':', self.importedVarNames()
+ for chunk in chunks[1:-1]:
+ if modName in self.importedVarNames():
+ needToAddImport = False
+ finalBaseClassName = baseClassName.replace(modName+'.', '')
+ self._getActiveClassCompiler().setBaseClass(finalBaseClassName)
+ break
+ else:
+ modName += '.'+chunk
+ if needToAddImport:
+ modName, finalClassName = '.'.join(chunks[:-1]), chunks[-1]
+ #if finalClassName != chunks[:-1][-1]:
+ if finalClassName != chunks[-2]:
+ # we assume the class name to be the module name
+ modName = '.'.join(chunks)
+ self._getActiveClassCompiler().setBaseClass(finalClassName)
+ importStatement = "from %s import %s" % (modName, finalClassName)
+ self.addImportStatement(importStatement)
+ self.addImportedVarNames( [finalClassName,] )
+
+ def setCompilerSetting(self, key, valueExpr):
+ self.setSetting(key, eval(valueExpr) )
+ self._parser.configureParser()
+
+ def setCompilerSettings(self, keywords, settingsStr):
+ KWs = keywords
+ merge = True
+ if 'nomerge' in KWs:
+ merge = False
+
+ if 'reset' in KWs:
+ # @@TR: this is actually caught by the parser at the moment.
+ # subject to change in the future
+ self._initializeSettings()
+ self._parser.configureParser()
+ return
+ elif 'python' in KWs:
+ settingsReader = self.updateSettingsFromPySrcStr
+ # this comes from SettingsManager
+ else:
+ # this comes from SettingsManager
+ settingsReader = self.updateSettingsFromConfigStr
+
+ settingsReader(settingsStr)
+ self._parser.configureParser()
+
+ def setShBang(self, shBang):
+ self._moduleShBang = shBang
+
+ def setModuleEncoding(self, encoding):
+ self._moduleEncoding = encoding
+
+ def getModuleEncoding(self):
+ return self._moduleEncoding
+
+ def addModuleHeader(self, line):
+ """Adds a header comment to the top of the generated module.
+ """
+ self._moduleHeaderLines.append(line)
+
+ def addModuleDocString(self, line):
+ """Adds a line to the generated module docstring.
+ """
+ self._moduleDocStringLines.append(line)
+
+ def addModuleGlobal(self, line):
+ """Adds a line of global module code. It is inserted after the import
+ statements and Cheetah default module constants.
+ """
+ self._moduleConstants.append(line)
+
+ def addSpecialVar(self, basename, contents, includeUnderscores=True):
+ """Adds module __specialConstant__ to the module globals.
+ """
+ name = includeUnderscores and '__'+basename+'__' or basename
+ self._specialVars[name] = contents.strip()
+
+ def addImportStatement(self, impStatement):
+ settings = self.settings()
+ if not self._methodBodyChunks or settings.get('useLegacyImportMode'):
+ # In the case where we are importing inline in the middle of a source block
+ # we don't want to inadvertantly import the module at the top of the file either
+ self._importStatements.append(impStatement)
+
+ #@@TR 2005-01-01: there's almost certainly a cleaner way to do this!
+ importVarNames = impStatement[impStatement.find('import') + len('import'):].split(',')
+ importVarNames = [var.split()[-1] for var in importVarNames] # handles aliases
+ importVarNames = [var for var in importVarNames if not var == '*']
+ self.addImportedVarNames(importVarNames, raw_statement=impStatement) #used by #extend for auto-imports
+
+ def addAttribute(self, attribName, expr):
+ self._getActiveClassCompiler().addAttribute(attribName + ' =' + expr)
+
+ def addComment(self, comm):
+ if re.match(r'#+$',comm): # skip bar comments
+ return
+
+ specialVarMatch = specialVarRE.match(comm)
+ if specialVarMatch:
+ # @@TR: this is a bit hackish and is being replaced with
+ # #set module varName = ...
+ return self.addSpecialVar(specialVarMatch.group(1),
+ comm[specialVarMatch.end():])
+ elif comm.startswith('doc:'):
+ addLine = self.addMethDocString
+ comm = comm[len('doc:'):].strip()
+ elif comm.startswith('doc-method:'):
+ addLine = self.addMethDocString
+ comm = comm[len('doc-method:'):].strip()
+ elif comm.startswith('doc-module:'):
+ addLine = self.addModuleDocString
+ comm = comm[len('doc-module:'):].strip()
+ elif comm.startswith('doc-class:'):
+ addLine = self.addClassDocString
+ comm = comm[len('doc-class:'):].strip()
+ elif comm.startswith('header:'):
+ addLine = self.addModuleHeader
+ comm = comm[len('header:'):].strip()
+ else:
+ addLine = self.addMethComment
+
+ for line in comm.splitlines():
+ addLine(line)
+
+ ## methods for module code wrapping
+
+ def getModuleCode(self):
+ if not self._compiled:
+ self.compile()
+ if self._moduleDef:
+ return self._moduleDef
+ else:
+ return self.wrapModuleDef()
+
+ __str__ = getModuleCode
+
+ def wrapModuleDef(self):
+ self.addSpecialVar('CHEETAH_docstring', self.setting('defDocStrMsg'))
+ self.addModuleGlobal('__CHEETAH_version__ = %r'%Version)
+ self.addModuleGlobal('__CHEETAH_versionTuple__ = %r'%(VersionTuple,))
+ if self.setting('addTimestampsToCompilerOutput'):
+ self.addModuleGlobal('__CHEETAH_genTime__ = %r'%time.time())
+ self.addModuleGlobal('__CHEETAH_genTimestamp__ = %r'%self.timestamp())
+ if self._filePath:
+ timestamp = self.timestamp(self._fileMtime)
+ self.addModuleGlobal('__CHEETAH_src__ = %r'%self._filePath)
+ self.addModuleGlobal('__CHEETAH_srcLastModified__ = %r'%timestamp)
+ else:
+ self.addModuleGlobal('__CHEETAH_src__ = None')
+ self.addModuleGlobal('__CHEETAH_srcLastModified__ = None')
+
+ moduleDef = """%(header)s
+%(docstring)s
+
+##################################################
+## DEPENDENCIES
+%(imports)s
+
+##################################################
+## MODULE CONSTANTS
+%(constants)s
+%(specialVars)s
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+ raise AssertionError(
+ 'This template was compiled with Cheetah version'
+ ' %%s. Templates compiled before version %%s must be recompiled.'%%(
+ __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+%(classes)s
+
+## END CLASS DEFINITION
+
+if not hasattr(%(mainClassName)s, '_initCheetahAttributes'):
+ templateAPIClass = getattr(%(mainClassName)s, '_CHEETAH_templateClass', Template)
+ templateAPIClass._addCheetahPlumbingCodeToClass(%(mainClassName)s)
+
+%(footer)s
+""" % {'header':self.moduleHeader(),
+ 'docstring':self.moduleDocstring(),
+ 'specialVars':self.specialVars(),
+ 'imports':self.importStatements(),
+ 'constants':self.moduleConstants(),
+ 'classes':self.classDefs(),
+ 'footer':self.moduleFooter(),
+ 'mainClassName':self._mainClassName,
+ }
+
+ self._moduleDef = moduleDef
+ return moduleDef
+
+ def timestamp(self, theTime=None):
+ if not theTime:
+ theTime = time.time()
+ return time.asctime(time.localtime(theTime))
+
+ def moduleHeader(self):
+ header = self._moduleShBang + '\n'
+ header += self._moduleEncodingStr + '\n'
+ if self._moduleHeaderLines:
+ offSet = self.setting('commentOffset')
+
+ header += (
+ '#' + ' '*offSet +
+ ('\n#'+ ' '*offSet).join(self._moduleHeaderLines) + '\n')
+
+ return header
+
+ def moduleDocstring(self):
+ if not self._moduleDocStringLines:
+ return ''
+
+ return ('"""' +
+ '\n'.join(self._moduleDocStringLines) +
+ '\n"""\n')
+
+ def specialVars(self):
+ chunks = []
+ theVars = self._specialVars
+ keys = theVars.keys()
+ keys.sort()
+ for key in keys:
+ chunks.append(key + ' = ' + repr(theVars[key]) )
+ return '\n'.join(chunks)
+
+ def importStatements(self):
+ return '\n'.join(self._importStatements)
+
+ def moduleConstants(self):
+ return '\n'.join(self._moduleConstants)
+
+ def classDefs(self):
+ classDefs = [klass.classDef() for klass in self._finishedClasses()]
+ return '\n\n'.join(classDefs)
+
+ def moduleFooter(self):
+ return """
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+ from Cheetah.TemplateCmdLineIface import CmdLineIface
+ CmdLineIface(templateObj=%(className)s()).run()
+
+""" % {'className':self._mainClassName}
+
+
+##################################################
+## Make Compiler an alias for ModuleCompiler
+
+Compiler = ModuleCompiler
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Django.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Django.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Django.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+import Cheetah.Template
+
+def render(template_file, **kwargs):
+ '''
+ Cheetah.Django.render() takes the template filename
+ (the filename should be a file in your Django
+ TEMPLATE_DIRS)
+
+ Any additional keyword arguments are passed into the
+ template are propogated into the template's searchList
+ '''
+ import django.http
+ import django.template.loader
+ source, loader = django.template.loader.find_template_source(template_file)
+ t = Cheetah.Template.Template(source, searchList=[kwargs])
+ return django.http.HttpResponse(t.__str__())
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/DummyTransaction.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/DummyTransaction.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/DummyTransaction.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+'''
+Provides dummy Transaction and Response classes is used by Cheetah in place
+of real Webware transactions when the Template obj is not used directly as a
+Webware servlet.
+
+Warning: This may be deprecated in the future, please do not rely on any
+specific DummyTransaction or DummyResponse behavior
+'''
+
+import types
+
+class DummyResponseFailure(Exception):
+ pass
+
+class DummyResponse(object):
+ '''
+ A dummy Response class is used by Cheetah in place of real Webware
+ Response objects when the Template obj is not used directly as a Webware
+ servlet
+ '''
+ def __init__(self):
+ self._outputChunks = []
+
+ def flush(self):
+ pass
+
+ def write(self, value):
+ self._outputChunks.append(value)
+
+ def writeln(self, txt):
+ write(txt)
+ write('\n')
+
+ def getvalue(self, outputChunks=None):
+ chunks = outputChunks or self._outputChunks
+ try:
+ return ''.join(chunks)
+ except UnicodeDecodeError, ex:
+ nonunicode = [c for c in chunks if not isinstance(c, unicode)]
+ raise DummyResponseFailure('''Looks like you're trying to mix encoded strings with Unicode strings
+ (most likely utf-8 encoded ones)
+
+ This can happen if you're using the `EncodeUnicode` filter, or if you're manually
+ encoding strings as utf-8 before passing them in on the searchList (possible offenders:
+ %s)
+ (%s)''' % (nonunicode, ex))
+
+
+ def writelines(self, *lines):
+ ## not used
+ [self.writeln(ln) for ln in lines]
+
+
+class DummyTransaction(object):
+ '''
+ A dummy Transaction class is used by Cheetah in place of real Webware
+ transactions when the Template obj is not used directly as a Webware
+ servlet.
+
+ It only provides a response object and method. All other methods and
+ attributes make no sense in this context.
+ '''
+ def __init__(self, *args, **kwargs):
+ self._response = None
+
+ def response(self, resp=None):
+ if self._response is None:
+ self._response = resp or DummyResponse()
+ return self._response
+
+
+class TransformerResponse(DummyResponse):
+ def __init__(self, *args, **kwargs):
+ super(TransformerResponse, self).__init__(*args, **kwargs)
+ self._filter = None
+
+ def getvalue(self, **kwargs):
+ output = super(TransformerResponse, self).getvalue(**kwargs)
+ if self._filter:
+ _filter = self._filter
+ if isinstance(_filter, types.TypeType):
+ _filter = _filter()
+ return _filter.filter(output)
+ return output
+
+
+class TransformerTransaction(object):
+ def __init__(self, *args, **kwargs):
+ self._response = None
+ def response(self):
+ if self._response:
+ return self._response
+ return TransformerResponse()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ErrorCatchers.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ErrorCatchers.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ErrorCatchers.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# $Id: ErrorCatchers.py,v 1.7 2005/01/03 19:59:07 tavis_rudd Exp $
+"""ErrorCatcher class for Cheetah Templates
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+Version: $Revision: 1.7 $
+Start Date: 2001/08/01
+Last Revision Date: $Date: 2005/01/03 19:59:07 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.7 $"[11:-2]
+
+import time
+from Cheetah.NameMapper import NotFound
+
+class Error(Exception):
+ pass
+
+class ErrorCatcher:
+ _exceptionsToCatch = (NotFound,)
+
+ def __init__(self, templateObj):
+ pass
+
+ def exceptions(self):
+ return self._exceptionsToCatch
+
+ def warn(self, exc_val, code, rawCode, lineCol):
+ return rawCode
+## make an alias
+Echo = ErrorCatcher
+
+class BigEcho(ErrorCatcher):
+ def warn(self, exc_val, code, rawCode, lineCol):
+ return "="*15 + "<" + rawCode + " could not be found>" + "="*15
+
+class KeyError(ErrorCatcher):
+ def warn(self, exc_val, code, rawCode, lineCol):
+ raise KeyError("no '%s' in this Template Object's Search List" % rawCode)
+
+class ListErrors(ErrorCatcher):
+ """Accumulate a list of errors."""
+ _timeFormat = "%c"
+
+ def __init__(self, templateObj):
+ ErrorCatcher.__init__(self, templateObj)
+ self._errors = []
+
+ def warn(self, exc_val, code, rawCode, lineCol):
+ dict = locals().copy()
+ del dict['self']
+ dict['time'] = time.strftime(self._timeFormat,
+ time.localtime(time.time()))
+ self._errors.append(dict)
+ return rawCode
+
+ def listErrors(self):
+ """Return the list of errors."""
+ return self._errors
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/FileUtils.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/FileUtils.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/FileUtils.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,374 @@
+#!/usr/bin/env python
+# $Id: FileUtils.py,v 1.12 2005/11/02 22:26:07 tavis_rudd Exp $
+"""File utitilies for Python:
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.12 $
+Start Date: 2001/09/26
+Last Revision Date: $Date: 2005/11/02 22:26:07 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.12 $"[11:-2]
+
+
+from glob import glob
+import os
+from os import listdir
+import os.path
+import re
+from types import StringType
+from tempfile import mktemp
+
+def _escapeRegexChars(txt,
+ escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')):
+ return escapeRE.sub(r'\\\1' , txt)
+
+def findFiles(*args, **kw):
+ """Recursively find all the files matching a glob pattern.
+
+ This function is a wrapper around the FileFinder class. See its docstring
+ for details about the accepted arguments, etc."""
+
+ return FileFinder(*args, **kw).files()
+
+def replaceStrInFiles(files, theStr, repl):
+
+ """Replace all instances of 'theStr' with 'repl' for each file in the 'files'
+ list. Returns a dictionary with data about the matches found.
+
+ This is like string.replace() on a multi-file basis.
+
+ This function is a wrapper around the FindAndReplace class. See its
+ docstring for more details."""
+
+ pattern = _escapeRegexChars(theStr)
+ return FindAndReplace(files, pattern, repl).results()
+
+def replaceRegexInFiles(files, pattern, repl):
+
+ """Replace all instances of regex 'pattern' with 'repl' for each file in the
+ 'files' list. Returns a dictionary with data about the matches found.
+
+ This is like re.sub on a multi-file basis.
+
+ This function is a wrapper around the FindAndReplace class. See its
+ docstring for more details."""
+
+ return FindAndReplace(files, pattern, repl).results()
+
+
+##################################################
+## CLASSES
+
+class FileFinder:
+
+ """Traverses a directory tree and finds all files in it that match one of
+ the specified glob patterns."""
+
+ def __init__(self, rootPath,
+ globPatterns=('*',),
+ ignoreBasenames=('CVS','.svn'),
+ ignoreDirs=(),
+ ):
+
+ self._rootPath = rootPath
+ self._globPatterns = globPatterns
+ self._ignoreBasenames = ignoreBasenames
+ self._ignoreDirs = ignoreDirs
+ self._files = []
+
+ self.walkDirTree(rootPath)
+
+ def walkDirTree(self, dir='.',
+
+ listdir=os.listdir,
+ isdir=os.path.isdir,
+ join=os.path.join,
+ ):
+
+ """Recursively walk through a directory tree and find matching files."""
+ processDir = self.processDir
+ filterDir = self.filterDir
+
+ pendingDirs = [dir]
+ addDir = pendingDirs.append
+ getDir = pendingDirs.pop
+
+ while pendingDirs:
+ dir = getDir()
+ ## process this dir
+ processDir(dir)
+
+ ## and add sub-dirs
+ for baseName in listdir(dir):
+ fullPath = join(dir, baseName)
+ if isdir(fullPath):
+ if filterDir(baseName, fullPath):
+ addDir( fullPath )
+
+ def filterDir(self, baseName, fullPath):
+
+ """A hook for filtering out certain dirs. """
+
+ return not (baseName in self._ignoreBasenames or
+ fullPath in self._ignoreDirs)
+
+ def processDir(self, dir, glob=glob):
+ extend = self._files.extend
+ for pattern in self._globPatterns:
+ extend( glob(os.path.join(dir, pattern)) )
+
+ def files(self):
+ return self._files
+
+class _GenSubberFunc:
+
+ """Converts a 'sub' string in the form that one feeds to re.sub (backrefs,
+ groups, etc.) into a function that can be used to do the substitutions in
+ the FindAndReplace class."""
+
+ backrefRE = re.compile(r'\\([1-9][0-9]*)')
+ groupRE = re.compile(r'\\g<([a-zA-Z_][a-zA-Z_]*)>')
+
+ def __init__(self, replaceStr):
+ self._src = replaceStr
+ self._pos = 0
+ self._codeChunks = []
+ self.parse()
+
+ def src(self):
+ return self._src
+
+ def pos(self):
+ return self._pos
+
+ def setPos(self, pos):
+ self._pos = pos
+
+ def atEnd(self):
+ return self._pos >= len(self._src)
+
+ def advance(self, offset=1):
+ self._pos += offset
+
+ def readTo(self, to, start=None):
+ if start == None:
+ start = self._pos
+ self._pos = to
+ if self.atEnd():
+ return self._src[start:]
+ else:
+ return self._src[start:to]
+
+ ## match and get methods
+
+ def matchBackref(self):
+ return self.backrefRE.match(self.src(), self.pos())
+
+ def getBackref(self):
+ m = self.matchBackref()
+ self.setPos(m.end())
+ return m.group(1)
+
+ def matchGroup(self):
+ return self.groupRE.match(self.src(), self.pos())
+
+ def getGroup(self):
+ m = self.matchGroup()
+ self.setPos(m.end())
+ return m.group(1)
+
+ ## main parse loop and the eat methods
+
+ def parse(self):
+ while not self.atEnd():
+ if self.matchBackref():
+ self.eatBackref()
+ elif self.matchGroup():
+ self.eatGroup()
+ else:
+ self.eatStrConst()
+
+ def eatStrConst(self):
+ startPos = self.pos()
+ while not self.atEnd():
+ if self.matchBackref() or self.matchGroup():
+ break
+ else:
+ self.advance()
+ strConst = self.readTo(self.pos(), start=startPos)
+ self.addChunk(repr(strConst))
+
+ def eatBackref(self):
+ self.addChunk( 'm.group(' + self.getBackref() + ')' )
+
+ def eatGroup(self):
+ self.addChunk( 'm.group("' + self.getGroup() + '")' )
+
+ def addChunk(self, chunk):
+ self._codeChunks.append(chunk)
+
+ ## code wrapping methods
+
+ def codeBody(self):
+ return ', '.join(self._codeChunks)
+
+ def code(self):
+ return "def subber(m):\n\treturn ''.join([%s])\n" % (self.codeBody())
+
+ def subberFunc(self):
+ exec self.code()
+ return subber
+
+
+class FindAndReplace:
+
+ """Find and replace all instances of 'patternOrRE' with 'replacement' for
+ each file in the 'files' list. This is a multi-file version of re.sub().
+
+ 'patternOrRE' can be a raw regex pattern or
+ a regex object as generated by the re module. 'replacement' can be any
+ string that would work with patternOrRE.sub(replacement, fileContents).
+ """
+
+ def __init__(self, files, patternOrRE, replacement,
+ recordResults=True):
+
+
+ if type(patternOrRE) == StringType:
+ self._regex = re.compile(patternOrRE)
+ else:
+ self._regex = patternOrRE
+ if type(replacement) == StringType:
+ self._subber = _GenSubberFunc(replacement).subberFunc()
+ else:
+ self._subber = replacement
+
+ self._pattern = pattern = self._regex.pattern
+ self._files = files
+ self._results = {}
+ self._recordResults = recordResults
+
+ ## see if we should use pgrep to do the file matching
+ self._usePgrep = False
+ if (os.popen3('pgrep')[2].read()).startswith('Usage:'):
+ ## now check to make sure pgrep understands the pattern
+ tmpFile = mktemp()
+ open(tmpFile, 'w').write('#')
+ if not (os.popen3('pgrep "' + pattern + '" ' + tmpFile)[2].read()):
+ # it didn't print an error msg so we're ok
+ self._usePgrep = True
+ os.remove(tmpFile)
+
+ self._run()
+
+ def results(self):
+ return self._results
+
+ def _run(self):
+ regex = self._regex
+ subber = self._subDispatcher
+ usePgrep = self._usePgrep
+ pattern = self._pattern
+ for file in self._files:
+ if not os.path.isfile(file):
+ continue # skip dirs etc.
+
+ self._currFile = file
+ found = False
+ if locals().has_key('orig'):
+ del orig
+ if self._usePgrep:
+ if os.popen('pgrep "' + pattern + '" ' + file ).read():
+ found = True
+ else:
+ orig = open(file).read()
+ if regex.search(orig):
+ found = True
+ if found:
+ if not locals().has_key('orig'):
+ orig = open(file).read()
+ new = regex.sub(subber, orig)
+ open(file, 'w').write(new)
+
+ def _subDispatcher(self, match):
+ if self._recordResults:
+ if not self._results.has_key(self._currFile):
+ res = self._results[self._currFile] = {}
+ res['count'] = 0
+ res['matches'] = []
+ else:
+ res = self._results[self._currFile]
+ res['count'] += 1
+ res['matches'].append({'contents':match.group(),
+ 'start':match.start(),
+ 'end':match.end(),
+ }
+ )
+ return self._subber(match)
+
+
+class SourceFileStats:
+
+ """
+ """
+
+ _fileStats = None
+
+ def __init__(self, files):
+ self._fileStats = stats = {}
+ for file in files:
+ stats[file] = self.getFileStats(file)
+
+ def rawStats(self):
+ return self._fileStats
+
+ def summary(self):
+ codeLines = 0
+ blankLines = 0
+ commentLines = 0
+ totalLines = 0
+ for fileStats in self.rawStats().values():
+ codeLines += fileStats['codeLines']
+ blankLines += fileStats['blankLines']
+ commentLines += fileStats['commentLines']
+ totalLines += fileStats['totalLines']
+
+ stats = {'codeLines':codeLines,
+ 'blankLines':blankLines,
+ 'commentLines':commentLines,
+ 'totalLines':totalLines,
+ }
+ return stats
+
+ def printStats(self):
+ pass
+
+ def getFileStats(self, fileName):
+ codeLines = 0
+ blankLines = 0
+ commentLines = 0
+ commentLineRe = re.compile(r'\s#.*$')
+ blankLineRe = re.compile('\s$')
+ lines = open(fileName).read().splitlines()
+ totalLines = len(lines)
+
+ for line in lines:
+ if commentLineRe.match(line):
+ commentLines += 1
+ elif blankLineRe.match(line):
+ blankLines += 1
+ else:
+ codeLines += 1
+
+ stats = {'codeLines':codeLines,
+ 'blankLines':blankLines,
+ 'commentLines':commentLines,
+ 'totalLines':totalLines,
+ }
+
+ return stats
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Filters.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Filters.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Filters.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+'''
+ Filters for the #filter directive as well as #transform
+
+ #filter results in output filters Cheetah's $placeholders .
+ #transform results in a filter on the entirety of the output
+'''
+import sys
+import Cheetah.contrib
+
+# Additional entities WebSafe knows how to transform. No need to include
+# '<', '>' or '&' since those will have been done already.
+webSafeEntities = {' ': ' ', '"': '"'}
+
+class Filter(object):
+ """A baseclass for the Cheetah Filters."""
+
+ def __init__(self, template=None):
+ """Setup a reference to the template that is using the filter instance.
+ This reference isn't used by any of the standard filters, but is
+ available to Filter subclasses, should they need it.
+
+ Subclasses should call this method.
+ """
+ self.template = template
+
+ def filter(self, val,
+ #encoding='utf8',
+ encoding=None,
+ str=str,
+ **kw):
+ """Pass Unicode strings through unmolested, unless an encoding is specified.
+ """
+ if isinstance(val, unicode):
+ if encoding:
+ filtered = val.encode(encoding)
+ else:
+ filtered = val
+ elif val is None:
+ filtered = ''
+ else:
+ try:
+ filtered = str(val)
+ except UnicodeEncodeError:
+ filtered = unicode(val)
+ return filtered
+
+RawOrEncodedUnicode = Filter
+
+
+class EncodeUnicode(Filter):
+ def filter(self, val,
+ encoding='utf8',
+ str=str,
+ **kw):
+ """Encode Unicode strings, by default in UTF-8.
+
+ >>> import Cheetah.Template
+ >>> t = Cheetah.Template.Template('''
+ ... $myvar
+ ... ${myvar, encoding='utf16'}
+ ... ''', searchList=[{'myvar': u'Asni\xe8res'}],
+ ... filter='EncodeUnicode')
+ >>> print t
+ """
+ if isinstance(val, unicode):
+ return val.encode(encoding)
+ if val is None:
+ return ''
+ return str(val)
+
+
+class Markdown(EncodeUnicode):
+ '''
+ Markdown will change regular strings to Markdown
+ (http://daringfireball.net/projects/markdown/)
+
+ Such that:
+ My Header
+ =========
+ Becaomes:
+ <h1>My Header</h1>
+
+ and so on.
+
+ Markdown is meant to be used with the #transform
+ tag, as it's usefulness with #filter is marginal at
+ best
+ '''
+ def filter(self, value, **kwargs):
+ # This is a bit of a hack to allow outright embedding of the markdown module
+ try:
+ markdown_path = '/'.join(Cheetah.contrib.__file__.split('/')[:-1])
+ sys.path.append(markdown_path)
+ from Cheetah.contrib import markdown
+ sys.path.pop()
+ except:
+ print '>>> Exception raised importing the "markdown" module'
+ print '>>> Are you sure you have the ElementTree module installed?'
+ print ' http://effbot.org/downloads/#elementtree'
+ raise
+
+ encoded = super(Markdown, self).filter(value, **kwargs)
+ return markdown.markdown(encoded)
+
+class CodeHighlighter(EncodeUnicode):
+ '''
+ The CodeHighlighter filter depends on the "pygments" module which you can
+ download and install from: http://pygments.org
+
+ What the CodeHighlighter assumes the string that it's receiving is source
+ code and uses pygments.lexers.guess_lexer() to try to guess which parser
+ to use when highlighting it.
+
+ CodeHighlighter will return the HTML and CSS to render the code block, syntax
+ highlighted, in a browser
+
+ NOTE: I had an issue installing pygments on Linux/amd64/Python 2.6 dealing with
+ importing of pygments.lexers, I was able to correct the failure by adding:
+ raise ImportError
+ to line 39 of pygments/plugin.py (since importing pkg_resources was causing issues)
+ '''
+ def filter(self, source, **kwargs):
+ encoded = super(CodeHighlighter, self).filter(source, **kwargs)
+ try:
+ from pygments import highlight
+ from pygments import lexers
+ from pygments import formatters
+ except ImportError, ex:
+ print '<%s> - Failed to import pygments! (%s)' % (self.__class__.__name__, ex)
+ print '-- You may need to install it from: http://pygments.org'
+ return encoded
+
+ lexer = None
+ try:
+ lexer = lexers.guess_lexer(source)
+ except lexers.ClassNotFound:
+ lexer = lexers.PythonLexer()
+
+ formatter = formatters.HtmlFormatter(cssclass='code_highlighter')
+ encoded = highlight(encoded, lexer, formatter)
+ css = formatter.get_style_defs('.code_highlighter')
+ return '''<style type="text/css"><!--
+ %(css)s
+ --></style>%(source)s''' % {'css' : css, 'source' : encoded}
+
+
+
+class MaxLen(Filter):
+ def filter(self, val, **kw):
+ """Replace None with '' and cut off at maxlen."""
+
+ output = super(MaxLen, self).filter(val, **kw)
+ if kw.has_key('maxlen') and len(output) > kw['maxlen']:
+ return output[:kw['maxlen']]
+ return output
+
+class WebSafe(Filter):
+ """Escape HTML entities in $placeholders.
+ """
+ def filter(self, val, **kw):
+ s = super(WebSafe, self).filter(val, **kw)
+ # These substitutions are copied from cgi.escape().
+ s = s.replace("&", "&") # Must be done first!
+ s = s.replace("<", "<")
+ s = s.replace(">", ">")
+ # Process the additional transformations if any.
+ if kw.has_key('also'):
+ also = kw['also']
+ entities = webSafeEntities # Global variable.
+ for k in also:
+ if k in entities:
+ v = entities[k]
+ else:
+ v = "&#%s;" % ord(k)
+ s = s.replace(k, v)
+ return s
+
+
+class Strip(Filter):
+ """Strip leading/trailing whitespace but preserve newlines.
+
+ This filter goes through the value line by line, removing leading and
+ trailing whitespace on each line. It does not strip newlines, so every
+ input line corresponds to one output line, with its trailing newline intact.
+
+ We do not use val.split('\n') because that would squeeze out consecutive
+ blank lines. Instead, we search for each newline individually. This
+ makes us unable to use the fast C .split method, but it makes the filter
+ much more widely useful.
+
+ This filter is intended to be usable both with the #filter directive and
+ with the proposed #sed directive (which has not been ratified yet.)
+ """
+ def filter(self, val, **kw):
+ s = super(Strip, self).filter(val, **kw)
+ result = []
+ start = 0 # The current line will be s[start:end].
+ while 1: # Loop through each line.
+ end = s.find('\n', start) # Find next newline.
+ if end == -1: # If no more newlines.
+ break
+ chunk = s[start:end].strip()
+ result.append(chunk)
+ result.append('\n')
+ start = end + 1
+ # Write the unfinished portion after the last newline, if any.
+ chunk = s[start:].strip()
+ result.append(chunk)
+ return "".join(result)
+
+class StripSqueeze(Filter):
+ """Canonicalizes every chunk of whitespace to a single space.
+
+ Strips leading/trailing whitespace. Removes all newlines, so multi-line
+ input is joined into one ling line with NO trailing newline.
+ """
+ def filter(self, val, **kw):
+ s = super(StripSqueeze, self).filter(val, **kw)
+ s = s.split()
+ return " ".join(s)
+
+##################################################
+## MAIN ROUTINE -- testing
+
+def test():
+ s1 = "abc <=> &"
+ s2 = " asdf \n\t 1 2 3\n"
+ print "WebSafe INPUT:", `s1`
+ print " WebSafe:", `WebSafe().filter(s1)`
+
+ print
+ print " Strip INPUT:", `s2`
+ print " Strip:", `Strip().filter(s2)`
+ print "StripSqueeze:", `StripSqueeze().filter(s2)`
+
+ print "Unicode:", `EncodeUnicode().filter(u'aoeu12345\u1234')`
+
+if __name__ == "__main__": test()
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportHooks.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportHooks.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportHooks.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+# $Id: ImportHooks.py,v 1.27 2007/11/16 18:28:47 tavis_rudd Exp $
+
+"""Provides some import hooks to allow Cheetah's .tmpl files to be imported
+directly like Python .py modules.
+
+To use these:
+ import Cheetah.ImportHooks
+ Cheetah.ImportHooks.install()
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.27 $
+Start Date: 2001/03/30
+Last Revision Date: $Date: 2007/11/16 18:28:47 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.27 $"[11:-2]
+
+import sys
+import os.path
+import types
+import __builtin__
+import new
+import imp
+from threading import RLock
+import string
+import traceback
+from Cheetah import ImportManager
+from Cheetah.ImportManager import DirOwner
+from Cheetah.Compiler import Compiler
+from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName
+
+_installed = False
+
+##################################################
+## HELPER FUNCS
+
+_cacheDir = []
+def setCacheDir(cacheDir):
+ global _cacheDir
+ _cacheDir.append(cacheDir)
+
+##################################################
+## CLASSES
+
+class CheetahDirOwner(DirOwner):
+ _lock = RLock()
+ _acquireLock = _lock.acquire
+ _releaseLock = _lock.release
+
+ templateFileExtensions = ('.tmpl',)
+
+ def getmod(self, name):
+ self._acquireLock()
+ try:
+ mod = DirOwner.getmod(self, name)
+ if mod:
+ return mod
+
+ for ext in self.templateFileExtensions:
+ tmplPath = os.path.join(self.path, name + ext)
+ if os.path.exists(tmplPath):
+ try:
+ return self._compile(name, tmplPath)
+ except:
+ # @@TR: log the error
+ exc_txt = traceback.format_exc()
+ exc_txt =' '+(' \n'.join(exc_txt.splitlines()))
+ raise ImportError(
+ 'Error while compiling Cheetah module'
+ ' %(name)s, original traceback follows:\n%(exc_txt)s'%locals())
+ ##
+ return None
+
+ finally:
+ self._releaseLock()
+
+ def _compile(self, name, tmplPath):
+ ## @@ consider adding an ImportError raiser here
+ code = str(Compiler(file=tmplPath, moduleName=name,
+ mainClassName=name))
+ if _cacheDir:
+ __file__ = os.path.join(_cacheDir[0],
+ convertTmplPathToModuleName(tmplPath)) + '.py'
+ try:
+ open(__file__, 'w').write(code)
+ except OSError:
+ ## @@ TR: need to add some error code here
+ traceback.print_exc(file=sys.stderr)
+ __file__ = tmplPath
+ else:
+ __file__ = tmplPath
+ co = compile(code+'\n', __file__, 'exec')
+
+ mod = imp.new_module(name)
+ mod.__file__ = co.co_filename
+ if _cacheDir:
+ mod.__orig_file__ = tmplPath # @@TR: this is used in the WebKit
+ # filemonitoring code
+ mod.__co__ = co
+ return mod
+
+
+##################################################
+## FUNCTIONS
+
+def install(templateFileExtensions=('.tmpl',)):
+ """Install the Cheetah Import Hooks"""
+
+ global _installed
+ if not _installed:
+ CheetahDirOwner.templateFileExtensions = templateFileExtensions
+ import __builtin__
+ if type(__builtin__.__import__) == types.BuiltinFunctionType:
+ global __oldimport__
+ __oldimport__ = __builtin__.__import__
+ ImportManager._globalOwnerTypes.insert(0, CheetahDirOwner)
+ #ImportManager._globalOwnerTypes.append(CheetahDirOwner)
+ global _manager
+ _manager=ImportManager.ImportManager()
+ _manager.setThreaded()
+ _manager.install()
+
+def uninstall():
+ """Uninstall the Cheetah Import Hooks"""
+ global _installed
+ if not _installed:
+ import __builtin__
+ if type(__builtin__.__import__) == types.MethodType:
+ __builtin__.__import__ = __oldimport__
+ global _manager
+ del _manager
+
+if __name__ == '__main__':
+ install()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportManager.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportManager.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/ImportManager.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,566 @@
+#!/usr/bin/env python
+# $Id: ImportManager.py,v 1.6 2007/04/03 01:56:24 tavis_rudd Exp $
+
+"""Provides an emulator/replacement for Python's standard import system.
+
+@@TR: Be warned that Import Hooks are in the deepest, darkest corner of Python's
+jungle. If you need to start hacking with this, be prepared to get lost for a
+while. Also note, this module predates the newstyle import hooks in Python 2.3
+http://www.python.org/peps/pep-0302.html.
+
+
+This is a hacked/documented version of Gordon McMillan's iu.py. I have:
+
+ - made it a little less terse
+
+ - added docstrings and explanatations
+
+ - standardized the variable naming scheme
+
+ - reorganized the code layout to enhance readability
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com> based on Gordon McMillan's iu.py
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.6 $
+Start Date: 2001/03/30
+Last Revision Date: $Date: 2007/04/03 01:56:24 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.6 $"[11:-2]
+
+##################################################
+## DEPENDENCIES
+
+import sys
+import imp
+import marshal
+
+##################################################
+## CONSTANTS & GLOBALS
+
+try:
+ True,False
+except NameError:
+ True, False = (1==1),(1==0)
+
+_installed = False
+
+STRINGTYPE = type('')
+
+# _globalOwnerTypes is defined at the bottom of this file
+
+_os_stat = _os_path_join = _os_getcwd = _os_path_dirname = None
+
+##################################################
+## FUNCTIONS
+
+def _os_bootstrap():
+ """Set up 'os' module replacement functions for use during import bootstrap."""
+
+ names = sys.builtin_module_names
+
+ join = dirname = None
+ if 'posix' in names:
+ sep = '/'
+ from posix import stat, getcwd
+ elif 'nt' in names:
+ sep = '\\'
+ from nt import stat, getcwd
+ elif 'dos' in names:
+ sep = '\\'
+ from dos import stat, getcwd
+ elif 'os2' in names:
+ sep = '\\'
+ from os2 import stat, getcwd
+ elif 'mac' in names:
+ from mac import stat, getcwd
+ def join(a, b):
+ if a == '':
+ return b
+ if ':' not in a:
+ a = ':' + a
+ if a[-1:] != ':':
+ a = a + ':'
+ return a + b
+ else:
+ raise ImportError, 'no os specific module found'
+
+ if join is None:
+ def join(a, b, sep=sep):
+ if a == '':
+ return b
+ lastchar = a[-1:]
+ if lastchar == '/' or lastchar == sep:
+ return a + b
+ return a + sep + b
+
+ if dirname is None:
+ def dirname(a, sep=sep):
+ for i in range(len(a)-1, -1, -1):
+ c = a[i]
+ if c == '/' or c == sep:
+ return a[:i]
+ return ''
+
+ global _os_stat
+ _os_stat = stat
+
+ global _os_path_join
+ _os_path_join = join
+
+ global _os_path_dirname
+ _os_path_dirname = dirname
+
+ global _os_getcwd
+ _os_getcwd = getcwd
+
+_os_bootstrap()
+
+def packageName(s):
+ for i in range(len(s)-1, -1, -1):
+ if s[i] == '.':
+ break
+ else:
+ return ''
+ return s[:i]
+
+def nameSplit(s):
+ rslt = []
+ i = j = 0
+ for j in range(len(s)):
+ if s[j] == '.':
+ rslt.append(s[i:j])
+ i = j+1
+ if i < len(s):
+ rslt.append(s[i:])
+ return rslt
+
+def getPathExt(fnm):
+ for i in range(len(fnm)-1, -1, -1):
+ if fnm[i] == '.':
+ return fnm[i:]
+ return ''
+
+def pathIsDir(pathname):
+ "Local replacement for os.path.isdir()."
+ try:
+ s = _os_stat(pathname)
+ except OSError:
+ return None
+ return (s[0] & 0170000) == 0040000
+
+def getDescr(fnm):
+ ext = getPathExt(fnm)
+ for (suffix, mode, typ) in imp.get_suffixes():
+ if suffix == ext:
+ return (suffix, mode, typ)
+
+##################################################
+## CLASSES
+
+class Owner:
+
+ """An Owner does imports from a particular piece of turf That is, there's
+ an Owner for each thing on sys.path There are owners for directories and
+ .pyz files. There could be owners for zip files, or even URLs. A
+ shadowpath (a dictionary mapping the names in sys.path to their owners) is
+ used so that sys.path (or a package's __path__) is still a bunch of strings,
+ """
+
+ def __init__(self, path):
+ self.path = path
+
+ def __str__(self):
+ return self.path
+
+ def getmod(self, nm):
+ return None
+
+class DirOwner(Owner):
+
+ def __init__(self, path):
+ if path == '':
+ path = _os_getcwd()
+ if not pathIsDir(path):
+ raise ValueError, "%s is not a directory" % path
+ Owner.__init__(self, path)
+
+ def getmod(self, nm,
+ getsuffixes=imp.get_suffixes, loadco=marshal.loads, newmod=imp.new_module):
+
+ pth = _os_path_join(self.path, nm)
+
+ possibles = [(pth, 0, None)]
+ if pathIsDir(pth):
+ possibles.insert(0, (_os_path_join(pth, '__init__'), 1, pth))
+ py = pyc = None
+ for pth, ispkg, pkgpth in possibles:
+ for ext, mode, typ in getsuffixes():
+ attempt = pth+ext
+ try:
+ st = _os_stat(attempt)
+ except:
+ pass
+ else:
+ if typ == imp.C_EXTENSION:
+ fp = open(attempt, 'rb')
+ mod = imp.load_module(nm, fp, attempt, (ext, mode, typ))
+ mod.__file__ = attempt
+ return mod
+ elif typ == imp.PY_SOURCE:
+ py = (attempt, st)
+ else:
+ pyc = (attempt, st)
+ if py or pyc:
+ break
+ if py is None and pyc is None:
+ return None
+ while 1:
+ if pyc is None or py and pyc[1][8] < py[1][8]:
+ try:
+ co = compile(open(py[0], 'r').read()+'\n', py[0], 'exec')
+ break
+ except SyntaxError, e:
+ print "Invalid syntax in %s" % py[0]
+ print e.args
+ raise
+ elif pyc:
+ stuff = open(pyc[0], 'rb').read()
+ try:
+ co = loadco(stuff[8:])
+ break
+ except (ValueError, EOFError):
+ pyc = None
+ else:
+ return None
+ mod = newmod(nm)
+ mod.__file__ = co.co_filename
+ if ispkg:
+ mod.__path__ = [pkgpth]
+ subimporter = PathImportDirector(mod.__path__)
+ mod.__importsub__ = subimporter.getmod
+ mod.__co__ = co
+ return mod
+
+
+class ImportDirector(Owner):
+ """ImportDirectors live on the metapath There's one for builtins, one for
+ frozen modules, and one for sys.path Windows gets one for modules gotten
+ from the Registry Mac would have them for PY_RESOURCE modules etc. A
+ generalization of Owner - their concept of 'turf' is broader"""
+
+ pass
+
+class BuiltinImportDirector(ImportDirector):
+ """Directs imports of builtin modules"""
+ def __init__(self):
+ self.path = 'Builtins'
+
+ def getmod(self, nm, isbuiltin=imp.is_builtin):
+ if isbuiltin(nm):
+ mod = imp.load_module(nm, None, nm, ('','',imp.C_BUILTIN))
+ return mod
+ return None
+
+class FrozenImportDirector(ImportDirector):
+ """Directs imports of frozen modules"""
+
+ def __init__(self):
+ self.path = 'FrozenModules'
+
+ def getmod(self, nm,
+ isFrozen=imp.is_frozen, loadMod=imp.load_module):
+ if isFrozen(nm):
+ mod = loadMod(nm, None, nm, ('','',imp.PY_FROZEN))
+ if hasattr(mod, '__path__'):
+ mod.__importsub__ = lambda name, pname=nm, owner=self: owner.getmod(pname+'.'+name)
+ return mod
+ return None
+
+
+class RegistryImportDirector(ImportDirector):
+ """Directs imports of modules stored in the Windows Registry"""
+
+ def __init__(self):
+ self.path = "WindowsRegistry"
+ self.map = {}
+ try:
+ import win32api
+ ## import win32con
+ except ImportError:
+ pass
+ else:
+ HKEY_CURRENT_USER = -2147483647
+ HKEY_LOCAL_MACHINE = -2147483646
+ KEY_ALL_ACCESS = 983103
+ subkey = r"Software\Python\PythonCore\%s\Modules" % sys.winver
+ for root in (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE):
+ try:
+ hkey = win32api.RegOpenKeyEx(root, subkey, 0, KEY_ALL_ACCESS)
+ except:
+ pass
+ else:
+ numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey)
+ for i in range(numsubkeys):
+ subkeyname = win32api.RegEnumKey(hkey, i)
+ hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, KEY_ALL_ACCESS)
+ val = win32api.RegQueryValueEx(hskey, '')
+ desc = getDescr(val[0])
+ self.map[subkeyname] = (val[0], desc)
+ hskey.Close()
+ hkey.Close()
+ break
+
+ def getmod(self, nm):
+ stuff = self.map.get(nm)
+ if stuff:
+ fnm, desc = stuff
+ fp = open(fnm, 'rb')
+ mod = imp.load_module(nm, fp, fnm, desc)
+ mod.__file__ = fnm
+ return mod
+ return None
+
+class PathImportDirector(ImportDirector):
+ """Directs imports of modules stored on the filesystem."""
+
+ def __init__(self, pathlist=None, importers=None, ownertypes=None):
+ if pathlist is None:
+ self.path = sys.path
+ else:
+ self.path = pathlist
+ if ownertypes == None:
+ self._ownertypes = _globalOwnerTypes
+ else:
+ self._ownertypes = ownertypes
+ if importers:
+ self._shadowPath = importers
+ else:
+ self._shadowPath = {}
+ self._inMakeOwner = False
+ self._building = {}
+
+ def getmod(self, nm):
+ mod = None
+ for thing in self.path:
+ if type(thing) is STRINGTYPE:
+ owner = self._shadowPath.get(thing, -1)
+ if owner == -1:
+ owner = self._shadowPath[thing] = self._makeOwner(thing)
+ if owner:
+ mod = owner.getmod(nm)
+ else:
+ mod = thing.getmod(nm)
+ if mod:
+ break
+ return mod
+
+ def _makeOwner(self, path):
+ if self._building.get(path):
+ return None
+ self._building[path] = 1
+ owner = None
+ for klass in self._ownertypes:
+ try:
+ # this may cause an import, which may cause recursion
+ # hence the protection
+ owner = klass(path)
+ except:
+ pass
+ else:
+ break
+ del self._building[path]
+ return owner
+
+#=================ImportManager============================#
+# The one-and-only ImportManager
+# ie, the builtin import
+
+UNTRIED = -1
+
+class ImportManager:
+ # really the equivalent of builtin import
+ def __init__(self):
+ self.metapath = [
+ BuiltinImportDirector(),
+ FrozenImportDirector(),
+ RegistryImportDirector(),
+ PathImportDirector()
+ ]
+ self.threaded = 0
+ self.rlock = None
+ self.locker = None
+ self.setThreaded()
+
+ def setThreaded(self):
+ thread = sys.modules.get('thread', None)
+ if thread and not self.threaded:
+ self.threaded = 1
+ self.rlock = thread.allocate_lock()
+ self._get_ident = thread.get_ident
+
+ def install(self):
+ import __builtin__
+ __builtin__.__import__ = self.importHook
+ __builtin__.reload = self.reloadHook
+
+ def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1):
+ '''
+ NOTE: Currently importHook will accept the keyword-argument "level"
+ but it will *NOT* use it (currently). Details about the "level" keyword
+ argument can be found here: http://www.python.org/doc/2.5.2/lib/built-in-funcs.html
+ '''
+ # first see if we could be importing a relative name
+ #print "importHook(%s, %s, locals, %s)" % (name, globals['__name__'], fromlist)
+ _sys_modules_get = sys.modules.get
+ contexts = [None]
+ if globals:
+ importernm = globals.get('__name__', '')
+ if importernm:
+ if hasattr(_sys_modules_get(importernm), '__path__'):
+ contexts.insert(0,importernm)
+ else:
+ pkgnm = packageName(importernm)
+ if pkgnm:
+ contexts.insert(0,pkgnm)
+ # so contexts is [pkgnm, None] or just [None]
+ # now break the name being imported up so we get:
+ # a.b.c -> [a, b, c]
+ nmparts = nameSplit(name)
+ _self_doimport = self.doimport
+ threaded = self.threaded
+ for context in contexts:
+ ctx = context
+ for i in range(len(nmparts)):
+ nm = nmparts[i]
+ #print " importHook trying %s in %s" % (nm, ctx)
+ if ctx:
+ fqname = ctx + '.' + nm
+ else:
+ fqname = nm
+ if threaded:
+ self._acquire()
+ mod = _sys_modules_get(fqname, UNTRIED)
+ if mod is UNTRIED:
+ mod = _self_doimport(nm, ctx, fqname)
+ if threaded:
+ self._release()
+ if mod:
+ ctx = fqname
+ else:
+ break
+ else:
+ # no break, point i beyond end
+ i = i + 1
+ if i:
+ break
+
+ if i<len(nmparts):
+ if ctx and hasattr(sys.modules[ctx], nmparts[i]):
+ #print "importHook done with %s %s %s (case 1)" % (name, globals['__name__'], fromlist)
+ return sys.modules[nmparts[0]]
+ del sys.modules[fqname]
+ raise ImportError, "No module named %s" % fqname
+ if fromlist is None:
+ #print "importHook done with %s %s %s (case 2)" % (name, globals['__name__'], fromlist)
+ if context:
+ return sys.modules[context+'.'+nmparts[0]]
+ return sys.modules[nmparts[0]]
+ bottommod = sys.modules[ctx]
+ if hasattr(bottommod, '__path__'):
+ fromlist = list(fromlist)
+ i = 0
+ while i < len(fromlist):
+ nm = fromlist[i]
+ if nm == '*':
+ fromlist[i:i+1] = list(getattr(bottommod, '__all__', []))
+ if i >= len(fromlist):
+ break
+ nm = fromlist[i]
+ i = i + 1
+ if not hasattr(bottommod, nm):
+ if self.threaded:
+ self._acquire()
+ mod = self.doimport(nm, ctx, ctx+'.'+nm)
+ if self.threaded:
+ self._release()
+ if not mod:
+ raise ImportError, "%s not found in %s" % (nm, ctx)
+ #print "importHook done with %s %s %s (case 3)" % (name, globals['__name__'], fromlist)
+ return bottommod
+
+ def doimport(self, nm, parentnm, fqname):
+ # Not that nm is NEVER a dotted name at this point
+ #print "doimport(%s, %s, %s)" % (nm, parentnm, fqname)
+ if parentnm:
+ parent = sys.modules[parentnm]
+ if hasattr(parent, '__path__'):
+ importfunc = getattr(parent, '__importsub__', None)
+ if not importfunc:
+ subimporter = PathImportDirector(parent.__path__)
+ importfunc = parent.__importsub__ = subimporter.getmod
+ mod = importfunc(nm)
+ if mod:
+ setattr(parent, nm, mod)
+ else:
+ #print "..parent not a package"
+ return None
+ else:
+ # now we're dealing with an absolute import
+ for director in self.metapath:
+ mod = director.getmod(nm)
+ if mod:
+ break
+ if mod:
+ mod.__name__ = fqname
+ sys.modules[fqname] = mod
+ if hasattr(mod, '__co__'):
+ co = mod.__co__
+ del mod.__co__
+ exec co in mod.__dict__
+ if fqname == 'thread' and not self.threaded:
+## print "thread detected!"
+ self.setThreaded()
+ else:
+ sys.modules[fqname] = None
+ #print "..found %s" % mod
+ return mod
+
+ def reloadHook(self, mod):
+ fqnm = mod.__name__
+ nm = nameSplit(fqnm)[-1]
+ parentnm = packageName(fqnm)
+ newmod = self.doimport(nm, parentnm, fqnm)
+ mod.__dict__.update(newmod.__dict__)
+## return newmod
+
+ def _acquire(self):
+ if self.rlock.locked():
+ if self.locker == self._get_ident():
+ self.lockcount = self.lockcount + 1
+## print "_acquire incrementing lockcount to", self.lockcount
+ return
+ self.rlock.acquire()
+ self.locker = self._get_ident()
+ self.lockcount = 0
+## print "_acquire first time!"
+
+ def _release(self):
+ if self.lockcount:
+ self.lockcount = self.lockcount - 1
+## print "_release decrementing lockcount to", self.lockcount
+ else:
+ self.rlock.release()
+## print "_release releasing lock!"
+
+
+##################################################
+## MORE CONSTANTS & GLOBALS
+
+_globalOwnerTypes = [
+ DirOwner,
+ Owner,
+]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/I18n.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/I18n.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/I18n.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,67 @@
+import gettext
+_ = gettext.gettext
+class I18n(object):
+ def __init__(self, parser):
+ pass
+
+## junk I'm playing with to test the macro framework
+# def parseArgs(self, parser, startPos):
+# parser.getWhiteSpace()
+# args = parser.getExpression(useNameMapper=False,
+# pyTokensToBreakAt=[':']).strip()
+# return args
+#
+# def convertArgStrToDict(self, args, parser=None, startPos=None):
+# def getArgs(*pargs, **kws):
+# return pargs, kws
+# exec 'positionalArgs, kwArgs = getArgs(%(args)s)'%locals()
+# return kwArgs
+
+ def __call__(self,
+ src, # aka message,
+ plural=None,
+ n=None, # should be a string representing the name of the
+ # '$var' rather than $var itself
+ id=None,
+ domain=None,
+ source=None,
+ target=None,
+ comment=None,
+
+ # args that are automatically supplied by the parser when the
+ # macro is called:
+ parser=None,
+ macros=None,
+ isShortForm=False,
+ EOLCharsInShortForm=None,
+ startPos=None,
+ endPos=None,
+ ):
+ """This is just a stub at this time.
+
+ plural = the plural form of the message
+ n = a sized argument to distinguish between single and plural forms
+
+ id = msgid in the translation catalog
+ domain = translation domain
+ source = source lang
+ target = a specific target lang
+ comment = a comment to the translation team
+
+ See the following for some ideas
+ http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport
+
+ Other notes:
+ - There is no need to replicate the i18n:name attribute from plone / PTL,
+ as cheetah placeholders serve the same purpose
+
+
+ """
+
+ #print macros['i18n']
+ src = _(src)
+ if isShortForm and endPos<len(parser):
+ return src+EOLCharsInShortForm
+ else:
+ return src
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Macros/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/NameMapper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/NameMapper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/NameMapper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,375 @@
+#!/usr/bin/env python
+# $Id: NameMapper.py,v 1.32 2007/12/10 19:20:09 tavis_rudd Exp $
+
+"""This module supports Cheetah's optional NameMapper syntax.
+
+Overview
+================================================================================
+
+NameMapper provides a simple syntax for accessing Python data structures,
+functions, and methods from Cheetah. It's called NameMapper because it 'maps'
+simple 'names' in Cheetah templates to possibly more complex syntax in Python.
+
+Its purpose is to make working with Cheetah easy for non-programmers.
+Specifically, non-programmers using Cheetah should NOT need to be taught (a)
+what the difference is between an object and a dictionary, (b) what functions
+and methods are, and (c) what 'self' is. A further aim (d) is to buffer the
+code in Cheetah templates from changes in the implementation of the Python data
+structures behind them.
+
+Consider this scenario:
+
+You are building a customer information system. The designers with you want to
+use information from your system on the client's website --AND-- they want to
+understand the display code and so they can maintian it themselves.
+
+You write a UI class with a 'customers' method that returns a dictionary of all
+the customer objects. Each customer object has an 'address' method that returns
+the a dictionary with information about the customer's address. The designers
+want to be able to access that information.
+
+Using PSP, the display code for the website would look something like the
+following, assuming your servlet subclasses the class you created for managing
+customer information:
+
+ <%= self.customer()[ID].address()['city'] %> (42 chars)
+
+Using Cheetah's NameMapper syntax it could be any of the following:
+
+ $self.customers()[$ID].address()['city'] (39 chars)
+ --OR--
+ $customers()[$ID].address()['city']
+ --OR--
+ $customers()[$ID].address().city
+ --OR--
+ $customers()[$ID].address.city
+ --OR--
+ $customers()[$ID].address.city
+ --OR--
+ $customers[$ID].address.city (27 chars)
+
+
+Which of these would you prefer to explain to the designers, who have no
+programming experience? The last form is 15 characters shorter than the PSP
+and, conceptually, is far more accessible. With PHP or ASP, the code would be
+even messier than the PSP
+
+This is a rather extreme example and, of course, you could also just implement
+'$getCustomer($ID).city' and obey the Law of Demeter (search Google for more on that).
+But good object orientated design isn't the point here.
+
+Details
+================================================================================
+The parenthesized letters below correspond to the aims in the second paragraph.
+
+DICTIONARY ACCESS (a)
+---------------------
+
+NameMapper allows access to items in a dictionary using the same dotted notation
+used to access object attributes in Python. This aspect of NameMapper is known
+as 'Unified Dotted Notation'.
+
+For example, with Cheetah it is possible to write:
+ $customers()['kerr'].address() --OR-- $customers().kerr.address()
+where the second form is in NameMapper syntax.
+
+This only works with dictionary keys that are also valid python identifiers:
+ regex = '[a-zA-Z_][a-zA-Z_0-9]*'
+
+
+AUTOCALLING (b,d)
+-----------------
+
+NameMapper automatically detects functions and methods in Cheetah $vars and calls
+them if the parentheses have been left off.
+
+For example if 'a' is an object, 'b' is a method
+ $a.b
+is equivalent to
+ $a.b()
+
+If b returns a dictionary, then following variations are possible
+ $a.b.c --OR-- $a.b().c --OR-- $a.b()['c']
+where 'c' is a key in the dictionary that a.b() returns.
+
+Further notes:
+* NameMapper autocalls the function or method without any arguments. Thus
+autocalling can only be used with functions or methods that either have no
+arguments or have default values for all arguments.
+
+* NameMapper only autocalls functions and methods. Classes and callable object instances
+will not be autocalled.
+
+* Autocalling can be disabled using Cheetah's 'useAutocalling' setting.
+
+LEAVING OUT 'self' (c,d)
+------------------------
+
+NameMapper makes it possible to access the attributes of a servlet in Cheetah
+without needing to include 'self' in the variable names. See the NAMESPACE
+CASCADING section below for details.
+
+NAMESPACE CASCADING (d)
+--------------------
+...
+
+Implementation details
+================================================================================
+
+* NameMapper's search order is dictionary keys then object attributes
+
+* NameMapper.NotFound is raised if a value can't be found for a name.
+
+Performance and the C version
+================================================================================
+
+Cheetah comes with both a C version and a Python version of NameMapper. The C
+version is significantly faster and the exception tracebacks are much easier to
+read. It's still slower than standard Python syntax, but you won't notice the
+difference in realistic usage scenarios.
+
+Cheetah uses the optimized C version (_namemapper.c) if it has
+been compiled or falls back to the Python version if not.
+
+Meta-Data
+================================================================================
+Authors: Tavis Rudd <tavis at damnsimple.com>,
+ Chuck Esterbrook <echuck at mindspring.com>
+Version: $Revision: 1.32 $
+Start Date: 2001/04/03
+Last Revision Date: $Date: 2007/12/10 19:20:09 $
+"""
+from __future__ import generators
+__author__ = "Tavis Rudd <tavis at damnsimple.com>," +\
+ "\nChuck Esterbrook <echuck at mindspring.com>"
+__revision__ = "$Revision: 1.32 $"[11:-2]
+import types
+from types import StringType, InstanceType, ClassType, TypeType
+from pprint import pformat
+import inspect
+import pdb
+
+_INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS = False
+_ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS = True
+__all__ = ['NotFound',
+ 'hasKey',
+ 'valueForKey',
+ 'valueForName',
+ 'valueFromSearchList',
+ 'valueFromFrameOrSearchList',
+ 'valueFromFrame',
+ ]
+
+
+## N.B. An attempt is made at the end of this module to import C versions of
+## these functions. If _namemapper.c has been compiled succesfully and the
+## import goes smoothly, the Python versions defined here will be replaced with
+## the C versions.
+
+class NotFound(LookupError):
+ pass
+
+def _raiseNotFoundException(key, namespace):
+ excString = "cannot find '%s'"%key
+ if _INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS:
+ excString += ' in the namespace %s'%pformat(namespace)
+ raise NotFound(excString)
+
+def _wrapNotFoundException(exc, fullName, namespace):
+ if not _ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS:
+ raise
+ else:
+ excStr = exc.args[0]
+ if excStr.find('while searching')==-1: # only wrap once!
+ excStr +=" while searching for '%s'"%fullName
+ if _INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS:
+ excStr += ' in the namespace %s'%pformat(namespace)
+ exc.args = (excStr,)
+ raise
+
+def _isInstanceOrClass(obj):
+ if type(obj) in (InstanceType, ClassType):
+ # oldstyle
+ return True
+
+ if hasattr(obj, "__class__"):
+ # newstyle
+ if hasattr(obj, 'mro'):
+ # type/class
+ return True
+ elif (hasattr(obj, 'im_func') or hasattr(obj, 'func_code') or hasattr(obj, '__self__')):
+ # method, func, or builtin func
+ return False
+ elif hasattr(obj, '__init__'):
+ # instance
+ return True
+ return False
+
+def hasKey(obj, key):
+ """Determine if 'obj' has 'key' """
+ if hasattr(obj,'has_key') and obj.has_key(key):
+ return True
+ elif hasattr(obj, key):
+ return True
+ else:
+ return False
+
+def valueForKey(obj, key):
+ if hasattr(obj, 'has_key') and obj.has_key(key):
+ return obj[key]
+ elif hasattr(obj, key):
+ return getattr(obj, key)
+ else:
+ _raiseNotFoundException(key, obj)
+
+def _valueForName(obj, name, executeCallables=False):
+ nameChunks=name.split('.')
+ for i in range(len(nameChunks)):
+ key = nameChunks[i]
+ if hasattr(obj, 'has_key') and obj.has_key(key):
+ nextObj = obj[key]
+ else:
+ try:
+ nextObj = getattr(obj, key)
+ except AttributeError:
+ _raiseNotFoundException(key, obj)
+
+ if executeCallables and callable(nextObj) and not _isInstanceOrClass(nextObj):
+ obj = nextObj()
+ else:
+ obj = nextObj
+ return obj
+
+def valueForName(obj, name, executeCallables=False):
+ try:
+ return _valueForName(obj, name, executeCallables)
+ except NotFound, e:
+ _wrapNotFoundException(e, fullName=name, namespace=obj)
+
+def valueFromSearchList(searchList, name, executeCallables=False):
+ key = name.split('.')[0]
+ for namespace in searchList:
+ if hasKey(namespace, key):
+ return _valueForName(namespace, name,
+ executeCallables=executeCallables)
+ _raiseNotFoundException(key, searchList)
+
+def _namespaces(callerFrame, searchList=None):
+ yield callerFrame.f_locals
+ if searchList:
+ for namespace in searchList:
+ yield namespace
+ yield callerFrame.f_globals
+ yield __builtins__
+
+def valueFromFrameOrSearchList(searchList, name, executeCallables=False,
+ frame=None):
+ def __valueForName():
+ try:
+ return _valueForName(namespace, name, executeCallables=executeCallables)
+ except NotFound, e:
+ _wrapNotFoundException(e, fullName=name, namespace=searchList)
+ try:
+ if not frame:
+ frame = inspect.stack()[1][0]
+ key = name.split('.')[0]
+ for namespace in _namespaces(frame, searchList):
+ if hasKey(namespace, key):
+ return __valueForName()
+ _raiseNotFoundException(key, searchList)
+ finally:
+ del frame
+
+def valueFromFrame(name, executeCallables=False, frame=None):
+ # @@TR consider implementing the C version the same way
+ # at the moment it provides a seperate but mirror implementation
+ # to valueFromFrameOrSearchList
+ try:
+ if not frame:
+ frame = inspect.stack()[1][0]
+ return valueFromFrameOrSearchList(searchList=None,
+ name=name,
+ executeCallables=executeCallables,
+ frame=frame)
+ finally:
+ del frame
+
+def hasName(obj, name):
+ #Not in the C version
+ """Determine if 'obj' has the 'name' """
+ key = name.split('.')[0]
+ if not hasKey(obj, key):
+ return False
+ try:
+ valueForName(obj, name)
+ return True
+ except NotFound:
+ return False
+try:
+ from _namemapper import NotFound, valueForKey, valueForName, \
+ valueFromSearchList, valueFromFrameOrSearchList, valueFromFrame
+ # it is possible with Jython or Windows, for example, that _namemapper.c hasn't been compiled
+ C_VERSION = True
+except:
+ C_VERSION = False
+
+##################################################
+## CLASSES
+
+class Mixin:
+ """@@ document me"""
+ def valueForName(self, name):
+ return valueForName(self, name)
+
+ def valueForKey(self, key):
+ return valueForKey(self, key)
+
+##################################################
+## if run from the command line ##
+
+def example():
+ class A(Mixin):
+ classVar = 'classVar val'
+ def method(self,arg='method 1 default arg'):
+ return arg
+
+ def method2(self, arg='meth 2 default arg'):
+ return {'item1':arg}
+
+ def method3(self, arg='meth 3 default'):
+ return arg
+
+ class B(A):
+ classBvar = 'classBvar val'
+
+ a = A()
+ a.one = 'valueForOne'
+ def function(whichOne='default'):
+ values = {
+ 'default': 'default output',
+ 'one': 'output option one',
+ 'two': 'output option two'
+ }
+ return values[whichOne]
+
+ a.dic = {
+ 'func': function,
+ 'method': a.method3,
+ 'item': 'itemval',
+ 'subDict': {'nestedMethod':a.method3}
+ }
+ b = 'this is local b'
+
+ print valueForKey(a.dic,'subDict')
+ print valueForName(a, 'dic.item')
+ print valueForName(vars(), 'b')
+ print valueForName(__builtins__, 'dir')()
+ print valueForName(vars(), 'a.classVar')
+ print valueForName(vars(), 'a.dic.func', executeCallables=True)
+ print valueForName(vars(), 'a.method2.item1', executeCallables=True)
+
+if __name__ == '__main__':
+ example()
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Parser.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Parser.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Parser.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2626 @@
+#!/usr/bin/env python
+# $Id: Parser.py,v 1.137 2008/03/10 05:25:13 tavis_rudd Exp $
+"""Parser classes for Cheetah's Compiler
+
+Classes:
+ ParseError( Exception )
+ _LowLevelParser( Cheetah.SourceReader.SourceReader ), basically a lexer
+ _HighLevelParser( _LowLevelParser )
+ Parser === _HighLevelParser (an alias)
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+Version: $Revision: 1.137 $
+Start Date: 2001/08/01
+Last Revision Date: $Date: 2008/03/10 05:25:13 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.137 $"[11:-2]
+
+import os
+import sys
+import re
+from re import DOTALL, MULTILINE
+from types import StringType, ListType, TupleType, ClassType, TypeType
+import time
+from tokenize import pseudoprog
+import inspect
+import new
+import traceback
+
+from Cheetah.SourceReader import SourceReader
+from Cheetah import Filters
+from Cheetah import ErrorCatchers
+from Cheetah.Unspecified import Unspecified
+from Cheetah.Macros.I18n import I18n
+
+# re tools
+_regexCache = {}
+def cachedRegex(pattern):
+ if pattern not in _regexCache:
+ _regexCache[pattern] = re.compile(pattern)
+ return _regexCache[pattern]
+
+def escapeRegexChars(txt,
+ escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')):
+
+ """Return a txt with all special regular expressions chars escaped."""
+
+ return escapeRE.sub(r'\\\1' , txt)
+
+def group(*choices): return '(' + '|'.join(choices) + ')'
+def nongroup(*choices): return '(?:' + '|'.join(choices) + ')'
+def namedGroup(name, *choices): return '(P:<' + name +'>' + '|'.join(choices) + ')'
+def any(*choices): return apply(group, choices) + '*'
+def maybe(*choices): return apply(group, choices) + '?'
+
+##################################################
+## CONSTANTS & GLOBALS ##
+
+NO_CACHE = 0
+STATIC_CACHE = 1
+REFRESH_CACHE = 2
+
+SET_LOCAL = 0
+SET_GLOBAL = 1
+SET_MODULE = 2
+
+##################################################
+## Tokens for the parser ##
+
+#generic
+identchars = "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
+namechars = identchars + "0123456789"
+
+#operators
+powerOp = '**'
+unaryArithOps = ('+', '-', '~')
+binaryArithOps = ('+', '-', '/', '//','%')
+shiftOps = ('>>','<<')
+bitwiseOps = ('&','|','^')
+assignOp = '='
+augAssignOps = ('+=','-=','/=','*=', '**=','^=','%=',
+ '>>=','<<=','&=','|=', )
+assignmentOps = (assignOp,) + augAssignOps
+
+compOps = ('<','>','==','!=','<=','>=', '<>', 'is', 'in',)
+booleanOps = ('and','or','not')
+operators = (powerOp,) + unaryArithOps + binaryArithOps \
+ + shiftOps + bitwiseOps + assignmentOps \
+ + compOps + booleanOps
+
+delimeters = ('(',')','{','}','[',']',
+ ',','.',':',';','=','`') + augAssignOps
+
+
+keywords = ('and', 'del', 'for', 'is', 'raise',
+ 'assert', 'elif', 'from', 'lambda', 'return',
+ 'break', 'else', 'global', 'not', 'try',
+ 'class', 'except', 'if', 'or', 'while',
+ 'continue', 'exec', 'import', 'pass',
+ 'def', 'finally', 'in', 'print',
+ )
+
+single3 = "'''"
+double3 = '"""'
+
+tripleQuotedStringStarts = ("'''", '"""',
+ "r'''", 'r"""', "R'''", 'R"""',
+ "u'''", 'u"""', "U'''", 'U"""',
+ "ur'''", 'ur"""', "Ur'''", 'Ur"""',
+ "uR'''", 'uR"""', "UR'''", 'UR"""')
+
+tripleQuotedStringPairs = {"'''": single3, '"""': double3,
+ "r'''": single3, 'r"""': double3,
+ "u'''": single3, 'u"""': double3,
+ "ur'''": single3, 'ur"""': double3,
+ "R'''": single3, 'R"""': double3,
+ "U'''": single3, 'U"""': double3,
+ "uR'''": single3, 'uR"""': double3,
+ "Ur'''": single3, 'Ur"""': double3,
+ "UR'''": single3, 'UR"""': double3,
+ }
+
+closurePairs= {')':'(',']':'[','}':'{'}
+closurePairsRev= {'(':')','[':']','{':'}'}
+
+##################################################
+## Regex chunks for the parser ##
+
+tripleQuotedStringREs = {}
+def makeTripleQuoteRe(start, end):
+ start = escapeRegexChars(start)
+ end = escapeRegexChars(end)
+ return re.compile(r'(?:' + start + r').*?' + r'(?:' + end + r')', re.DOTALL)
+
+for start, end in tripleQuotedStringPairs.items():
+ tripleQuotedStringREs[start] = makeTripleQuoteRe(start, end)
+
+WS = r'[ \f\t]*'
+EOL = r'\r\n|\n|\r'
+EOLZ = EOL + r'|\Z'
+escCharLookBehind = nongroup(r'(?<=\A)',r'(?<!\\)')
+nameCharLookAhead = r'(?=[A-Za-z_])'
+identRE=re.compile(r'[a-zA-Z_][a-zA-Z_0-9]*')
+EOLre=re.compile(r'(?:\r\n|\r|\n)')
+
+specialVarRE=re.compile(r'([a-zA-z_]+)@') # for matching specialVar comments
+# e.g. ##author@ Tavis Rudd
+
+unicodeDirectiveRE = re.compile(
+ r'(?:^|\r\n|\r|\n)\s*#\s{0,5}unicode[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
+encodingDirectiveRE = re.compile(
+ r'(?:^|\r\n|\r|\n)\s*#\s{0,5}encoding[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
+
+escapedNewlineRE = re.compile(r'(?<!\\)\\n')
+
+directiveNamesAndParsers = {
+ # importing and inheritance
+ 'import':None,
+ 'from':None,
+ 'extends': 'eatExtends',
+ 'implements': 'eatImplements',
+ 'super': 'eatSuper',
+
+ # output, filtering, and caching
+ 'slurp': 'eatSlurp',
+ 'raw': 'eatRaw',
+ 'include': 'eatInclude',
+ 'cache': 'eatCache',
+ 'filter': 'eatFilter',
+ 'echo': None,
+ 'silent': None,
+ 'transform' : 'eatTransform',
+
+ 'call': 'eatCall',
+ 'arg': 'eatCallArg',
+
+ 'capture': 'eatCapture',
+
+ # declaration, assignment, and deletion
+ 'attr': 'eatAttr',
+ 'def': 'eatDef',
+ 'block': 'eatBlock',
+ '@': 'eatDecorator',
+ 'defmacro': 'eatDefMacro',
+
+ 'closure': 'eatClosure',
+
+ 'set': 'eatSet',
+ 'del': None,
+
+ # flow control
+ 'if': 'eatIf',
+ 'while': None,
+ 'for': None,
+ 'else': None,
+ 'elif': None,
+ 'pass': None,
+ 'break': None,
+ 'continue': None,
+ 'stop': None,
+ 'return': None,
+ 'yield': None,
+
+ # little wrappers
+ 'repeat': None,
+ 'unless': None,
+
+ # error handling
+ 'assert': None,
+ 'raise': None,
+ 'try': None,
+ 'except': None,
+ 'finally': None,
+ 'errorCatcher': 'eatErrorCatcher',
+
+ # intructions to the parser and compiler
+ 'breakpoint': 'eatBreakPoint',
+ 'compiler': 'eatCompiler',
+ 'compiler-settings': 'eatCompilerSettings',
+
+ # misc
+ 'shBang': 'eatShbang',
+ 'encoding': 'eatEncoding',
+
+ 'end': 'eatEndDirective',
+ }
+
+endDirectiveNamesAndHandlers = {
+ 'def': 'handleEndDef', # has short-form
+ 'block': None, # has short-form
+ 'closure': None, # has short-form
+ 'cache': None, # has short-form
+ 'call': None, # has short-form
+ 'capture': None, # has short-form
+ 'filter': None,
+ 'errorCatcher':None,
+ 'while': None, # has short-form
+ 'for': None, # has short-form
+ 'if': None, # has short-form
+ 'try': None, # has short-form
+ 'repeat': None, # has short-form
+ 'unless': None, # has short-form
+ }
+
+##################################################
+## CLASSES ##
+
+# @@TR: SyntaxError doesn't call exception.__str__ for some reason!
+#class ParseError(SyntaxError):
+class ParseError(ValueError):
+ def __init__(self, stream, msg='Invalid Syntax', extMsg='', lineno=None, col=None):
+ self.stream = stream
+ if stream.pos() >= len(stream):
+ stream.setPos(len(stream) -1)
+ self.msg = msg
+ self.extMsg = extMsg
+ self.lineno = lineno
+ self.col = col
+
+ def __str__(self):
+ return self.report()
+
+ def report(self):
+ stream = self.stream
+ if stream.filename():
+ f = " in file %s" % stream.filename()
+ else:
+ f = ''
+ report = ''
+ if self.lineno:
+ lineno = self.lineno
+ row, col, line = (lineno, (self.col or 0),
+ self.stream.splitlines()[lineno-1])
+ else:
+ row, col, line = self.stream.getRowColLine()
+
+ ## get the surrounding lines
+ lines = stream.splitlines()
+ prevLines = [] # (rowNum, content)
+ for i in range(1,4):
+ if row-1-i <=0:
+ break
+ prevLines.append( (row-i,lines[row-1-i]) )
+
+ nextLines = [] # (rowNum, content)
+ for i in range(1,4):
+ if not row-1+i < len(lines):
+ break
+ nextLines.append( (row+i,lines[row-1+i]) )
+ nextLines.reverse()
+
+ ## print the main message
+ report += "\n\n%s\n" %self.msg
+ report += "Line %i, column %i%s\n\n" % (row, col, f)
+ report += 'Line|Cheetah Code\n'
+ report += '----|-------------------------------------------------------------\n'
+ while prevLines:
+ lineInfo = prevLines.pop()
+ report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
+ report += "%(row)-4d|%(line)s\n"% {'row':row, 'line':line}
+ report += ' '*5 +' '*(col-1) + "^\n"
+
+ while nextLines:
+ lineInfo = nextLines.pop()
+ report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
+ ## add the extra msg
+ if self.extMsg:
+ report += self.extMsg + '\n'
+
+ return report
+
+class ForbiddenSyntax(ParseError): pass
+class ForbiddenExpression(ForbiddenSyntax): pass
+class ForbiddenDirective(ForbiddenSyntax): pass
+
+class CheetahVariable:
+ def __init__(self, nameChunks, useNameMapper=True, cacheToken=None,
+ rawSource=None):
+ self.nameChunks = nameChunks
+ self.useNameMapper = useNameMapper
+ self.cacheToken = cacheToken
+ self.rawSource = rawSource
+
+class Placeholder(CheetahVariable): pass
+
+class ArgList:
+ """Used by _LowLevelParser.getArgList()"""
+
+ def __init__(self):
+ self.argNames = []
+ self.defVals = []
+ self.i = 0
+
+ def addArgName(self, name):
+ self.argNames.append( name )
+ self.defVals.append( None )
+
+ def next(self):
+ self.i += 1
+
+ def addToDefVal(self, token):
+ i = self.i
+ if self.defVals[i] == None:
+ self.defVals[i] = ''
+ self.defVals[i] += token
+
+ def merge(self):
+ defVals = self.defVals
+ for i in range(len(defVals)):
+ if type(defVals[i]) == StringType:
+ defVals[i] = defVals[i].strip()
+
+ return map(None, [i.strip() for i in self.argNames], defVals)
+
+ def __str__(self):
+ return str(self.merge())
+
+class _LowLevelParser(SourceReader):
+ """This class implements the methods to match or extract ('get*') the basic
+ elements of Cheetah's grammar. It does NOT handle any code generation or
+ state management.
+ """
+
+ _settingsManager = None
+
+ def setSettingsManager(self, settingsManager):
+ self._settingsManager = settingsManager
+
+ def setting(self, key, default=Unspecified):
+ if default is Unspecified:
+ return self._settingsManager.setting(key)
+ else:
+ return self._settingsManager.setting(key, default=default)
+
+ def setSetting(self, key, val):
+ self._settingsManager.setSetting(key, val)
+
+ def settings(self):
+ return self._settingsManager.settings()
+
+ def updateSettings(self, settings):
+ self._settingsManager.updateSettings(settings)
+
+ def _initializeSettings(self):
+ self._settingsManager._initializeSettings()
+
+ def configureParser(self):
+ """Is called by the Compiler instance after the parser has had a
+ settingsManager assigned with self.setSettingsManager()
+ """
+ self._makeCheetahVarREs()
+ self._makeCommentREs()
+ self._makeDirectiveREs()
+ self._makePspREs()
+ self._possibleNonStrConstantChars = (
+ self.setting('commentStartToken')[0] +
+ self.setting('multiLineCommentStartToken')[0] +
+ self.setting('cheetahVarStartToken')[0] +
+ self.setting('directiveStartToken')[0] +
+ self.setting('PSPStartToken')[0])
+ self._nonStrConstMatchers = [
+ self.matchCommentStartToken,
+ self.matchMultiLineCommentStartToken,
+ self.matchVariablePlaceholderStart,
+ self.matchExpressionPlaceholderStart,
+ self.matchDirective,
+ self.matchPSPStartToken,
+ self.matchEOLSlurpToken,
+ ]
+
+ ## regex setup ##
+
+ def _makeCheetahVarREs(self):
+
+ """Setup the regexs for Cheetah $var parsing."""
+
+ num = r'[0-9\.]+'
+ interval = (r'(?P<interval>' +
+ num + r's|' +
+ num + r'm|' +
+ num + r'h|' +
+ num + r'd|' +
+ num + r'w|' +
+ num + ')'
+ )
+
+ cacheToken = (r'(?:' +
+ r'(?P<REFRESH_CACHE>\*' + interval + '\*)'+
+ '|' +
+ r'(?P<STATIC_CACHE>\*)' +
+ '|' +
+ r'(?P<NO_CACHE>)' +
+ ')')
+ self.cacheTokenRE = cachedRegex(cacheToken)
+
+ silentPlaceholderToken = (r'(?:' +
+ r'(?P<SILENT>' +escapeRegexChars('!')+')'+
+ '|' +
+ r'(?P<NOT_SILENT>)' +
+ ')')
+ self.silentPlaceholderTokenRE = cachedRegex(silentPlaceholderToken)
+
+ self.cheetahVarStartRE = cachedRegex(
+ escCharLookBehind +
+ r'(?P<startToken>'+escapeRegexChars(self.setting('cheetahVarStartToken'))+')'+
+ r'(?P<silenceToken>'+silentPlaceholderToken+')'+
+ r'(?P<cacheToken>'+cacheToken+')'+
+ r'(?P<enclosure>|(?:(?:\{|\(|\[)[ \t\f]*))' + # allow WS after enclosure
+ r'(?=[A-Za-z_])')
+ validCharsLookAhead = r'(?=[A-Za-z_\*!\{\(\[])'
+ self.cheetahVarStartToken = self.setting('cheetahVarStartToken')
+ self.cheetahVarStartTokenRE = cachedRegex(
+ escCharLookBehind +
+ escapeRegexChars(self.setting('cheetahVarStartToken'))
+ +validCharsLookAhead
+ )
+
+ self.cheetahVarInExpressionStartTokenRE = cachedRegex(
+ escapeRegexChars(self.setting('cheetahVarStartToken'))
+ +r'(?=[A-Za-z_])'
+ )
+
+ self.expressionPlaceholderStartRE = cachedRegex(
+ escCharLookBehind +
+ r'(?P<startToken>' + escapeRegexChars(self.setting('cheetahVarStartToken')) + ')' +
+ r'(?P<cacheToken>' + cacheToken + ')' +
+ #r'\[[ \t\f]*'
+ r'(?:\{|\(|\[)[ \t\f]*'
+ + r'(?=[^\)\}\]])'
+ )
+
+ if self.setting('EOLSlurpToken'):
+ self.EOLSlurpRE = cachedRegex(
+ escapeRegexChars(self.setting('EOLSlurpToken'))
+ + r'[ \t\f]*'
+ + r'(?:'+EOL+')'
+ )
+ else:
+ self.EOLSlurpRE = None
+
+
+ def _makeCommentREs(self):
+ """Construct the regex bits that are used in comment parsing."""
+ startTokenEsc = escapeRegexChars(self.setting('commentStartToken'))
+ self.commentStartTokenRE = cachedRegex(escCharLookBehind + startTokenEsc)
+ del startTokenEsc
+
+ startTokenEsc = escapeRegexChars(
+ self.setting('multiLineCommentStartToken'))
+ endTokenEsc = escapeRegexChars(
+ self.setting('multiLineCommentEndToken'))
+ self.multiLineCommentTokenStartRE = cachedRegex(escCharLookBehind +
+ startTokenEsc)
+ self.multiLineCommentEndTokenRE = cachedRegex(escCharLookBehind +
+ endTokenEsc)
+
+ def _makeDirectiveREs(self):
+ """Construct the regexs that are used in directive parsing."""
+ startToken = self.setting('directiveStartToken')
+ endToken = self.setting('directiveEndToken')
+ startTokenEsc = escapeRegexChars(startToken)
+ endTokenEsc = escapeRegexChars(endToken)
+ validSecondCharsLookAhead = r'(?=[A-Za-z_@])'
+ reParts = [escCharLookBehind, startTokenEsc]
+ if self.setting('allowWhitespaceAfterDirectiveStartToken'):
+ reParts.append('[ \t]*')
+ reParts.append(validSecondCharsLookAhead)
+ self.directiveStartTokenRE = cachedRegex(''.join(reParts))
+ self.directiveEndTokenRE = cachedRegex(escCharLookBehind + endTokenEsc)
+
+ def _makePspREs(self):
+ """Setup the regexs for PSP parsing."""
+ startToken = self.setting('PSPStartToken')
+ startTokenEsc = escapeRegexChars(startToken)
+ self.PSPStartTokenRE = cachedRegex(escCharLookBehind + startTokenEsc)
+ endToken = self.setting('PSPEndToken')
+ endTokenEsc = escapeRegexChars(endToken)
+ self.PSPEndTokenRE = cachedRegex(escCharLookBehind + endTokenEsc)
+
+
+ def isLineClearToStartToken(self, pos=None):
+ return self.isLineClearToPos(pos)
+
+ def matchTopLevelToken(self):
+ """Returns the first match found from the following methods:
+ self.matchCommentStartToken
+ self.matchMultiLineCommentStartToken
+ self.matchVariablePlaceholderStart
+ self.matchExpressionPlaceholderStart
+ self.matchDirective
+ self.matchPSPStartToken
+ self.matchEOLSlurpToken
+
+ Returns None if no match.
+ """
+ match = None
+ if self.peek() in self._possibleNonStrConstantChars:
+ for matcher in self._nonStrConstMatchers:
+ match = matcher()
+ if match:
+ break
+ return match
+
+ def matchPyToken(self):
+ match = pseudoprog.match(self.src(), self.pos())
+
+ if match and match.group() in tripleQuotedStringStarts:
+ TQSmatch = tripleQuotedStringREs[match.group()].match(self.src(), self.pos())
+ if TQSmatch:
+ return TQSmatch
+ return match
+
+ def getPyToken(self):
+ match = self.matchPyToken()
+ if match is None:
+ raise ParseError(self)
+ elif match.group() in tripleQuotedStringStarts:
+ raise ParseError(self, msg='Malformed triple-quoted string')
+ return self.readTo(match.end())
+
+ def matchEOLSlurpToken(self):
+ if self.EOLSlurpRE:
+ return self.EOLSlurpRE.match(self.src(), self.pos())
+
+ def getEOLSlurpToken(self):
+ match = self.matchEOLSlurpToken()
+ if not match:
+ raise ParseError(self, msg='Invalid EOL slurp token')
+ return self.readTo(match.end())
+
+ def matchCommentStartToken(self):
+ return self.commentStartTokenRE.match(self.src(), self.pos())
+
+ def getCommentStartToken(self):
+ match = self.matchCommentStartToken()
+ if not match:
+ raise ParseError(self, msg='Invalid single-line comment start token')
+ return self.readTo(match.end())
+
+ def matchMultiLineCommentStartToken(self):
+ return self.multiLineCommentTokenStartRE.match(self.src(), self.pos())
+
+ def getMultiLineCommentStartToken(self):
+ match = self.matchMultiLineCommentStartToken()
+ if not match:
+ raise ParseError(self, msg='Invalid multi-line comment start token')
+ return self.readTo(match.end())
+
+ def matchMultiLineCommentEndToken(self):
+ return self.multiLineCommentEndTokenRE.match(self.src(), self.pos())
+
+ def getMultiLineCommentEndToken(self):
+ match = self.matchMultiLineCommentEndToken()
+ if not match:
+ raise ParseError(self, msg='Invalid multi-line comment end token')
+ return self.readTo(match.end())
+
+ def getDottedName(self):
+ srcLen = len(self)
+ nameChunks = []
+
+ if not self.peek() in identchars:
+ raise ParseError(self)
+
+ while self.pos() < srcLen:
+ c = self.peek()
+ if c in namechars:
+ nameChunk = self.getIdentifier()
+ nameChunks.append(nameChunk)
+ elif c == '.':
+ if self.pos()+1 <srcLen and self.peek(1) in identchars:
+ nameChunks.append(self.getc())
+ else:
+ break
+ else:
+ break
+
+ return ''.join(nameChunks)
+
+ def matchIdentifier(self):
+ return identRE.match(self.src(), self.pos())
+
+ def getIdentifier(self):
+ match = self.matchIdentifier()
+ if not match:
+ raise ParseError(self, msg='Invalid identifier')
+ return self.readTo(match.end())
+
+ def matchOperator(self):
+ match = self.matchPyToken()
+ if match and match.group() not in operators:
+ match = None
+ return match
+
+ def getOperator(self):
+ match = self.matchOperator()
+ if not match:
+ raise ParseError(self, msg='Expected operator')
+ return self.readTo( match.end() )
+
+ def matchAssignmentOperator(self):
+ match = self.matchPyToken()
+ if match and match.group() not in assignmentOps:
+ match = None
+ return match
+
+ def getAssignmentOperator(self):
+ match = self.matchAssignmentOperator()
+ if not match:
+ raise ParseError(self, msg='Expected assignment operator')
+ return self.readTo( match.end() )
+
+ def matchDirective(self):
+ """Returns False or the name of the directive matched.
+ """
+ startPos = self.pos()
+ if not self.matchDirectiveStartToken():
+ return False
+ self.getDirectiveStartToken()
+ directiveName = self.matchDirectiveName()
+ self.setPos(startPos)
+ return directiveName
+
+ def matchDirectiveName(self, directiveNameChars=identchars+'0123456789-@'):
+ startPos = self.pos()
+ possibleMatches = self._directiveNamesAndParsers.keys()
+ name = ''
+ match = None
+
+ while not self.atEnd():
+ c = self.getc()
+ if not c in directiveNameChars:
+ break
+ name += c
+ if name == '@':
+ if not self.atEnd() and self.peek() in identchars:
+ match = '@'
+ break
+ possibleMatches = [dn for dn in possibleMatches if dn.startswith(name)]
+ if not possibleMatches:
+ break
+ elif (name in possibleMatches and (self.atEnd() or self.peek() not in directiveNameChars)):
+ match = name
+ break
+
+ self.setPos(startPos)
+ return match
+
+ def matchDirectiveStartToken(self):
+ return self.directiveStartTokenRE.match(self.src(), self.pos())
+
+ def getDirectiveStartToken(self):
+ match = self.matchDirectiveStartToken()
+ if not match:
+ raise ParseError(self, msg='Invalid directive start token')
+ return self.readTo(match.end())
+
+ def matchDirectiveEndToken(self):
+ return self.directiveEndTokenRE.match(self.src(), self.pos())
+
+ def getDirectiveEndToken(self):
+ match = self.matchDirectiveEndToken()
+ if not match:
+ raise ParseError(self, msg='Invalid directive end token')
+ return self.readTo(match.end())
+
+
+ def matchColonForSingleLineShortFormDirective(self):
+ if not self.atEnd() and self.peek()==':':
+ restOfLine = self[self.pos()+1:self.findEOL()]
+ restOfLine = restOfLine.strip()
+ if not restOfLine:
+ return False
+ elif self.commentStartTokenRE.match(restOfLine):
+ return False
+ else: # non-whitespace, non-commment chars found
+ return True
+ return False
+
+ def matchPSPStartToken(self):
+ return self.PSPStartTokenRE.match(self.src(), self.pos())
+
+ def matchPSPEndToken(self):
+ return self.PSPEndTokenRE.match(self.src(), self.pos())
+
+ def getPSPStartToken(self):
+ match = self.matchPSPStartToken()
+ if not match:
+ raise ParseError(self, msg='Invalid psp start token')
+ return self.readTo(match.end())
+
+ def getPSPEndToken(self):
+ match = self.matchPSPEndToken()
+ if not match:
+ raise ParseError(self, msg='Invalid psp end token')
+ return self.readTo(match.end())
+
+ def matchCheetahVarStart(self):
+ """includes the enclosure and cache token"""
+ return self.cheetahVarStartRE.match(self.src(), self.pos())
+
+ def matchCheetahVarStartToken(self):
+ """includes the enclosure and cache token"""
+ return self.cheetahVarStartTokenRE.match(self.src(), self.pos())
+
+ def matchCheetahVarInExpressionStartToken(self):
+ """no enclosures or cache tokens allowed"""
+ return self.cheetahVarInExpressionStartTokenRE.match(self.src(), self.pos())
+
+ def matchVariablePlaceholderStart(self):
+ """includes the enclosure and cache token"""
+ return self.cheetahVarStartRE.match(self.src(), self.pos())
+
+ def matchExpressionPlaceholderStart(self):
+ """includes the enclosure and cache token"""
+ return self.expressionPlaceholderStartRE.match(self.src(), self.pos())
+
+ def getCheetahVarStartToken(self):
+ """just the start token, not the enclosure or cache token"""
+ match = self.matchCheetahVarStartToken()
+ if not match:
+ raise ParseError(self, msg='Expected Cheetah $var start token')
+ return self.readTo( match.end() )
+
+
+ def getCacheToken(self):
+ try:
+ token = self.cacheTokenRE.match(self.src(), self.pos())
+ self.setPos( token.end() )
+ return token.group()
+ except:
+ raise ParseError(self, msg='Expected cache token')
+
+ def getSilentPlaceholderToken(self):
+ try:
+ token = self.silentPlaceholderTokenRE.match(self.src(), self.pos())
+ self.setPos( token.end() )
+ return token.group()
+ except:
+ raise ParseError(self, msg='Expected silent placeholder token')
+
+
+
+ def getTargetVarsList(self):
+ varnames = []
+ while not self.atEnd():
+ if self.peek() in ' \t\f':
+ self.getWhiteSpace()
+ elif self.peek() in '\r\n':
+ break
+ elif self.startswith(','):
+ self.advance()
+ elif self.startswith('in ') or self.startswith('in\t'):
+ break
+ #elif self.matchCheetahVarStart():
+ elif self.matchCheetahVarInExpressionStartToken():
+ self.getCheetahVarStartToken()
+ self.getSilentPlaceholderToken()
+ self.getCacheToken()
+ varnames.append( self.getDottedName() )
+ elif self.matchIdentifier():
+ varnames.append( self.getDottedName() )
+ else:
+ break
+ return varnames
+
+ def getCheetahVar(self, plain=False, skipStartToken=False):
+ """This is called when parsing inside expressions. Cache tokens are only
+ valid in placeholders so this method discards any cache tokens found.
+ """
+ if not skipStartToken:
+ self.getCheetahVarStartToken()
+ self.getSilentPlaceholderToken()
+ self.getCacheToken()
+ return self.getCheetahVarBody(plain=plain)
+
+ def getCheetahVarBody(self, plain=False):
+ # @@TR: this should be in the compiler
+ return self._compiler.genCheetahVar(self.getCheetahVarNameChunks(), plain=plain)
+
+ def getCheetahVarNameChunks(self):
+
+ """
+ nameChunks = list of Cheetah $var subcomponents represented as tuples
+ [ (namemapperPart,autoCall,restOfName),
+ ]
+ where:
+ namemapperPart = the dottedName base
+ autocall = where NameMapper should use autocalling on namemapperPart
+ restOfName = any arglist, index, or slice
+
+ If restOfName contains a call arglist (e.g. '(1234)') then autocall is
+ False, otherwise it defaults to True.
+
+ EXAMPLE
+ ------------------------------------------------------------------------
+
+ if the raw CheetahVar is
+ $a.b.c[1].d().x.y.z
+
+ nameChunks is the list
+ [ ('a.b.c',True,'[1]'),
+ ('d',False,'()'),
+ ('x.y.z',True,''),
+ ]
+
+ """
+
+ chunks = []
+ while self.pos() < len(self):
+ rest = ''
+ autoCall = True
+ if not self.peek() in identchars + '.':
+ break
+ elif self.peek() == '.':
+
+ if self.pos()+1 < len(self) and self.peek(1) in identchars:
+ self.advance() # discard the period as it isn't needed with NameMapper
+ else:
+ break
+
+ dottedName = self.getDottedName()
+ if not self.atEnd() and self.peek() in '([':
+ if self.peek() == '(':
+ rest = self.getCallArgString()
+ else:
+ rest = self.getExpression(enclosed=True)
+
+ period = max(dottedName.rfind('.'), 0)
+ if period:
+ chunks.append( (dottedName[:period], autoCall, '') )
+ dottedName = dottedName[period+1:]
+ if rest and rest[0]=='(':
+ autoCall = False
+ chunks.append( (dottedName, autoCall, rest) )
+
+ return chunks
+
+
+ def getCallArgString(self,
+ enclosures=[], # list of tuples (char, pos), where char is ({ or [
+ useNameMapper=Unspecified):
+
+ """ Get a method/function call argument string.
+
+ This method understands *arg, and **kw
+ """
+
+ # @@TR: this settings mangling should be removed
+ if useNameMapper is not Unspecified:
+ useNameMapper_orig = self.setting('useNameMapper')
+ self.setSetting('useNameMapper', useNameMapper)
+
+ if enclosures:
+ pass
+ else:
+ if not self.peek() == '(':
+ raise ParseError(self, msg="Expected '('")
+ startPos = self.pos()
+ self.getc()
+ enclosures = [('(', startPos),
+ ]
+
+ argStringBits = ['(']
+ addBit = argStringBits.append
+
+ while 1:
+ if self.atEnd():
+ open = enclosures[-1][0]
+ close = closurePairsRev[open]
+ self.setPos(enclosures[-1][1])
+ raise ParseError(
+ self, msg="EOF was reached before a matching '" + close +
+ "' was found for the '" + open + "'")
+
+ c = self.peek()
+ if c in ")}]": # get the ending enclosure and break
+ if not enclosures:
+ raise ParseError(self)
+ c = self.getc()
+ open = closurePairs[c]
+ if enclosures[-1][0] == open:
+ enclosures.pop()
+ addBit(')')
+ break
+ else:
+ raise ParseError(self)
+ elif c in " \t\f\r\n":
+ addBit(self.getc())
+ elif self.matchCheetahVarInExpressionStartToken():
+ startPos = self.pos()
+ codeFor1stToken = self.getCheetahVar()
+ WS = self.getWhiteSpace()
+ if not self.atEnd() and self.peek() == '=':
+ nextToken = self.getPyToken()
+ if nextToken == '=':
+ endPos = self.pos()
+ self.setPos(startPos)
+ codeFor1stToken = self.getCheetahVar(plain=True)
+ self.setPos(endPos)
+
+ ## finally
+ addBit( codeFor1stToken + WS + nextToken )
+ else:
+ addBit( codeFor1stToken + WS)
+ elif self.matchCheetahVarStart():
+ # it has syntax that is only valid at the top level
+ self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
+ else:
+ beforeTokenPos = self.pos()
+ token = self.getPyToken()
+ if token in ('{','(','['):
+ self.rev()
+ token = self.getExpression(enclosed=True)
+ token = self.transformToken(token, beforeTokenPos)
+ addBit(token)
+
+ if useNameMapper is not Unspecified:
+ self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
+
+ return ''.join(argStringBits)
+
+ def getDefArgList(self, exitPos=None, useNameMapper=False):
+
+ """ Get an argument list. Can be used for method/function definition
+ argument lists or for #directive argument lists. Returns a list of
+ tuples in the form (argName, defVal=None) with one tuple for each arg
+ name.
+
+ These defVals are always strings, so (argName, defVal=None) is safe even
+ with a case like (arg1, arg2=None, arg3=1234*2), which would be returned as
+ [('arg1', None),
+ ('arg2', 'None'),
+ ('arg3', '1234*2'),
+ ]
+
+ This method understands *arg, and **kw
+
+ """
+
+ if self.peek() == '(':
+ self.advance()
+ else:
+ exitPos = self.findEOL() # it's a directive so break at the EOL
+ argList = ArgList()
+ onDefVal = False
+
+ # @@TR: this settings mangling should be removed
+ useNameMapper_orig = self.setting('useNameMapper')
+ self.setSetting('useNameMapper', useNameMapper)
+
+ while 1:
+ if self.atEnd():
+ raise ParseError(
+ self, msg="EOF was reached before a matching ')'"+
+ " was found for the '('")
+
+ if self.pos() == exitPos:
+ break
+
+ c = self.peek()
+ if c == ")" or self.matchDirectiveEndToken():
+ break
+ elif c == ":":
+ break
+ elif c in " \t\f\r\n":
+ if onDefVal:
+ argList.addToDefVal(c)
+ self.advance()
+ elif c == '=':
+ onDefVal = True
+ self.advance()
+ elif c == ",":
+ argList.next()
+ onDefVal = False
+ self.advance()
+ elif self.startswith(self.cheetahVarStartToken) and not onDefVal:
+ self.advance(len(self.cheetahVarStartToken))
+ elif self.matchIdentifier() and not onDefVal:
+ argList.addArgName( self.getIdentifier() )
+ elif onDefVal:
+ if self.matchCheetahVarInExpressionStartToken():
+ token = self.getCheetahVar()
+ elif self.matchCheetahVarStart():
+ # it has syntax that is only valid at the top level
+ self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
+ else:
+ beforeTokenPos = self.pos()
+ token = self.getPyToken()
+ if token in ('{','(','['):
+ self.rev()
+ token = self.getExpression(enclosed=True)
+ token = self.transformToken(token, beforeTokenPos)
+ argList.addToDefVal(token)
+ elif c == '*' and not onDefVal:
+ varName = self.getc()
+ if self.peek() == '*':
+ varName += self.getc()
+ if not self.matchIdentifier():
+ raise ParseError(self)
+ varName += self.getIdentifier()
+ argList.addArgName(varName)
+ else:
+ raise ParseError(self)
+
+
+ self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
+ return argList.merge()
+
+ def getExpressionParts(self,
+ enclosed=False,
+ enclosures=None, # list of tuples (char, pos), where char is ({ or [
+ pyTokensToBreakAt=None, # only works if not enclosed
+ useNameMapper=Unspecified,
+ ):
+
+ """ Get a Cheetah expression that includes $CheetahVars and break at
+ directive end tokens, the end of an enclosure, or at a specified
+ pyToken.
+ """
+
+ if useNameMapper is not Unspecified:
+ useNameMapper_orig = self.setting('useNameMapper')
+ self.setSetting('useNameMapper', useNameMapper)
+
+ if enclosures is None:
+ enclosures = []
+
+ srcLen = len(self)
+ exprBits = []
+ while 1:
+ if self.atEnd():
+ if enclosures:
+ open = enclosures[-1][0]
+ close = closurePairsRev[open]
+ self.setPos(enclosures[-1][1])
+ raise ParseError(
+ self, msg="EOF was reached before a matching '" + close +
+ "' was found for the '" + open + "'")
+ else:
+ break
+
+ c = self.peek()
+ if c in "{([":
+ exprBits.append(c)
+ enclosures.append( (c, self.pos()) )
+ self.advance()
+ elif enclosed and not enclosures:
+ break
+ elif c in "])}":
+ if not enclosures:
+ raise ParseError(self)
+ open = closurePairs[c]
+ if enclosures[-1][0] == open:
+ enclosures.pop()
+ exprBits.append(c)
+ else:
+ open = enclosures[-1][0]
+ close = closurePairsRev[open]
+ row, col = self.getRowCol()
+ self.setPos(enclosures[-1][1])
+ raise ParseError(
+ self, msg= "A '" + c + "' was found at line " + str(row) +
+ ", col " + str(col) +
+ " before a matching '" + close +
+ "' was found\nfor the '" + open + "'")
+ self.advance()
+
+ elif c in " \f\t":
+ exprBits.append(self.getWhiteSpace())
+ elif self.matchDirectiveEndToken() and not enclosures:
+ break
+ elif c == "\\" and self.pos()+1 < srcLen:
+ eolMatch = EOLre.match(self.src(), self.pos()+1)
+ if not eolMatch:
+ self.advance()
+ raise ParseError(self, msg='Line ending expected')
+ self.setPos( eolMatch.end() )
+ elif c in '\r\n':
+ if enclosures:
+ self.advance()
+ else:
+ break
+ elif self.matchCheetahVarInExpressionStartToken():
+ expr = self.getCheetahVar()
+ exprBits.append(expr)
+ elif self.matchCheetahVarStart():
+ # it has syntax that is only valid at the top level
+ self._raiseErrorAboutInvalidCheetahVarSyntaxInExpr()
+ else:
+ beforeTokenPos = self.pos()
+ token = self.getPyToken()
+ if (not enclosures
+ and pyTokensToBreakAt
+ and token in pyTokensToBreakAt):
+
+ self.setPos(beforeTokenPos)
+ break
+
+ token = self.transformToken(token, beforeTokenPos)
+
+ exprBits.append(token)
+ if identRE.match(token):
+ if token == 'for':
+ expr = self.getExpression(useNameMapper=False, pyTokensToBreakAt=['in'])
+ exprBits.append(expr)
+ else:
+ exprBits.append(self.getWhiteSpace())
+ if not self.atEnd() and self.peek() == '(':
+ exprBits.append(self.getCallArgString())
+ ##
+ if useNameMapper is not Unspecified:
+ self.setSetting('useNameMapper', useNameMapper_orig) # @@TR: see comment above
+ return exprBits
+
+ def getExpression(self,
+ enclosed=False,
+ enclosures=None, # list of tuples (char, pos), where # char is ({ or [
+ pyTokensToBreakAt=None,
+ useNameMapper=Unspecified,
+ ):
+ """Returns the output of self.getExpressionParts() as a concatenated
+ string rather than as a list.
+ """
+ return ''.join(self.getExpressionParts(
+ enclosed=enclosed, enclosures=enclosures,
+ pyTokensToBreakAt=pyTokensToBreakAt,
+ useNameMapper=useNameMapper))
+
+
+ def transformToken(self, token, beforeTokenPos):
+ """Takes a token from the expression being parsed and performs and
+ special transformations required by Cheetah.
+
+ At the moment only Cheetah's c'$placeholder strings' are transformed.
+ """
+ if token=='c' and not self.atEnd() and self.peek() in '\'"':
+ nextToken = self.getPyToken()
+ token = nextToken.upper()
+ theStr = eval(token)
+ endPos = self.pos()
+ if not theStr:
+ return
+
+ if token.startswith(single3) or token.startswith(double3):
+ startPosIdx = 3
+ else:
+ startPosIdx = 1
+ #print 'CHEETAH STRING', nextToken, theStr, startPosIdx
+ self.setPos(beforeTokenPos+startPosIdx+1)
+ outputExprs = []
+ strConst = ''
+ while self.pos() < (endPos-startPosIdx):
+ if self.matchCheetahVarStart() or self.matchExpressionPlaceholderStart():
+ if strConst:
+ outputExprs.append(repr(strConst))
+ strConst = ''
+ placeholderExpr = self.getPlaceholder()
+ outputExprs.append('str('+placeholderExpr+')')
+ else:
+ strConst += self.getc()
+ self.setPos(endPos)
+ if strConst:
+ outputExprs.append(repr(strConst))
+ #if not self.atEnd() and self.matches('.join('):
+ # print 'DEBUG***'
+ token = "''.join(["+','.join(outputExprs)+"])"
+ return token
+
+ def _raiseErrorAboutInvalidCheetahVarSyntaxInExpr(self):
+ match = self.matchCheetahVarStart()
+ groupdict = match.groupdict()
+ if groupdict.get('cacheToken'):
+ raise ParseError(
+ self,
+ msg='Cache tokens are not valid inside expressions. '
+ 'Use them in top-level $placeholders only.')
+ elif groupdict.get('enclosure'):
+ raise ParseError(
+ self,
+ msg='Long-form placeholders - ${}, $(), $[], etc. are not valid inside expressions. '
+ 'Use them in top-level $placeholders only.')
+ else:
+ raise ParseError(
+ self,
+ msg='This form of $placeholder syntax is not valid here.')
+
+
+ def getPlaceholder(self, allowCacheTokens=False, plain=False, returnEverything=False):
+ # filtered
+ for callback in self.setting('preparsePlaceholderHooks'):
+ callback(parser=self)
+
+ startPos = self.pos()
+ lineCol = self.getRowCol(startPos)
+ startToken = self.getCheetahVarStartToken()
+ silentPlaceholderToken = self.getSilentPlaceholderToken()
+ if silentPlaceholderToken:
+ isSilentPlaceholder = True
+ else:
+ isSilentPlaceholder = False
+
+
+ if allowCacheTokens:
+ cacheToken = self.getCacheToken()
+ cacheTokenParts = self.cacheTokenRE.match(cacheToken).groupdict()
+ else:
+ cacheTokenParts = {}
+
+ if self.peek() in '({[':
+ pos = self.pos()
+ enclosureOpenChar = self.getc()
+ enclosures = [ (enclosureOpenChar, pos) ]
+ self.getWhiteSpace()
+ else:
+ enclosures = []
+
+ filterArgs = None
+ if self.matchIdentifier():
+ nameChunks = self.getCheetahVarNameChunks()
+ expr = self._compiler.genCheetahVar(nameChunks[:], plain=plain)
+ restOfExpr = None
+ if enclosures:
+ WS = self.getWhiteSpace()
+ expr += WS
+ if self.setting('allowPlaceholderFilterArgs') and self.peek()==',':
+ filterArgs = self.getCallArgString(enclosures=enclosures)[1:-1]
+ else:
+ if self.peek()==closurePairsRev[enclosureOpenChar]:
+ self.getc()
+ else:
+ restOfExpr = self.getExpression(enclosed=True, enclosures=enclosures)
+ if restOfExpr[-1] == closurePairsRev[enclosureOpenChar]:
+ restOfExpr = restOfExpr[:-1]
+ expr += restOfExpr
+ rawPlaceholder = self[startPos: self.pos()]
+ else:
+ expr = self.getExpression(enclosed=True, enclosures=enclosures)
+ if expr[-1] == closurePairsRev[enclosureOpenChar]:
+ expr = expr[:-1]
+ rawPlaceholder=self[startPos: self.pos()]
+
+ expr = self._applyExpressionFilters(expr,'placeholder',
+ rawExpr=rawPlaceholder,startPos=startPos)
+ for callback in self.setting('postparsePlaceholderHooks'):
+ callback(parser=self)
+
+ if returnEverything:
+ return (expr, rawPlaceholder, lineCol, cacheTokenParts,
+ filterArgs, isSilentPlaceholder)
+ else:
+ return expr
+
+
+class _HighLevelParser(_LowLevelParser):
+ """This class is a StateMachine for parsing Cheetah source and
+ sending state dependent code generation commands to
+ Cheetah.Compiler.Compiler.
+ """
+ def __init__(self, src, filename=None, breakPoint=None, compiler=None):
+ _LowLevelParser.__init__(self, src, filename=filename, breakPoint=breakPoint)
+ self.setSettingsManager(compiler)
+ self._compiler = compiler
+ self.setupState()
+ self.configureParser()
+
+ def setupState(self):
+ self._macros = {}
+ self._macroDetails = {}
+ self._openDirectivesStack = []
+
+ def cleanup(self):
+ """Cleanup to remove any possible reference cycles
+ """
+ self._macros.clear()
+ for macroname, macroDetails in self._macroDetails.items():
+ macroDetails.template.shutdown()
+ del macroDetails.template
+ self._macroDetails.clear()
+
+ def configureParser(self):
+ _LowLevelParser.configureParser(self)
+ self._initDirectives()
+
+ def _initDirectives(self):
+ def normalizeParserVal(val):
+ if isinstance(val, (str,unicode)):
+ handler = getattr(self, val)
+ elif type(val) in (ClassType, TypeType):
+ handler = val(self)
+ elif callable(val):
+ handler = val
+ elif val is None:
+ handler = val
+ else:
+ raise Exception('Invalid parser/handler value %r for %s'%(val, name))
+ return handler
+
+ normalizeHandlerVal = normalizeParserVal
+
+ _directiveNamesAndParsers = directiveNamesAndParsers.copy()
+ customNamesAndParsers = self.setting('directiveNamesAndParsers',{})
+ _directiveNamesAndParsers.update(customNamesAndParsers)
+
+ _endDirectiveNamesAndHandlers = endDirectiveNamesAndHandlers.copy()
+ customNamesAndHandlers = self.setting('endDirectiveNamesAndHandlers',{})
+ _endDirectiveNamesAndHandlers.update(customNamesAndHandlers)
+
+ self._directiveNamesAndParsers = {}
+ for name, val in _directiveNamesAndParsers.items():
+ if val in (False, 0):
+ continue
+ self._directiveNamesAndParsers[name] = normalizeParserVal(val)
+
+ self._endDirectiveNamesAndHandlers = {}
+ for name, val in _endDirectiveNamesAndHandlers.items():
+ if val in (False, 0):
+ continue
+ self._endDirectiveNamesAndHandlers[name] = normalizeHandlerVal(val)
+
+ self._closeableDirectives = ['def','block','closure','defmacro',
+ 'call',
+ 'capture',
+ 'cache',
+ 'filter',
+ 'if','unless',
+ 'for','while','repeat',
+ 'try',
+ ]
+ for directiveName in self.setting('closeableDirectives',[]):
+ self._closeableDirectives.append(directiveName)
+
+
+
+ macroDirectives = self.setting('macroDirectives',{})
+ macroDirectives['i18n'] = I18n
+
+
+ for macroName, callback in macroDirectives.items():
+ if type(callback) in (ClassType, TypeType):
+ callback = callback(parser=self)
+ assert callback
+ self._macros[macroName] = callback
+ self._directiveNamesAndParsers[macroName] = self.eatMacroCall
+
+ def _applyExpressionFilters(self, expr, exprType, rawExpr=None, startPos=None):
+ """Pipes cheetah expressions through a set of optional filter hooks.
+
+ The filters are functions which may modify the expressions or raise
+ a ForbiddenExpression exception if the expression is not allowed. They
+ are defined in the compiler setting 'expressionFilterHooks'.
+
+ Some intended use cases:
+
+ - to implement 'restricted execution' safeguards in cases where you
+ can't trust the author of the template.
+
+ - to enforce style guidelines
+
+ filter call signature: (parser, expr, exprType, rawExpr=None, startPos=None)
+ - parser is the Cheetah parser
+ - expr is the expression to filter. In some cases the parser will have
+ already modified it from the original source code form. For example,
+ placeholders will have been translated into namemapper calls. If you
+ need to work with the original source, see rawExpr.
+ - exprType is the name of the directive, 'psp', or 'placeholder'. All
+ lowercase. @@TR: These will eventually be replaced with a set of
+ constants.
+ - rawExpr is the original source string that Cheetah parsed. This
+ might be None in some cases.
+ - startPos is the character position in the source string/file
+ where the parser started parsing the current expression.
+
+ @@TR: I realize this use of the term 'expression' is a bit wonky as many
+ of the 'expressions' are actually statements, but I haven't thought of
+ a better name yet. Suggestions?
+ """
+ for callback in self.setting('expressionFilterHooks'):
+ expr = callback(parser=self, expr=expr, exprType=exprType,
+ rawExpr=rawExpr, startPos=startPos)
+ return expr
+
+ def _filterDisabledDirectives(self, directiveName):
+ directiveName = directiveName.lower()
+ if (directiveName in self.setting('disabledDirectives')
+ or (self.setting('enabledDirectives')
+ and directiveName not in self.setting('enabledDirectives'))):
+ for callback in self.setting('disabledDirectiveHooks'):
+ callback(parser=self, directiveName=directiveName)
+ raise ForbiddenDirective(self, msg='This %r directive is disabled'%directiveName)
+
+ ## main parse loop
+
+ def parse(self, breakPoint=None, assertEmptyStack=True):
+ if breakPoint:
+ origBP = self.breakPoint()
+ self.setBreakPoint(breakPoint)
+ assertEmptyStack = False
+
+ while not self.atEnd():
+ if self.matchCommentStartToken():
+ self.eatComment()
+ elif self.matchMultiLineCommentStartToken():
+ self.eatMultiLineComment()
+ elif self.matchVariablePlaceholderStart():
+ self.eatPlaceholder()
+ elif self.matchExpressionPlaceholderStart():
+ self.eatPlaceholder()
+ elif self.matchDirective():
+ self.eatDirective()
+ elif self.matchPSPStartToken():
+ self.eatPSP()
+ elif self.matchEOLSlurpToken():
+ self.eatEOLSlurpToken()
+ else:
+ self.eatPlainText()
+ if assertEmptyStack:
+ self.assertEmptyOpenDirectivesStack()
+ if breakPoint:
+ self.setBreakPoint(origBP)
+
+ ## non-directive eat methods
+
+ def eatPlainText(self):
+ startPos = self.pos()
+ match = None
+ while not self.atEnd():
+ match = self.matchTopLevelToken()
+ if match:
+ break
+ else:
+ self.advance()
+ strConst = self.readTo(self.pos(), start=startPos)
+ self._compiler.addStrConst(strConst)
+ return match
+
+ def eatComment(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ if isLineClearToStartToken:
+ self._compiler.handleWSBeforeDirective()
+ self.getCommentStartToken()
+ comm = self.readToEOL(gobble=isLineClearToStartToken)
+ self._compiler.addComment(comm)
+
+ def eatMultiLineComment(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+
+ self.getMultiLineCommentStartToken()
+ endPos = startPos = self.pos()
+ level = 1
+ while 1:
+ endPos = self.pos()
+ if self.atEnd():
+ break
+ if self.matchMultiLineCommentStartToken():
+ self.getMultiLineCommentStartToken()
+ level += 1
+ elif self.matchMultiLineCommentEndToken():
+ self.getMultiLineCommentEndToken()
+ level -= 1
+ if not level:
+ break
+ self.advance()
+ comm = self.readTo(endPos, start=startPos)
+
+ if not self.atEnd():
+ self.getMultiLineCommentEndToken()
+
+ if (not self.atEnd()) and self.setting('gobbleWhitespaceAroundMultiLineComments'):
+ restOfLine = self[self.pos():self.findEOL()]
+ if not restOfLine.strip(): # WS only to EOL
+ self.readToEOL(gobble=isLineClearToStartToken)
+
+ if isLineClearToStartToken and (self.atEnd() or self.pos() > endOfFirstLine):
+ self._compiler.handleWSBeforeDirective()
+
+ self._compiler.addComment(comm)
+
+ def eatPlaceholder(self):
+ (expr, rawPlaceholder,
+ lineCol, cacheTokenParts,
+ filterArgs, isSilentPlaceholder) = self.getPlaceholder(
+ allowCacheTokens=True, returnEverything=True)
+
+ self._compiler.addPlaceholder(
+ expr,
+ filterArgs=filterArgs,
+ rawPlaceholder=rawPlaceholder,
+ cacheTokenParts=cacheTokenParts,
+ lineCol=lineCol,
+ silentMode=isSilentPlaceholder)
+ return
+
+ def eatPSP(self):
+ # filtered
+ self._filterDisabledDirectives(directiveName='psp')
+ self.getPSPStartToken()
+ endToken = self.setting('PSPEndToken')
+ startPos = self.pos()
+ while not self.atEnd():
+ if self.peek() == endToken[0]:
+ if self.matchPSPEndToken():
+ break
+ self.advance()
+ pspString = self.readTo(self.pos(), start=startPos).strip()
+ pspString = self._applyExpressionFilters(pspString, 'psp', startPos=startPos)
+ self._compiler.addPSP(pspString)
+ self.getPSPEndToken()
+
+ ## generic directive eat methods
+ _simpleIndentingDirectives = '''
+ else elif for while repeat unless try except finally'''.split()
+ _simpleExprDirectives = '''
+ pass continue stop return yield break
+ del assert raise
+ silent echo
+ import from'''.split()
+ _directiveHandlerNames = {'import':'addImportStatement',
+ 'from':'addImportStatement', }
+ def eatDirective(self):
+ directiveName = self.matchDirective()
+ self._filterDisabledDirectives(directiveName)
+
+ for callback in self.setting('preparseDirectiveHooks'):
+ callback(parser=self, directiveName=directiveName)
+
+ # subclasses can override the default behaviours here by providing an
+ # eater method in self._directiveNamesAndParsers[directiveName]
+ directiveParser = self._directiveNamesAndParsers.get(directiveName)
+ if directiveParser:
+ directiveParser()
+ elif directiveName in self._simpleIndentingDirectives:
+ handlerName = self._directiveHandlerNames.get(directiveName)
+ if not handlerName:
+ handlerName = 'add'+directiveName.capitalize()
+ handler = getattr(self._compiler, handlerName)
+ self.eatSimpleIndentingDirective(directiveName, callback=handler)
+ elif directiveName in self._simpleExprDirectives:
+ handlerName = self._directiveHandlerNames.get(directiveName)
+ if not handlerName:
+ handlerName = 'add'+directiveName.capitalize()
+ handler = getattr(self._compiler, handlerName)
+ if directiveName in ('silent', 'echo'):
+ includeDirectiveNameInExpr = False
+ else:
+ includeDirectiveNameInExpr = True
+ expr = self.eatSimpleExprDirective(
+ directiveName,
+ includeDirectiveNameInExpr=includeDirectiveNameInExpr)
+ handler(expr)
+ ##
+ for callback in self.setting('postparseDirectiveHooks'):
+ callback(parser=self, directiveName=directiveName)
+
+ def _eatRestOfDirectiveTag(self, isLineClearToStartToken, endOfFirstLinePos):
+ foundComment = False
+ if self.matchCommentStartToken():
+ pos = self.pos()
+ self.advance()
+ if not self.matchDirective():
+ self.setPos(pos)
+ foundComment = True
+ self.eatComment() # this won't gobble the EOL
+ else:
+ self.setPos(pos)
+
+ if not foundComment and self.matchDirectiveEndToken():
+ self.getDirectiveEndToken()
+ elif isLineClearToStartToken and (not self.atEnd()) and self.peek() in '\r\n':
+ # still gobble the EOL if a comment was found.
+ self.readToEOL(gobble=True)
+
+ if isLineClearToStartToken and (self.atEnd() or self.pos() > endOfFirstLinePos):
+ self._compiler.handleWSBeforeDirective()
+
+ def _eatToThisEndDirective(self, directiveName):
+ finalPos = endRawPos = startPos = self.pos()
+ directiveChar = self.setting('directiveStartToken')[0]
+ isLineClearToStartToken = False
+ while not self.atEnd():
+ if self.peek() == directiveChar:
+ if self.matchDirective() == 'end':
+ endRawPos = self.pos()
+ self.getDirectiveStartToken()
+ self.advance(len('end'))
+ self.getWhiteSpace()
+ if self.startswith(directiveName):
+ if self.isLineClearToStartToken(endRawPos):
+ isLineClearToStartToken = True
+ endRawPos = self.findBOL(endRawPos)
+ self.advance(len(directiveName)) # to end of directiveName
+ self.getWhiteSpace()
+ finalPos = self.pos()
+ break
+ self.advance()
+ finalPos = endRawPos = self.pos()
+
+ textEaten = self.readTo(endRawPos, start=startPos)
+ self.setPos(finalPos)
+
+ endOfFirstLinePos = self.findEOL()
+
+ if self.matchDirectiveEndToken():
+ self.getDirectiveEndToken()
+ elif isLineClearToStartToken and (not self.atEnd()) and self.peek() in '\r\n':
+ self.readToEOL(gobble=True)
+
+ if isLineClearToStartToken and self.pos() > endOfFirstLinePos:
+ self._compiler.handleWSBeforeDirective()
+ return textEaten
+
+
+ def eatSimpleExprDirective(self, directiveName, includeDirectiveNameInExpr=True):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ if not includeDirectiveNameInExpr:
+ self.advance(len(directiveName))
+ startPos = self.pos()
+ expr = self.getExpression().strip()
+ directiveName = expr.split()[0]
+ expr = self._applyExpressionFilters(expr, directiveName, startPos=startPos)
+ if directiveName in self._closeableDirectives:
+ self.pushToOpenDirectivesStack(directiveName)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ return expr
+
+ def eatSimpleIndentingDirective(self, directiveName, callback,
+ includeDirectiveNameInExpr=False):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ lineCol = self.getRowCol()
+ self.getDirectiveStartToken()
+ if directiveName not in 'else elif for while try except finally'.split():
+ self.advance(len(directiveName))
+ startPos = self.pos()
+
+ self.getWhiteSpace()
+
+ expr = self.getExpression(pyTokensToBreakAt=[':'])
+ expr = self._applyExpressionFilters(expr, directiveName, startPos=startPos)
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ if directiveName in 'else elif except finally'.split():
+ callback(expr, dedent=False, lineCol=lineCol)
+ else:
+ callback(expr, lineCol=lineCol)
+
+ self.getWhiteSpace(max=1)
+ self.parse(breakPoint=self.findEOL(gobble=True))
+ self._compiler.commitStrConst()
+ self._compiler.dedent()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ if directiveName in self._closeableDirectives:
+ self.pushToOpenDirectivesStack(directiveName)
+ callback(expr, lineCol=lineCol)
+
+ def eatEndDirective(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ self.getDirectiveStartToken()
+ self.advance(3) # to end of 'end'
+ self.getWhiteSpace()
+ pos = self.pos()
+ directiveName = False
+ for key in self._endDirectiveNamesAndHandlers.keys():
+ if self.find(key, pos) == pos:
+ directiveName = key
+ break
+ if not directiveName:
+ raise ParseError(self, msg='Invalid end directive')
+
+ endOfFirstLinePos = self.findEOL()
+ self.getExpression() # eat in any extra comment-like crap
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ if directiveName in self._closeableDirectives:
+ self.popFromOpenDirectivesStack(directiveName)
+
+ # subclasses can override the default behaviours here by providing an
+ # end-directive handler in self._endDirectiveNamesAndHandlers[directiveName]
+ if self._endDirectiveNamesAndHandlers.get(directiveName):
+ handler = self._endDirectiveNamesAndHandlers[directiveName]
+ handler()
+ elif directiveName in 'block capture cache call filter errorCatcher'.split():
+ if key == 'block':
+ self._compiler.closeBlock()
+ elif key == 'capture':
+ self._compiler.endCaptureRegion()
+ elif key == 'cache':
+ self._compiler.endCacheRegion()
+ elif key == 'call':
+ self._compiler.endCallRegion()
+ elif key == 'filter':
+ self._compiler.closeFilterBlock()
+ elif key == 'errorCatcher':
+ self._compiler.turnErrorCatcherOff()
+ elif directiveName in 'while for if try repeat unless'.split():
+ self._compiler.commitStrConst()
+ self._compiler.dedent()
+ elif directiveName=='closure':
+ self._compiler.commitStrConst()
+ self._compiler.dedent()
+ # @@TR: temporary hack of useSearchList
+ self.setSetting('useSearchList', self._useSearchList_orig)
+
+ ## specific directive eat methods
+
+ def eatBreakPoint(self):
+ """Tells the parser to stop parsing at this point and completely ignore
+ everything else.
+
+ This is a debugging tool.
+ """
+ self.setBreakPoint(self.pos())
+
+ def eatShbang(self):
+ # filtered
+ self.getDirectiveStartToken()
+ self.advance(len('shBang'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ shBang = self.readToEOL()
+ shBang = self._applyExpressionFilters(shBang, 'shbang', startPos=startPos)
+ self._compiler.setShBang(shBang.strip())
+
+ def eatEncoding(self):
+ # filtered
+ self.getDirectiveStartToken()
+ self.advance(len('encoding'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ encoding = self.readToEOL()
+ encoding = self._applyExpressionFilters(encoding, 'encoding', startPos=startPos)
+ self._compiler.setModuleEncoding(encoding.strip())
+
+ def eatCompiler(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ startPos = self.pos()
+ self.getDirectiveStartToken()
+ self.advance(len('compiler')) # to end of 'compiler'
+ self.getWhiteSpace()
+
+ startPos = self.pos()
+ settingName = self.getIdentifier()
+
+ if settingName.lower() == 'reset':
+ self.getExpression() # gobble whitespace & junk
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ self._initializeSettings()
+ self.configureParser()
+ return
+
+ self.getWhiteSpace()
+ if self.peek() == '=':
+ self.advance()
+ else:
+ raise ParseError(self)
+ valueExpr = self.getExpression()
+ endPos = self.pos()
+
+ # @@TR: it's unlikely that anyone apply filters would have left this
+ # directive enabled:
+ # @@TR: fix up filtering, regardless
+ self._applyExpressionFilters('%s=%r'%(settingName, valueExpr),
+ 'compiler', startPos=startPos)
+
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ try:
+ self._compiler.setCompilerSetting(settingName, valueExpr)
+ except:
+ out = sys.stderr
+ print >> out, 'An error occurred while processing the following #compiler directive.'
+ print >> out, '-'*80
+ print >> out, self[startPos:endPos]
+ print >> out, '-'*80
+ print >> out, 'Please check the syntax of these settings.'
+ print >> out, 'A full Python exception traceback follows.'
+ raise
+
+
+ def eatCompilerSettings(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('compiler-settings')) # to end of 'settings'
+
+ keywords = self.getTargetVarsList()
+ self.getExpression() # gobble any garbage
+
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+
+ if 'reset' in keywords:
+ self._compiler._initializeSettings()
+ self.configureParser()
+ # @@TR: this implies a single-line #compiler-settings directive, and
+ # thus we should parse forward for an end directive.
+ # Subject to change in the future
+ return
+ startPos = self.pos()
+ settingsStr = self._eatToThisEndDirective('compiler-settings')
+ settingsStr = self._applyExpressionFilters(settingsStr, 'compilerSettings',
+ startPos=startPos)
+ try:
+ self._compiler.setCompilerSettings(keywords=keywords, settingsStr=settingsStr)
+ except:
+ out = sys.stderr
+ print >> out, 'An error occurred while processing the following compiler settings.'
+ print >> out, '-'*80
+ print >> out, settingsStr.strip()
+ print >> out, '-'*80
+ print >> out, 'Please check the syntax of these settings.'
+ print >> out, 'A full Python exception traceback follows.'
+ raise
+
+ def eatAttr(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ startPos = self.pos()
+ self.getDirectiveStartToken()
+ self.advance(len('attr'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ if self.matchCheetahVarStart():
+ self.getCheetahVarStartToken()
+ attribName = self.getIdentifier()
+ self.getWhiteSpace()
+ self.getAssignmentOperator()
+ expr = self.getExpression()
+ expr = self._applyExpressionFilters(expr, 'attr', startPos=startPos)
+ self._compiler.addAttribute(attribName, expr)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+
+ def eatDecorator(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ startPos = self.pos()
+ self.getDirectiveStartToken()
+ #self.advance() # eat @
+ startPos = self.pos()
+ decoratorExpr = self.getExpression()
+ decoratorExpr = self._applyExpressionFilters(decoratorExpr, 'decorator', startPos=startPos)
+ self._compiler.addDecorator(decoratorExpr)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self.getWhiteSpace()
+
+ directiveName = self.matchDirective()
+ if not directiveName or directiveName not in ('def', 'block', 'closure', '@'):
+ raise ParseError(
+ self, msg='Expected #def, #block, #closure or another @decorator')
+ self.eatDirective()
+
+ def eatDef(self):
+ # filtered
+ self._eatDefOrBlock('def')
+
+ def eatBlock(self):
+ # filtered
+ startPos = self.pos()
+ methodName, rawSignature = self._eatDefOrBlock('block')
+ self._compiler._blockMetaData[methodName] = {
+ 'raw':rawSignature,
+ 'lineCol':self.getRowCol(startPos),
+ }
+
+ def eatClosure(self):
+ # filtered
+ self._eatDefOrBlock('closure')
+
+ def _eatDefOrBlock(self, directiveName):
+ # filtered
+ assert directiveName in ('def','block','closure')
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ startPos = self.pos()
+ self.getDirectiveStartToken()
+ self.advance(len(directiveName))
+ self.getWhiteSpace()
+ if self.matchCheetahVarStart():
+ self.getCheetahVarStartToken()
+ methodName = self.getIdentifier()
+ self.getWhiteSpace()
+ if self.peek() == '(':
+ argsList = self.getDefArgList()
+ self.advance() # past the closing ')'
+ if argsList and argsList[0][0] == 'self':
+ del argsList[0]
+ else:
+ argsList=[]
+
+ def includeBlockMarkers():
+ if self.setting('includeBlockMarkers'):
+ startMarker = self.setting('blockMarkerStart')
+ self._compiler.addStrConst(startMarker[0] + methodName + startMarker[1])
+
+ # @@TR: fix up filtering
+ self._applyExpressionFilters(self[startPos:self.pos()], 'def', startPos=startPos)
+
+ if self.matchColonForSingleLineShortFormDirective():
+ isNestedDef = (self.setting('allowNestedDefScopes')
+ and [name for name in self._openDirectivesStack if name=='def'])
+ self.getc()
+ rawSignature = self[startPos:endOfFirstLinePos]
+ self._eatSingleLineDef(directiveName=directiveName,
+ methodName=methodName,
+ argsList=argsList,
+ startPos=startPos,
+ endPos=endOfFirstLinePos)
+ if directiveName == 'def' and not isNestedDef:
+ #@@TR: must come before _eatRestOfDirectiveTag ... for some reason
+ self._compiler.closeDef()
+ elif directiveName == 'block':
+ includeBlockMarkers()
+ self._compiler.closeBlock()
+ elif directiveName == 'closure' or isNestedDef:
+ self._compiler.dedent()
+
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ else:
+ if self.peek()==':':
+ self.getc()
+ self.pushToOpenDirectivesStack(directiveName)
+ rawSignature = self[startPos:self.pos()]
+ self._eatMultiLineDef(directiveName=directiveName,
+ methodName=methodName,
+ argsList=argsList,
+ startPos=startPos,
+ isLineClearToStartToken=isLineClearToStartToken)
+ if directiveName == 'block':
+ includeBlockMarkers()
+
+ return methodName, rawSignature
+
+ def _eatMultiLineDef(self, directiveName, methodName, argsList, startPos,
+ isLineClearToStartToken=False):
+ # filtered in calling method
+ self.getExpression() # slurp up any garbage left at the end
+ signature = self[startPos:self.pos()]
+ endOfFirstLinePos = self.findEOL()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ signature = ' '.join([line.strip() for line in signature.splitlines()])
+ parserComment = ('## CHEETAH: generated from ' + signature +
+ ' at line %s, col %s' % self.getRowCol(startPos)
+ + '.')
+
+ isNestedDef = (self.setting('allowNestedDefScopes')
+ and len([name for name in self._openDirectivesStack if name=='def'])>1)
+ if directiveName=='block' or (directiveName=='def' and not isNestedDef):
+ self._compiler.startMethodDef(methodName, argsList, parserComment)
+ else: #closure
+ self._useSearchList_orig = self.setting('useSearchList')
+ self.setSetting('useSearchList', False)
+ self._compiler.addClosure(methodName, argsList, parserComment)
+
+ return methodName
+
+ def _eatSingleLineDef(self, directiveName, methodName, argsList, startPos, endPos):
+ # filtered in calling method
+ fullSignature = self[startPos:endPos]
+ parserComment = ('## Generated from ' + fullSignature +
+ ' at line %s, col %s' % self.getRowCol(startPos)
+ + '.')
+ isNestedDef = (self.setting('allowNestedDefScopes')
+ and [name for name in self._openDirectivesStack if name=='def'])
+ if directiveName=='block' or (directiveName=='def' and not isNestedDef):
+ self._compiler.startMethodDef(methodName, argsList, parserComment)
+ else: #closure
+ # @@TR: temporary hack of useSearchList
+ useSearchList_orig = self.setting('useSearchList')
+ self.setSetting('useSearchList', False)
+ self._compiler.addClosure(methodName, argsList, parserComment)
+
+ self.getWhiteSpace(max=1)
+ self.parse(breakPoint=endPos)
+ if directiveName=='closure' or isNestedDef: # @@TR: temporary hack of useSearchList
+ self.setSetting('useSearchList', useSearchList_orig)
+
+ def eatExtends(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('extends'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ if self.setting('allowExpressionsInExtendsDirective'):
+ baseName = self.getExpression()
+ else:
+ baseName = self.getDottedName()
+
+ baseName = self._applyExpressionFilters(baseName, 'extends', startPos=startPos)
+ self._compiler.setBaseClass(baseName) # in compiler
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+
+ def eatImplements(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('implements'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ methodName = self.getIdentifier()
+ if not self.atEnd() and self.peek() == '(':
+ argsList = self.getDefArgList()
+ self.advance() # past the closing ')'
+ if argsList and argsList[0][0] == 'self':
+ del argsList[0]
+ else:
+ argsList=[]
+
+ # @@TR: need to split up filtering of the methodname and the args
+ #methodName = self._applyExpressionFilters(methodName, 'implements', startPos=startPos)
+ self._applyExpressionFilters(self[startPos:self.pos()], 'implements', startPos=startPos)
+
+ self._compiler.setMainMethodName(methodName)
+ self._compiler.setMainMethodArgs(argsList)
+
+ self.getExpression() # throw away and unwanted crap that got added in
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+
+ def eatSuper(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('super'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ if not self.atEnd() and self.peek() == '(':
+ argsList = self.getDefArgList()
+ self.advance() # past the closing ')'
+ if argsList and argsList[0][0] == 'self':
+ del argsList[0]
+ else:
+ argsList=[]
+
+ self._applyExpressionFilters(self[startPos:self.pos()], 'super', startPos=startPos)
+
+ #parserComment = ('## CHEETAH: generated from ' + signature +
+ # ' at line %s, col %s' % self.getRowCol(startPos)
+ # + '.')
+
+ self.getExpression() # throw away and unwanted crap that got added in
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ self._compiler.addSuper(argsList)
+
+ def eatSet(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(3)
+ self.getWhiteSpace()
+ style = SET_LOCAL
+ if self.startswith('local'):
+ self.getIdentifier()
+ self.getWhiteSpace()
+ elif self.startswith('global'):
+ self.getIdentifier()
+ self.getWhiteSpace()
+ style = SET_GLOBAL
+ elif self.startswith('module'):
+ self.getIdentifier()
+ self.getWhiteSpace()
+ style = SET_MODULE
+
+ startsWithDollar = self.matchCheetahVarStart()
+ startPos = self.pos()
+ LVALUE = self.getExpression(pyTokensToBreakAt=assignmentOps, useNameMapper=False).strip()
+ OP = self.getAssignmentOperator()
+ RVALUE = self.getExpression()
+ expr = LVALUE + ' ' + OP + ' ' + RVALUE.strip()
+
+ expr = self._applyExpressionFilters(expr, 'set', startPos=startPos)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+
+ class Components: pass # used for 'set global'
+ exprComponents = Components()
+ exprComponents.LVALUE = LVALUE
+ exprComponents.OP = OP
+ exprComponents.RVALUE = RVALUE
+ self._compiler.addSet(expr, exprComponents, style)
+
+ def eatSlurp(self):
+ if self.isLineClearToStartToken():
+ self._compiler.handleWSBeforeDirective()
+ self._compiler.commitStrConst()
+ self.readToEOL(gobble=True)
+
+ def eatEOLSlurpToken(self):
+ if self.isLineClearToStartToken():
+ self._compiler.handleWSBeforeDirective()
+ self._compiler.commitStrConst()
+ self.readToEOL(gobble=True)
+
+ def eatRaw(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('raw'))
+ self.getWhiteSpace()
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self.getWhiteSpace(max=1)
+ rawBlock = self.readToEOL(gobble=False)
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ rawBlock = self._eatToThisEndDirective('raw')
+ self._compiler.addRawText(rawBlock)
+
+ def eatInclude(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('include'))
+
+ self.getWhiteSpace()
+ includeFrom = 'file'
+ isRaw = False
+ if self.startswith('raw'):
+ self.advance(3)
+ isRaw=True
+
+ self.getWhiteSpace()
+ if self.startswith('source'):
+ self.advance(len('source'))
+ includeFrom = 'str'
+ self.getWhiteSpace()
+ if not self.peek() == '=':
+ raise ParseError(self)
+ self.advance()
+ startPos = self.pos()
+ sourceExpr = self.getExpression()
+ sourceExpr = self._applyExpressionFilters(sourceExpr, 'include', startPos=startPos)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self._compiler.addInclude(sourceExpr, includeFrom, isRaw)
+
+
+ def eatDefMacro(self):
+ # @@TR: not filtered yet
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('defmacro'))
+
+ self.getWhiteSpace()
+ if self.matchCheetahVarStart():
+ self.getCheetahVarStartToken()
+ macroName = self.getIdentifier()
+ self.getWhiteSpace()
+ if self.peek() == '(':
+ argsList = self.getDefArgList(useNameMapper=False)
+ self.advance() # past the closing ')'
+ if argsList and argsList[0][0] == 'self':
+ del argsList[0]
+ else:
+ argsList=[]
+
+ assert not self._directiveNamesAndParsers.has_key(macroName)
+ argsList.insert(0, ('src',None))
+ argsList.append(('parser','None'))
+ argsList.append(('macros','None'))
+ argsList.append(('compilerSettings','None'))
+ argsList.append(('isShortForm','None'))
+ argsList.append(('EOLCharsInShortForm','None'))
+ argsList.append(('startPos','None'))
+ argsList.append(('endPos','None'))
+
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self.getWhiteSpace(max=1)
+ macroSrc = self.readToEOL(gobble=False)
+ self.readToEOL(gobble=True)
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ macroSrc = self._eatToThisEndDirective('defmacro')
+
+ #print argsList
+ normalizedMacroSrc = ''.join(
+ ['%def callMacro('+','.join([defv and '%s=%s'%(n,defv) or n
+ for n,defv in argsList])
+ +')\n',
+ macroSrc,
+ '%end def'])
+
+
+ from Cheetah.Template import Template
+ templateAPIClass = self.setting('templateAPIClassForDefMacro', default=Template)
+ compilerSettings = self.setting('compilerSettingsForDefMacro', default={})
+ searchListForMacros = self.setting('searchListForDefMacro', default=[])
+ searchListForMacros = list(searchListForMacros) # copy to avoid mutation bugs
+ searchListForMacros.append({'macros':self._macros,
+ 'parser':self,
+ 'compilerSettings':self.settings(),
+ })
+
+ templateAPIClass._updateSettingsWithPreprocessTokens(
+ compilerSettings, placeholderToken='@', directiveToken='%')
+ macroTemplateClass = templateAPIClass.compile(source=normalizedMacroSrc,
+ compilerSettings=compilerSettings)
+ #print normalizedMacroSrc
+ #t = macroTemplateClass()
+ #print t.callMacro('src')
+ #print t.generatedClassCode()
+
+ class MacroDetails: pass
+ macroDetails = MacroDetails()
+ macroDetails.macroSrc = macroSrc
+ macroDetails.argsList = argsList
+ macroDetails.template = macroTemplateClass(searchList=searchListForMacros)
+
+ self._macroDetails[macroName] = macroDetails
+ self._macros[macroName] = macroDetails.template.callMacro
+ self._directiveNamesAndParsers[macroName] = self.eatMacroCall
+
+ def eatMacroCall(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ startPos = self.pos()
+ self.getDirectiveStartToken()
+ macroName = self.getIdentifier()
+ macro = self._macros[macroName]
+ if hasattr(macro, 'parse'):
+ return macro.parse(parser=self, startPos=startPos)
+
+ if hasattr(macro, 'parseArgs'):
+ args = macro.parseArgs(parser=self, startPos=startPos)
+ else:
+ self.getWhiteSpace()
+ args = self.getExpression(useNameMapper=False,
+ pyTokensToBreakAt=[':']).strip()
+
+ if self.matchColonForSingleLineShortFormDirective():
+ isShortForm = True
+ self.advance() # skip over :
+ self.getWhiteSpace(max=1)
+ srcBlock = self.readToEOL(gobble=False)
+ EOLCharsInShortForm = self.readToEOL(gobble=True)
+ #self.readToEOL(gobble=False)
+ else:
+ isShortForm = False
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ srcBlock = self._eatToThisEndDirective(macroName)
+
+
+ if hasattr(macro, 'convertArgStrToDict'):
+ kwArgs = macro.convertArgStrToDict(args, parser=self, startPos=startPos)
+ else:
+ def getArgs(*pargs, **kws):
+ return pargs, kws
+ exec 'positionalArgs, kwArgs = getArgs(%(args)s)'%locals()
+
+ assert not kwArgs.has_key('src')
+ kwArgs['src'] = srcBlock
+
+ if type(macro)==new.instancemethod:
+ co = macro.im_func.func_code
+ elif (hasattr(macro, '__call__')
+ and hasattr(macro.__call__, 'im_func')):
+ co = macro.__call__.im_func.func_code
+ else:
+ co = macro.func_code
+ availableKwArgs = inspect.getargs(co)[0]
+
+ if 'parser' in availableKwArgs:
+ kwArgs['parser'] = self
+ if 'macros' in availableKwArgs:
+ kwArgs['macros'] = self._macros
+ if 'compilerSettings' in availableKwArgs:
+ kwArgs['compilerSettings'] = self.settings()
+ if 'isShortForm' in availableKwArgs:
+ kwArgs['isShortForm'] = isShortForm
+ if isShortForm and 'EOLCharsInShortForm' in availableKwArgs:
+ kwArgs['EOLCharsInShortForm'] = EOLCharsInShortForm
+
+ if 'startPos' in availableKwArgs:
+ kwArgs['startPos'] = startPos
+ if 'endPos' in availableKwArgs:
+ kwArgs['endPos'] = self.pos()
+
+ srcFromMacroOutput = macro(**kwArgs)
+
+ origParseSrc = self._src
+ origBreakPoint = self.breakPoint()
+ origPos = self.pos()
+ # add a comment to the output about the macro src that is being parsed
+ # or add a comment prefix to all the comments added by the compiler
+ self._src = srcFromMacroOutput
+ self.setPos(0)
+ self.setBreakPoint(len(srcFromMacroOutput))
+
+ self.parse(assertEmptyStack=False)
+
+ self._src = origParseSrc
+ self.setBreakPoint(origBreakPoint)
+ self.setPos(origPos)
+
+
+ #self._compiler.addRawText('end')
+
+ def eatCache(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ lineCol = self.getRowCol()
+ self.getDirectiveStartToken()
+ self.advance(len('cache'))
+
+ startPos = self.pos()
+ argList = self.getDefArgList(useNameMapper=True)
+ argList = self._applyExpressionFilters(argList, 'cache', startPos=startPos)
+
+ def startCache():
+ cacheInfo = self._compiler.genCacheInfoFromArgList(argList)
+ self._compiler.startCacheRegion(cacheInfo, lineCol)
+
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self.getWhiteSpace(max=1)
+ startCache()
+ self.parse(breakPoint=self.findEOL(gobble=True))
+ self._compiler.endCacheRegion()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self.pushToOpenDirectivesStack('cache')
+ startCache()
+
+ def eatCall(self):
+ # @@TR: need to enable single line version of this
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ lineCol = self.getRowCol()
+ self.getDirectiveStartToken()
+ self.advance(len('call'))
+ startPos = self.pos()
+
+ useAutocallingOrig = self.setting('useAutocalling')
+ self.setSetting('useAutocalling', False)
+ self.getWhiteSpace()
+ if self.matchCheetahVarStart():
+ functionName = self.getCheetahVar()
+ else:
+ functionName = self.getCheetahVar(plain=True, skipStartToken=True)
+ self.setSetting('useAutocalling', useAutocallingOrig)
+ # @@TR: fix up filtering
+ self._applyExpressionFilters(self[startPos:self.pos()], 'call', startPos=startPos)
+
+ self.getWhiteSpace()
+ args = self.getExpression(pyTokensToBreakAt=[':']).strip()
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self._compiler.startCallRegion(functionName, args, lineCol)
+ self.getWhiteSpace(max=1)
+ self.parse(breakPoint=self.findEOL(gobble=False))
+ self._compiler.endCallRegion()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self.pushToOpenDirectivesStack("call")
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self._compiler.startCallRegion(functionName, args, lineCol)
+
+ def eatCallArg(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ lineCol = self.getRowCol()
+ self.getDirectiveStartToken()
+
+ self.advance(len('arg'))
+ startPos = self.pos()
+ self.getWhiteSpace()
+ argName = self.getIdentifier()
+ self.getWhiteSpace()
+ argName = self._applyExpressionFilters(argName, 'arg', startPos=startPos)
+ self._compiler.setCallArg(argName, lineCol)
+ if self.peek() == ':':
+ self.getc()
+ else:
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+
+ def eatFilter(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+
+ self.getDirectiveStartToken()
+ self.advance(len('filter'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ if self.matchCheetahVarStart():
+ isKlass = True
+ theFilter = self.getExpression(pyTokensToBreakAt=[':'])
+ else:
+ isKlass = False
+ theFilter = self.getIdentifier()
+ self.getWhiteSpace()
+ theFilter = self._applyExpressionFilters(theFilter, 'filter', startPos=startPos)
+
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self.getWhiteSpace(max=1)
+ self._compiler.setFilter(theFilter, isKlass)
+ self.parse(breakPoint=self.findEOL(gobble=False))
+ self._compiler.closeFilterBlock()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self.pushToOpenDirectivesStack("filter")
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self._compiler.setFilter(theFilter, isKlass)
+
+ def eatTransform(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+
+ self.getDirectiveStartToken()
+ self.advance(len('transform'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ if self.matchCheetahVarStart():
+ isKlass = True
+ transformer = self.getExpression(pyTokensToBreakAt=[':'])
+ else:
+ isKlass = False
+ transformer = self.getIdentifier()
+ self.getWhiteSpace()
+ transformer = self._applyExpressionFilters(transformer, 'transform', startPos=startPos)
+
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self._compiler.setTransform(transformer, isKlass)
+
+
+ def eatErrorCatcher(self):
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ self.getDirectiveStartToken()
+ self.advance(len('errorCatcher'))
+ self.getWhiteSpace()
+ startPos = self.pos()
+ errorCatcherName = self.getIdentifier()
+ errorCatcherName = self._applyExpressionFilters(
+ errorCatcherName, 'errorcatcher', startPos=startPos)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self._compiler.setErrorCatcher(errorCatcherName)
+
+ def eatCapture(self):
+ # @@TR: this could be refactored to use the code in eatSimpleIndentingDirective
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLinePos = self.findEOL()
+ lineCol = self.getRowCol()
+
+ self.getDirectiveStartToken()
+ self.advance(len('capture'))
+ startPos = self.pos()
+ self.getWhiteSpace()
+
+ expr = self.getExpression(pyTokensToBreakAt=[':'])
+ expr = self._applyExpressionFilters(expr, 'capture', startPos=startPos)
+ if self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self._compiler.startCaptureRegion(assignTo=expr, lineCol=lineCol)
+ self.getWhiteSpace(max=1)
+ self.parse(breakPoint=self.findEOL(gobble=False))
+ self._compiler.endCaptureRegion()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
+ self.pushToOpenDirectivesStack("capture")
+ self._compiler.startCaptureRegion(assignTo=expr, lineCol=lineCol)
+
+
+ def eatIf(self):
+ # filtered
+ isLineClearToStartToken = self.isLineClearToStartToken()
+ endOfFirstLine = self.findEOL()
+ lineCol = self.getRowCol()
+ self.getDirectiveStartToken()
+ startPos = self.pos()
+
+ expressionParts = self.getExpressionParts(pyTokensToBreakAt=[':'])
+ expr = ''.join(expressionParts).strip()
+ expr = self._applyExpressionFilters(expr, 'if', startPos=startPos)
+
+ isTernaryExpr = ('then' in expressionParts and 'else' in expressionParts)
+ if isTernaryExpr:
+ conditionExpr = []
+ trueExpr = []
+ falseExpr = []
+ currentExpr = conditionExpr
+ for part in expressionParts:
+ if part.strip()=='then':
+ currentExpr = trueExpr
+ elif part.strip()=='else':
+ currentExpr = falseExpr
+ else:
+ currentExpr.append(part)
+
+ conditionExpr = ''.join(conditionExpr)
+ trueExpr = ''.join(trueExpr)
+ falseExpr = ''.join(falseExpr)
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ self._compiler.addTernaryExpr(conditionExpr, trueExpr, falseExpr, lineCol=lineCol)
+ elif self.matchColonForSingleLineShortFormDirective():
+ self.advance() # skip over :
+ self._compiler.addIf(expr, lineCol=lineCol)
+ self.getWhiteSpace(max=1)
+ self.parse(breakPoint=self.findEOL(gobble=True))
+ self._compiler.commitStrConst()
+ self._compiler.dedent()
+ else:
+ if self.peek()==':':
+ self.advance()
+ self.getWhiteSpace()
+ self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
+ self.pushToOpenDirectivesStack('if')
+ self._compiler.addIf(expr, lineCol=lineCol)
+
+ ## end directive handlers
+ def handleEndDef(self):
+ isNestedDef = (self.setting('allowNestedDefScopes')
+ and [name for name in self._openDirectivesStack if name=='def'])
+ if not isNestedDef:
+ self._compiler.closeDef()
+ else:
+ # @@TR: temporary hack of useSearchList
+ self.setSetting('useSearchList', self._useSearchList_orig)
+ self._compiler.commitStrConst()
+ self._compiler.dedent()
+ ###
+
+ def pushToOpenDirectivesStack(self, directiveName):
+ assert directiveName in self._closeableDirectives
+ self._openDirectivesStack.append(directiveName)
+
+ def popFromOpenDirectivesStack(self, directiveName):
+ if not self._openDirectivesStack:
+ raise ParseError(self, msg="#end found, but nothing to end")
+
+ if self._openDirectivesStack[-1] == directiveName:
+ del self._openDirectivesStack[-1]
+ else:
+ raise ParseError(self, msg="#end %s found, expected #end %s" %(
+ directiveName, self._openDirectivesStack[-1]))
+
+ def assertEmptyOpenDirectivesStack(self):
+ if self._openDirectivesStack:
+ errorMsg = (
+ "Some #directives are missing their corresponding #end ___ tag: %s" %(
+ ', '.join(self._openDirectivesStack)))
+ raise ParseError(self, msg=errorMsg)
+
+##################################################
+## Make an alias to export
+Parser = _HighLevelParser
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Servlet.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Servlet.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Servlet.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+'''
+Provides an abstract Servlet baseclass for Cheetah's Template class
+'''
+
+import sys
+import os.path
+
+isWebwareInstalled = False
+try:
+ try:
+ from ds.appserver.Servlet import Servlet as BaseServlet
+ except:
+ from WebKit.Servlet import Servlet as BaseServlet
+ isWebwareInstalled = True
+
+ if not issubclass(BaseServlet, object):
+ class NewStyleBaseServlet(BaseServlet, object):
+ pass
+ BaseServlet = NewStyleBaseServlet
+except:
+ class BaseServlet(object):
+ _reusable = 1
+ _threadSafe = 0
+
+ def awake(self, transaction):
+ pass
+
+ def sleep(self, transaction):
+ pass
+
+ def shutdown(self):
+ pass
+
+##################################################
+## CLASSES
+
+class Servlet(BaseServlet):
+
+ """This class is an abstract baseclass for Cheetah.Template.Template.
+
+ It wraps WebKit.Servlet and provides a few extra convenience methods that
+ are also found in WebKit.Page. It doesn't do any of the HTTP method
+ resolution that is done in WebKit.HTTPServlet
+ """
+
+ transaction = None
+ application = None
+ request = None
+ session = None
+
+ def __init__(self, *args, **kwargs):
+ super(Servlet, self).__init__(*args, **kwargs)
+
+ # this default will be changed by the .awake() method
+ self._CHEETAH__isControlledByWebKit = False
+
+ ## methods called by Webware during the request-response
+
+ def awake(self, transaction):
+ super(Servlet, self).awake(transaction)
+
+ # a hack to signify that the servlet is being run directly from WebKit
+ self._CHEETAH__isControlledByWebKit = True
+
+ self.transaction = transaction
+ #self.application = transaction.application
+ self.response = response = transaction.response
+ self.request = transaction.request
+
+ # Temporary hack to accomodate bug in
+ # WebKit.Servlet.Servlet.serverSidePath: it uses
+ # self._request even though this attribute does not exist.
+ # This attribute WILL disappear in the future.
+ self._request = transaction.request()
+
+
+ self.session = transaction.session
+ self.write = response().write
+ #self.writeln = response.writeln
+
+ def respond(self, trans=None):
+ raise NotImplementedError("""\
+couldn't find the template's main method. If you are using #extends
+without #implements, try adding '#implements respond' to your template
+definition.""")
+
+ def sleep(self, transaction):
+ super(Servlet, self).sleep(transaction)
+ self.session = None
+ self.request = None
+ self._request = None
+ self.response = None
+ self.transaction = None
+
+ def shutdown(self):
+ pass
+
+ def serverSidePath(self, path=None,
+ normpath=os.path.normpath,
+ abspath=os.path.abspath
+ ):
+
+ if self._CHEETAH__isControlledByWebKit:
+ return super(Servlet, self).serverSidePath(path)
+ elif path:
+ return normpath(abspath(path.replace("\\",'/')))
+ elif hasattr(self, '_filePath') and self._filePath:
+ return normpath(abspath(self._filePath))
+ else:
+ return None
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SettingsManager.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SettingsManager.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SettingsManager.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,320 @@
+"""Provides a mixin/base class for collecting and managing application settings
+
+Meta-Data
+==========
+Author: Tavis Rudd <tavis at damnsimple.com>
+Version: $Revision: 1.30 $
+Start Date: 2001/05/30
+Last Revision Date: $Date: 2008/02/14 03:03:16 $
+"""
+
+# $Id: SettingsManager.py,v 1.30 2008/02/14 03:03:16 tavis_rudd Exp $
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.30 $"[11:-2]
+
+import sys
+import os.path
+import copy as copyModule
+from ConfigParser import ConfigParser
+import re
+from tokenize import Intnumber, Floatnumber, Number
+from types import *
+import types
+import new
+import time
+from StringIO import StringIO # not cStringIO because of unicode support
+import imp # used by SettingsManager.updateSettingsFromPySrcFile()
+
+##################################################
+## CONSTANTS & GLOBALS ##
+
+try:
+ True,False
+except NameError:
+ True, False = (1==1),(1==0)
+
+numberRE = re.compile(Number)
+complexNumberRE = re.compile('[\(]*' +Number + r'[ \t]*\+[ \t]*' + Number + '[\)]*')
+
+convertableToStrTypes = (StringType, IntType, FloatType,
+ LongType, ComplexType, NoneType,
+ UnicodeType)
+
+##################################################
+## FUNCTIONS ##
+
+def mergeNestedDictionaries(dict1, dict2, copy=False, deepcopy=False):
+ """Recursively merge the values of dict2 into dict1.
+
+ This little function is very handy for selectively overriding settings in a
+ settings dictionary that has a nested structure.
+ """
+
+ if copy:
+ dict1 = copyModule.copy(dict1)
+ elif deepcopy:
+ dict1 = copyModule.deepcopy(dict1)
+
+ for key,val in dict2.items():
+ if dict1.has_key(key) and type(val) == types.DictType and \
+ type(dict1[key]) == types.DictType:
+
+ dict1[key] = mergeNestedDictionaries(dict1[key], val)
+ else:
+ dict1[key] = val
+ return dict1
+
+def stringIsNumber(S):
+ """Return True if theString represents a Python number, False otherwise.
+ This also works for complex numbers and numbers with +/- in front."""
+
+ S = S.strip()
+
+ if S[0] in '-+' and len(S) > 1:
+ S = S[1:].strip()
+
+ match = complexNumberRE.match(S)
+ if not match:
+ match = numberRE.match(S)
+ if not match or (match.end() != len(S)):
+ return False
+ else:
+ return True
+
+def convStringToNum(theString):
+ """Convert a string representation of a Python number to the Python version"""
+
+ if not stringIsNumber(theString):
+ raise Error(theString + ' cannot be converted to a Python number')
+ return eval(theString, {}, {})
+
+
+##################################################
+## CLASSES ##
+
+class Error(Exception):
+ pass
+
+class NoDefault:
+ pass
+
+class ConfigParserCaseSensitive(ConfigParser):
+ """A case sensitive version of the standard Python ConfigParser."""
+
+ def optionxform(self, optionstr):
+ """Don't change the case as is done in the default implemenation."""
+ return optionstr
+
+class _SettingsCollector:
+ """An abstract base class that provides the methods SettingsManager uses to
+ collect settings from config files and strings.
+
+ This class only collects settings it doesn't modify the _settings dictionary
+ of SettingsManager instances in any way.
+ """
+
+ _ConfigParserClass = ConfigParserCaseSensitive
+
+ def __init__(self):
+ pass
+
+ def readSettingsFromModule(self, mod, ignoreUnderscored=True):
+ """Returns all settings from a Python module.
+ """
+ S = {}
+ attrs = vars(mod)
+ for k, v in attrs.items():
+ if (ignoreUnderscored and k.startswith('_')):
+ continue
+ else:
+ S[k] = v
+ return S
+
+ def readSettingsFromPySrcStr(self, theString):
+ """Return a dictionary of the settings in a Python src string."""
+
+ globalsDict = {'True':(1==1),
+ 'False':(0==1),
+ }
+ newSettings = {'self':self}
+ exec (theString+os.linesep) in globalsDict, newSettings
+ del newSettings['self']
+ module = new.module('temp_settings_module')
+ module.__dict__.update(newSettings)
+ return self.readSettingsFromModule(module)
+
+ def readSettingsFromConfigFileObj(self, inFile, convert=True):
+ """Return the settings from a config file that uses the syntax accepted by
+ Python's standard ConfigParser module (like Windows .ini files).
+
+ NOTE:
+ this method maintains case unlike the ConfigParser module, unless this
+ class was initialized with the 'caseSensitive' keyword set to False.
+
+ All setting values are initially parsed as strings. However, If the
+ 'convert' arg is True this method will do the following value
+ conversions:
+
+ * all Python numeric literals will be coverted from string to number
+
+ * The string 'None' will be converted to the Python value None
+
+ * The string 'True' will be converted to a Python truth value
+
+ * The string 'False' will be converted to a Python false value
+
+ * Any string starting with 'python:' will be treated as a Python literal
+ or expression that needs to be eval'd. This approach is useful for
+ declaring lists and dictionaries.
+
+ If a config section titled 'Globals' is present the options defined
+ under it will be treated as top-level settings.
+ """
+
+ p = self._ConfigParserClass()
+ p.readfp(inFile)
+ sects = p.sections()
+ newSettings = {}
+
+ sects = p.sections()
+ newSettings = {}
+
+ for s in sects:
+ newSettings[s] = {}
+ for o in p.options(s):
+ if o != '__name__':
+ newSettings[s][o] = p.get(s,o)
+
+ ## loop through new settings -> deal with global settings, numbers,
+ ## booleans and None ++ also deal with 'importSettings' commands
+
+ for sect, subDict in newSettings.items():
+ for key, val in subDict.items():
+ if convert:
+ if val.lower().startswith('python:'):
+ subDict[key] = eval(val[7:],{},{})
+ if val.lower() == 'none':
+ subDict[key] = None
+ if val.lower() == 'true':
+ subDict[key] = True
+ if val.lower() == 'false':
+ subDict[key] = False
+ if stringIsNumber(val):
+ subDict[key] = convStringToNum(val)
+
+ ## now deal with any 'importSettings' commands
+ if key.lower() == 'importsettings':
+ if val.find(';') < 0:
+ importedSettings = self.readSettingsFromPySrcFile(val)
+ else:
+ path = val.split(';')[0]
+ rest = ''.join(val.split(';')[1:]).strip()
+ parentDict = self.readSettingsFromPySrcFile(path)
+ importedSettings = eval('parentDict["' + rest + '"]')
+
+ subDict.update(mergeNestedDictionaries(subDict,
+ importedSettings))
+
+ if sect.lower() == 'globals':
+ newSettings.update(newSettings[sect])
+ del newSettings[sect]
+
+ return newSettings
+
+
+class SettingsManager(_SettingsCollector):
+ """A mixin class that provides facilities for managing application settings.
+
+ SettingsManager is designed to work well with nested settings dictionaries
+ of any depth.
+ """
+
+ def __init__(self):
+ """MUST BE CALLED BY SUBCLASSES"""
+ _SettingsCollector.__init__(self)
+ self._settings = {}
+ self._initializeSettings()
+
+ def _defaultSettings(self):
+ return {}
+
+ def _initializeSettings(self):
+ """A hook that allows for complex setting initialization sequences that
+ involve references to 'self' or other settings. For example:
+ self._settings['myCalcVal'] = self._settings['someVal'] * 15
+ This method should be called by the class' __init__() method when needed.
+ The dummy implementation should be reimplemented by subclasses.
+ """
+
+ pass
+
+ ## core post startup methods
+
+ def setting(self, name, default=NoDefault):
+ """Get a setting from self._settings, with or without a default value."""
+
+ if default is NoDefault:
+ return self._settings[name]
+ else:
+ return self._settings.get(name, default)
+
+
+ def hasSetting(self, key):
+ """True/False"""
+ return key in self._settings
+
+ def setSetting(self, name, value):
+ """Set a setting in self._settings."""
+ self._settings[name] = value
+
+ def settings(self):
+ """Return a reference to the settings dictionary"""
+ return self._settings
+
+ def copySettings(self):
+ """Returns a shallow copy of the settings dictionary"""
+ return copyModule.copy(self._settings)
+
+ def deepcopySettings(self):
+ """Returns a deep copy of the settings dictionary"""
+ return copyModule.deepcopy(self._settings)
+
+ def updateSettings(self, newSettings, merge=True):
+ """Update the settings with a selective merge or a complete overwrite."""
+
+ if merge:
+ mergeNestedDictionaries(self._settings, newSettings)
+ else:
+ self._settings.update(newSettings)
+
+
+ ## source specific update methods
+
+ def updateSettingsFromPySrcStr(self, theString, merge=True):
+ """Update the settings from a code in a Python src string."""
+
+ newSettings = self.readSettingsFromPySrcStr(theString)
+ self.updateSettings(newSettings,
+ merge=newSettings.get('mergeSettings',merge) )
+
+
+ def updateSettingsFromConfigFileObj(self, inFile, convert=True, merge=True):
+ """See the docstring for .updateSettingsFromConfigFile()
+
+ The caller of this method is responsible for closing the inFile file
+ object."""
+
+ newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert)
+ self.updateSettings(newSettings,
+ merge=newSettings.get('mergeSettings',merge))
+
+ def updateSettingsFromConfigStr(self, configStr, convert=True, merge=True):
+ """See the docstring for .updateSettingsFromConfigFile()
+ """
+
+ configStr = '[globals]\n' + configStr
+ inFile = StringIO(configStr)
+ newSettings = self.readSettingsFromConfigFileObj(inFile, convert=convert)
+ self.updateSettings(newSettings,
+ merge=newSettings.get('mergeSettings',merge))
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SourceReader.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SourceReader.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/SourceReader.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,304 @@
+#!/usr/bin/env python
+# $Id: SourceReader.py,v 1.15 2007/04/03 01:57:42 tavis_rudd Exp $
+"""SourceReader class for Cheetah's Parser and CodeGenerator
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.15 $
+Start Date: 2001/09/19
+Last Revision Date: $Date: 2007/04/03 01:57:42 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.15 $"[11:-2]
+
+import re
+import sys
+
+EOLre = re.compile(r'[ \f\t]*(?:\r\n|\r|\n)')
+EOLZre = re.compile(r'(?:\r\n|\r|\n|\Z)')
+ENCODINGsearch = re.compile("coding[=:]\s*([-\w.]+)").search
+
+class Error(Exception):
+ pass
+
+class SourceReader:
+ def __init__(self, src, filename=None, breakPoint=None, encoding=None):
+
+ ## @@TR 2005-01-17: the following comes from a patch Terrel Shumway
+ ## contributed to add unicode support to the reading of Cheetah source
+ ## files with dynamically compiled templates. All the existing unit
+ ## tests pass but, it needs more testing and some test cases of its
+ ## own. My instinct is to move this up into the code that passes in the
+ ## src string rather than leaving it here. As implemented here it
+ ## forces all src strings to unicode, which IMO is not what we want.
+ # if encoding is None:
+ # # peek at the encoding in the first two lines
+ # m = EOLZre.search(src)
+ # pos = m.end()
+ # if pos<len(src):
+ # m = EOLZre.search(src,pos)
+ # pos = m.end()
+ # m = ENCODINGsearch(src,0,pos)
+ # if m:
+ # encoding = m.group(1)
+ # else:
+ # encoding = sys.getfilesystemencoding()
+ # self._encoding = encoding
+ # if type(src) is not unicode:
+ # src = src.decode(encoding)
+ ## end of Terrel's patch
+
+ self._src = src
+ self._filename = filename
+
+ self._srcLen = len(src)
+ if breakPoint == None:
+ self._breakPoint = self._srcLen
+ else:
+ self.setBreakPoint(breakPoint)
+ self._pos = 0
+ self._bookmarks = {}
+ self._posTobookmarkMap = {}
+
+ ## collect some meta-information
+ self._EOLs = []
+ pos = 0
+ while pos < len(self):
+ EOLmatch = EOLZre.search(src, pos)
+ self._EOLs.append(EOLmatch.start())
+ pos = EOLmatch.end()
+
+ self._BOLs = []
+ for pos in self._EOLs:
+ BOLpos = self.findBOL(pos)
+ self._BOLs.append(BOLpos)
+
+ def src(self):
+ return self._src
+
+ def filename(self):
+ return self._filename
+
+ def __len__(self):
+ return self._breakPoint
+
+ def __getitem__(self, i):
+ self.checkPos(i)
+ return self._src[i]
+
+ def __getslice__(self, i, j):
+ i = max(i, 0); j = max(j, 0)
+ return self._src[i:j]
+
+ def splitlines(self):
+ if not hasattr(self, '_srcLines'):
+ self._srcLines = self._src.splitlines()
+ return self._srcLines
+
+ def lineNum(self, pos=None):
+ if pos == None:
+ pos = self._pos
+
+ for i in range(len(self._BOLs)):
+ if pos >= self._BOLs[i] and pos <= self._EOLs[i]:
+ return i
+
+ def getRowCol(self, pos=None):
+ if pos == None:
+ pos = self._pos
+ lineNum = self.lineNum(pos)
+ BOL, EOL = self._BOLs[lineNum], self._EOLs[lineNum]
+ return lineNum+1, pos-BOL+1
+
+ def getRowColLine(self, pos=None):
+ if pos == None:
+ pos = self._pos
+ row, col = self.getRowCol(pos)
+ return row, col, self.splitlines()[row-1]
+
+ def getLine(self, pos):
+ if pos == None:
+ pos = self._pos
+ lineNum = self.lineNum(pos)
+ return self.splitlines()[lineNum]
+
+ def pos(self):
+ return self._pos
+
+ def setPos(self, pos):
+ self.checkPos(pos)
+ self._pos = pos
+
+
+ def validPos(self, pos):
+ return pos <= self._breakPoint and pos >=0
+
+ def checkPos(self, pos):
+ if not pos <= self._breakPoint:
+ raise Error("pos (" + str(pos) + ") is invalid: beyond the stream's end (" +
+ str(self._breakPoint-1) + ")" )
+ elif not pos >=0:
+ raise Error("pos (" + str(pos) + ") is invalid: less than 0" )
+
+ def breakPoint(self):
+ return self._breakPoint
+
+ def setBreakPoint(self, pos):
+ if pos > self._srcLen:
+ raise Error("New breakpoint (" + str(pos) +
+ ") is invalid: beyond the end of stream's source string (" +
+ str(self._srcLen) + ")" )
+ elif not pos >= 0:
+ raise Error("New breakpoint (" + str(pos) + ") is invalid: less than 0" )
+
+ self._breakPoint = pos
+
+ def setBookmark(self, name):
+ self._bookmarks[name] = self._pos
+ self._posTobookmarkMap[self._pos] = name
+
+ def hasBookmark(self, name):
+ return self._bookmarks.has_key(name)
+
+ def gotoBookmark(self, name):
+ if not self.hasBookmark(name):
+ raise Error("Invalid bookmark (" + name + ") is invalid: does not exist")
+ pos = self._bookmarks[name]
+ if not self.validPos(pos):
+ raise Error("Invalid bookmark (" + name + ', '+
+ str(pos) + ") is invalid: pos is out of range" )
+ self._pos = pos
+
+ def atEnd(self):
+ return self._pos >= self._breakPoint
+
+ def atStart(self):
+ return self._pos == 0
+
+ def peek(self, offset=0):
+ self.checkPos(self._pos+offset)
+ pos = self._pos + offset
+ return self._src[pos]
+
+ def getc(self):
+ pos = self._pos
+ if self.validPos(pos+1):
+ self._pos += 1
+ return self._src[pos]
+
+ def ungetc(self, c=None):
+ if not self.atStart():
+ raise Error('Already at beginning of stream')
+
+ self._pos -= 1
+ if not c==None:
+ self._src[self._pos] = c
+
+ def advance(self, offset=1):
+ self.checkPos(self._pos + offset)
+ self._pos += offset
+
+ def rev(self, offset=1):
+ self.checkPos(self._pos - offset)
+ self._pos -= offset
+
+ def read(self, offset):
+ self.checkPos(self._pos + offset)
+ start = self._pos
+ self._pos += offset
+ return self._src[start:self._pos]
+
+ def readTo(self, to, start=None):
+ self.checkPos(to)
+ if start == None:
+ start = self._pos
+ self._pos = to
+ return self._src[start:to]
+
+
+ def readToEOL(self, start=None, gobble=True):
+ EOLmatch = EOLZre.search(self.src(), self.pos())
+ if gobble:
+ pos = EOLmatch.end()
+ else:
+ pos = EOLmatch.start()
+ return self.readTo(to=pos, start=start)
+
+
+ def find(self, it, pos=None):
+ if pos == None:
+ pos = self._pos
+ return self._src.find(it, pos )
+
+ def startswith(self, it, pos=None):
+ if self.find(it, pos) == self.pos():
+ return True
+ else:
+ return False
+
+ def rfind(self, it, pos):
+ if pos == None:
+ pos = self._pos
+ return self._src.rfind(it, pos)
+
+ def findBOL(self, pos=None):
+ if pos == None:
+ pos = self._pos
+ src = self.src()
+ return max(src.rfind('\n',0,pos)+1, src.rfind('\r',0,pos)+1, 0)
+
+ def findEOL(self, pos=None, gobble=False):
+ if pos == None:
+ pos = self._pos
+
+ match = EOLZre.search(self.src(), pos)
+ if gobble:
+ return match.end()
+ else:
+ return match.start()
+
+ def isLineClearToPos(self, pos=None):
+ if pos == None:
+ pos = self.pos()
+ self.checkPos(pos)
+ src = self.src()
+ BOL = self.findBOL()
+ return BOL == pos or src[BOL:pos].isspace()
+
+ def matches(self, strOrRE):
+ if isinstance(strOrRE, (str, unicode)):
+ return self.startswith(strOrRE, pos=self.pos())
+ else: # assume an re object
+ return strOrRE.match(self.src(), self.pos())
+
+ def matchWhiteSpace(self, WSchars=' \f\t'):
+ return (not self.atEnd()) and self.peek() in WSchars
+
+ def getWhiteSpace(self, max=None, WSchars=' \f\t'):
+ if not self.matchWhiteSpace(WSchars):
+ return ''
+ start = self.pos()
+ breakPoint = self.breakPoint()
+ if max is not None:
+ breakPoint = min(breakPoint, self.pos()+max)
+ while self.pos() < breakPoint:
+ self.advance()
+ if not self.matchWhiteSpace(WSchars):
+ break
+ return self.src()[start:self.pos()]
+
+ def matchNonWhiteSpace(self, WSchars=' \f\t\n\r'):
+ return self.atEnd() or not self.peek() in WSchars
+
+ def getNonWhiteSpace(self, WSchars=' \f\t\n\r'):
+ if not self.matchNonWhiteSpace(WSchars):
+ return ''
+ start = self.pos()
+ while self.pos() < self.breakPoint():
+ self.advance()
+ if not self.matchNonWhiteSpace(WSchars):
+ break
+ return self.src()[start:self.pos()]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Template.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Template.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Template.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1899 @@
+#!/usr/bin/env python
+'''
+Provides the core API for Cheetah.
+
+See the docstring in the Template class and the Users' Guide for more information
+'''
+
+################################################################################
+## DEPENDENCIES
+import sys # used in the error handling code
+import re # used to define the internal delims regex
+import new # used to bind methods and create dummy modules
+import string
+import os.path
+import time # used in the cache refresh code
+from random import randrange
+import imp
+import inspect
+import StringIO
+import traceback
+import pprint
+import cgi # Used by .webInput() if the template is a CGI script.
+import types
+from types import StringType, ClassType
+try:
+ from types import StringTypes
+except ImportError:
+ StringTypes = (types.StringType,types.UnicodeType)
+try:
+ from types import BooleanType
+ boolTypeAvailable = True
+except ImportError:
+ boolTypeAvailable = False
+
+try:
+ from threading import Lock
+except ImportError:
+ class Lock:
+ def acquire(self):
+ pass
+ def release(self):
+ pass
+
+try:
+ x = set()
+except NameError:
+ # Python 2.3 compatibility
+ from sets import Set as set
+
+from Cheetah.Version import convertVersionStringToTuple, MinCompatibleVersionTuple
+from Cheetah.Version import MinCompatibleVersion
+# Base classes for Template
+from Cheetah.Servlet import Servlet
+# More intra-package imports ...
+from Cheetah.Parser import ParseError, SourceReader
+from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS
+from Cheetah import ErrorCatchers # for placeholder tags
+from Cheetah import Filters # the output filters
+from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName
+from Cheetah.Utils import VerifyType # Used in Template.__init__
+from Cheetah.Utils.Misc import checkKeywords # Used in Template.__init__
+from Cheetah.Utils.Indenter import Indenter # Used in Template.__init__ and for
+ # placeholders
+from Cheetah.NameMapper import NotFound, valueFromSearchList
+from Cheetah.CacheStore import MemoryCacheStore, MemcachedCacheStore
+from Cheetah.CacheRegion import CacheRegion
+from Cheetah.Utils.WebInputMixin import _Converter, _lookup, NonNumericInputError
+
+from Cheetah.Unspecified import Unspecified
+
+# Decide whether to use the file modification time in file's cache key
+__checkFileMtime = True
+def checkFileMtime(value):
+ globals()['__checkFileMtime'] = value
+
+class Error(Exception):
+ pass
+class PreprocessError(Error):
+ pass
+
+def hashList(l):
+ hashedList = []
+ for v in l:
+ if isinstance(v, dict):
+ v = hashDict(v)
+ elif isinstance(v, list):
+ v = hashList(v)
+ hashedList.append(v)
+ return hash(tuple(hashedList))
+
+def hashDict(d):
+ items = d.items()
+ items.sort()
+ hashedList = []
+ for k, v in items:
+ if isinstance(v, dict):
+ v = hashDict(v)
+ elif isinstance(v, list):
+ v = hashList(v)
+ hashedList.append((k,v))
+ return hash(tuple(hashedList))
+
+################################################################################
+## MODULE GLOBALS AND CONSTANTS
+
+def _genUniqueModuleName(baseModuleName):
+ """The calling code is responsible for concurrency locking.
+ """
+ if baseModuleName not in sys.modules:
+ finalName = baseModuleName
+ else:
+ finalName = ('cheetah_%s_%s_%s'%(baseModuleName,
+ str(time.time()).replace('.','_'),
+ str(randrange(10000, 99999))))
+ return finalName
+
+# Cache of a cgi.FieldStorage() instance, maintained by .webInput().
+# This is only relavent to templates used as CGI scripts.
+_formUsedByWebInput = None
+
+# used in Template.compile()
+def valOrDefault(val, default):
+ if val is not Unspecified:
+ return val
+ return default
+
+def updateLinecache(filename, src):
+ import linecache
+ size = len(src)
+ mtime = time.time()
+ lines = src.splitlines()
+ fullname = filename
+ linecache.cache[filename] = size, mtime, lines, fullname
+
+class CompileCacheItem(object):
+ pass
+
+class TemplatePreprocessor(object):
+ '''
+ This is used with the preprocessors argument to Template.compile().
+
+ See the docstring for Template.compile
+
+ ** Preprocessors are an advanced topic **
+ '''
+
+ def __init__(self, settings):
+ self._settings = settings
+
+ def preprocess(self, source, file):
+ """Create an intermediate template and return the source code
+ it outputs
+ """
+ settings = self._settings
+ if not source: # @@TR: this needs improving
+ if isinstance(file, (str, unicode)): # it's a filename.
+ f = open(file)
+ source = f.read()
+ f.close()
+ elif hasattr(file, 'read'):
+ source = file.read()
+ file = None
+
+ templateAPIClass = settings.templateAPIClass
+ possibleKwArgs = [
+ arg for arg in
+ inspect.getargs(templateAPIClass.compile.im_func.func_code)[0]
+ if arg not in ('klass', 'source', 'file',)]
+
+ compileKwArgs = {}
+ for arg in possibleKwArgs:
+ if hasattr(settings, arg):
+ compileKwArgs[arg] = getattr(settings, arg)
+
+ tmplClass = templateAPIClass.compile(source=source, file=file, **compileKwArgs)
+ tmplInstance = tmplClass(**settings.templateInitArgs)
+ outputSource = settings.outputTransformer(tmplInstance)
+ outputFile = None
+ return outputSource, outputFile
+
+class Template(Servlet):
+ '''
+ This class provides a) methods used by templates at runtime and b)
+ methods for compiling Cheetah source code into template classes.
+
+ This documentation assumes you already know Python and the basics of object
+ oriented programming. If you don't know Python, see the sections of the
+ Cheetah Users' Guide for non-programmers. It also assumes you have read
+ about Cheetah's syntax in the Users' Guide.
+
+ The following explains how to use Cheetah from within Python programs or via
+ the interpreter. If you statically compile your templates on the command
+ line using the 'cheetah' script, this is not relevant to you. Statically
+ compiled Cheetah template modules/classes (e.g. myTemplate.py:
+ MyTemplateClasss) are just like any other Python module or class. Also note,
+ most Python web frameworks (Webware, Aquarium, mod_python, Turbogears,
+ CherryPy, Quixote, etc.) provide plugins that handle Cheetah compilation for
+ you.
+
+ There are several possible usage patterns:
+ 1) tclass = Template.compile(src)
+ t1 = tclass() # or tclass(namespaces=[namespace,...])
+ t2 = tclass() # or tclass(namespaces=[namespace2,...])
+ outputStr = str(t1) # or outputStr = t1.aMethodYouDefined()
+
+ Template.compile provides a rich and very flexible API via its
+ optional arguments so there are many possible variations of this
+ pattern. One example is:
+ tclass = Template.compile('hello $name from $caller', baseclass=dict)
+ print tclass(name='world', caller='me')
+ See the Template.compile() docstring for more details.
+
+ 2) tmplInstance = Template(src)
+ # or Template(src, namespaces=[namespace,...])
+ outputStr = str(tmplInstance) # or outputStr = tmplInstance.aMethodYouDefined(...args...)
+
+ Notes on the usage patterns:
+
+ usage pattern 1)
+ This is the most flexible, but it is slightly more verbose unless you
+ write a wrapper function to hide the plumbing. Under the hood, all
+ other usage patterns are based on this approach. Templates compiled
+ this way can #extend (subclass) any Python baseclass: old-style or
+ new-style (based on object or a builtin type).
+
+ usage pattern 2)
+ This was Cheetah's original usage pattern. It returns an instance,
+ but you can still access the generated class via
+ tmplInstance.__class__. If you want to use several different
+ namespace 'searchLists' with a single template source definition,
+ you're better off with Template.compile (1).
+
+ Limitations (use pattern 1 instead):
+ - Templates compiled this way can only #extend subclasses of the
+ new-style 'object' baseclass. Cheetah.Template is a subclass of
+ 'object'. You also can not #extend dict, list, or other builtin
+ types.
+ - If your template baseclass' __init__ constructor expects args there
+ is currently no way to pass them in.
+
+ If you need to subclass a dynamically compiled Cheetah class, do something like this:
+ from Cheetah.Template import Template
+ T1 = Template.compile('$meth1 #def meth1: this is meth1 in T1')
+ T2 = Template.compile('#implements meth1\nthis is meth1 redefined in T2', baseclass=T1)
+ print T1, T1()
+ print T2, T2()
+
+
+ Note about class and instance attribute names:
+ Attributes used by Cheetah have a special prefix to avoid confusion with
+ the attributes of the templates themselves or those of template
+ baseclasses.
+
+ Class attributes which are used in class methods look like this:
+ klass._CHEETAH_useCompilationCache (_CHEETAH_xxx)
+
+ Instance attributes look like this:
+ klass._CHEETAH__globalSetVars (_CHEETAH__xxx with 2 underscores)
+ '''
+
+ # this is used by ._addCheetahPlumbingCodeToClass()
+ _CHEETAH_requiredCheetahMethods = (
+ '_initCheetahInstance',
+ 'searchList',
+ 'errorCatcher',
+ 'getVar',
+ 'varExists',
+ 'getFileContents',
+ 'i18n',
+ 'runAsMainProgram',
+ 'respond',
+ 'shutdown',
+ 'webInput',
+ 'serverSidePath',
+ 'generatedClassCode',
+ 'generatedModuleCode',
+
+ '_getCacheStore',
+ '_getCacheStoreIdPrefix',
+ '_createCacheRegion',
+ 'getCacheRegion',
+ 'getCacheRegions',
+ 'refreshCache',
+
+ '_handleCheetahInclude',
+ '_getTemplateAPIClassForIncludeDirectiveCompilation',
+ )
+ _CHEETAH_requiredCheetahClassMethods = ('subclass',)
+ _CHEETAH_requiredCheetahClassAttributes = ('cacheRegionClass','cacheStore',
+ 'cacheStoreIdPrefix','cacheStoreClass')
+
+ ## the following are used by .compile(). Most are documented in its docstring.
+ _CHEETAH_cacheModuleFilesForTracebacks = False
+ _CHEETAH_cacheDirForModuleFiles = None # change to a dirname
+
+ _CHEETAH_compileCache = dict() # cache store for compiled code and classes
+ # To do something other than simple in-memory caching you can create an
+ # alternative cache store. It just needs to support the basics of Python's
+ # mapping/dict protocol. E.g.:
+ # class AdvCachingTemplate(Template):
+ # _CHEETAH_compileCache = MemoryOrFileCache()
+ _CHEETAH_compileLock = Lock() # used to prevent race conditions
+ _CHEETAH_defaultMainMethodName = None
+ _CHEETAH_compilerSettings = None
+ _CHEETAH_compilerClass = Compiler
+ _CHEETAH_cacheCompilationResults = True
+ _CHEETAH_useCompilationCache = True
+ _CHEETAH_keepRefToGeneratedCode = True
+ _CHEETAH_defaultBaseclassForTemplates = None
+ _CHEETAH_defaultClassNameForTemplates = None
+ # defaults to DEFAULT_COMPILER_SETTINGS['mainMethodName']:
+ _CHEETAH_defaultMainMethodNameForTemplates = None
+ _CHEETAH_defaultModuleNameForTemplates = 'DynamicallyCompiledCheetahTemplate'
+ _CHEETAH_defaultModuleGlobalsForTemplates = None
+ _CHEETAH_preprocessors = None
+ _CHEETAH_defaultPreprocessorClass = TemplatePreprocessor
+
+ ## The following attributes are used by instance methods:
+ _CHEETAH_generatedModuleCode = None
+ NonNumericInputError = NonNumericInputError
+ _CHEETAH_cacheRegionClass = CacheRegion
+ _CHEETAH_cacheStoreClass = MemoryCacheStore
+ #_CHEETAH_cacheStoreClass = MemcachedCacheStore
+ _CHEETAH_cacheStore = None
+ _CHEETAH_cacheStoreIdPrefix = None
+
+ def _getCompilerClass(klass, source=None, file=None):
+ return klass._CHEETAH_compilerClass
+ _getCompilerClass = classmethod(_getCompilerClass)
+
+ def _getCompilerSettings(klass, source=None, file=None):
+ return klass._CHEETAH_compilerSettings
+ _getCompilerSettings = classmethod(_getCompilerSettings)
+
+ def compile(klass, source=None, file=None,
+ returnAClass=True,
+
+ compilerSettings=Unspecified,
+ compilerClass=Unspecified,
+ moduleName=None,
+ className=Unspecified,
+ mainMethodName=Unspecified,
+ baseclass=Unspecified,
+ moduleGlobals=Unspecified,
+ cacheCompilationResults=Unspecified,
+ useCache=Unspecified,
+ preprocessors=Unspecified,
+ cacheModuleFilesForTracebacks=Unspecified,
+ cacheDirForModuleFiles=Unspecified,
+ commandlineopts=None,
+ keepRefToGeneratedCode=Unspecified,
+ ):
+
+ """
+ The core API for compiling Cheetah source code into template classes.
+
+ This class method compiles Cheetah source code and returns a python
+ class. You then create template instances using that class. All
+ Cheetah's other compilation API's use this method under the hood.
+
+ Internally, this method a) parses the Cheetah source code and generates
+ Python code defining a module with a single class in it, b) dynamically
+ creates a module object with a unique name, c) execs the generated code
+ in that module's namespace then inserts the module into sys.modules, and
+ d) returns a reference to the generated class. If you want to get the
+ generated python source code instead, pass the argument
+ returnAClass=False.
+
+ It caches generated code and classes. See the descriptions of the
+ arguments'cacheCompilationResults' and 'useCache' for details. This
+ doesn't mean that templates will automatically recompile themselves when
+ the source file changes. Rather, if you call Template.compile(src) or
+ Template.compile(file=path) repeatedly it will attempt to return a
+ cached class definition instead of recompiling.
+
+ Hooks are provided template source preprocessing. See the notes on the
+ 'preprocessors' arg.
+
+ If you are an advanced user and need to customize the way Cheetah parses
+ source code or outputs Python code, you should check out the
+ compilerSettings argument.
+
+ Arguments:
+ You must provide either a 'source' or 'file' arg, but not both:
+ - source (string or None)
+ - file (string path, file-like object, or None)
+
+ The rest of the arguments are strictly optional. All but the first
+ have defaults in attributes of the Template class which can be
+ overridden in subclasses of this class. Working with most of these is
+ an advanced topic.
+
+ - returnAClass=True
+ If false, return the generated module code rather than a class.
+
+ - compilerSettings (a dict)
+ Default: Template._CHEETAH_compilerSettings=None
+
+ a dictionary of settings to override those defined in
+ DEFAULT_COMPILER_SETTINGS. These can also be overridden in your
+ template source code with the #compiler or #compiler-settings
+ directives.
+
+ - compilerClass (a class)
+ Default: Template._CHEETAH_compilerClass=Cheetah.Compiler.Compiler
+
+ a subclass of Cheetah.Compiler.Compiler. Mucking with this is a
+ very advanced topic.
+
+ - moduleName (a string)
+ Default:
+ Template._CHEETAH_defaultModuleNameForTemplates
+ ='DynamicallyCompiledCheetahTemplate'
+
+ What to name the generated Python module. If the provided value is
+ None and a file arg was given, the moduleName is created from the
+ file path. In all cases if the moduleName provided is already in
+ sys.modules it is passed through a filter that generates a unique
+ variant of the name.
+
+
+ - className (a string)
+ Default: Template._CHEETAH_defaultClassNameForTemplates=None
+
+ What to name the generated Python class. If the provided value is
+ None, the moduleName is use as the class name.
+
+ - mainMethodName (a string)
+ Default:
+ Template._CHEETAH_defaultMainMethodNameForTemplates
+ =None (and thus DEFAULT_COMPILER_SETTINGS['mainMethodName'])
+
+ What to name the main output generating method in the compiled
+ template class.
+
+ - baseclass (a string or a class)
+ Default: Template._CHEETAH_defaultBaseclassForTemplates=None
+
+ Specifies the baseclass for the template without manually
+ including an #extends directive in the source. The #extends
+ directive trumps this arg.
+
+ If the provided value is a string you must make sure that a class
+ reference by that name is available to your template, either by
+ using an #import directive or by providing it in the arg
+ 'moduleGlobals'.
+
+ If the provided value is a class, Cheetah will handle all the
+ details for you.
+
+ - moduleGlobals (a dict)
+ Default: Template._CHEETAH_defaultModuleGlobalsForTemplates=None
+
+ A dict of vars that will be added to the global namespace of the
+ module the generated code is executed in, prior to the execution
+ of that code. This should be Python values, not code strings!
+
+ - cacheCompilationResults (True/False)
+ Default: Template._CHEETAH_cacheCompilationResults=True
+
+ Tells Cheetah to cache the generated code and classes so that they
+ can be reused if Template.compile() is called multiple times with
+ the same source and options.
+
+ - useCache (True/False)
+ Default: Template._CHEETAH_useCompilationCache=True
+
+ Should the compilation cache be used? If True and a previous
+ compilation created a cached template class with the same source
+ code, compiler settings and other options, the cached template
+ class will be returned.
+
+ - cacheModuleFilesForTracebacks (True/False)
+ Default: Template._CHEETAH_cacheModuleFilesForTracebacks=False
+
+ In earlier versions of Cheetah tracebacks from exceptions that
+ were raised inside dynamically compiled Cheetah templates were
+ opaque because Python didn't have access to a python source file
+ to use in the traceback:
+
+ File "xxxx.py", line 192, in getTextiledContent
+ content = str(template(searchList=searchList))
+ File "cheetah_yyyy.py", line 202, in __str__
+ File "cheetah_yyyy.py", line 187, in respond
+ File "cheetah_yyyy.py", line 139, in writeBody
+ ZeroDivisionError: integer division or modulo by zero
+
+ It is now possible to keep those files in a cache dir and allow
+ Python to include the actual source lines in tracebacks and makes
+ them much easier to understand:
+
+ File "xxxx.py", line 192, in getTextiledContent
+ content = str(template(searchList=searchList))
+ File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 202, in __str__
+ def __str__(self): return self.respond()
+ File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 187, in respond
+ self.writeBody(trans=trans)
+ File "/tmp/CheetahCacheDir/cheetah_yyyy.py", line 139, in writeBody
+ __v = 0/0 # $(0/0)
+ ZeroDivisionError: integer division or modulo by zero
+
+ - cacheDirForModuleFiles (a string representing a dir path)
+ Default: Template._CHEETAH_cacheDirForModuleFiles=None
+
+ See notes on cacheModuleFilesForTracebacks.
+
+ - preprocessors
+ Default: Template._CHEETAH_preprocessors=None
+
+ ** THIS IS A VERY ADVANCED TOPIC **
+
+ These are used to transform the source code prior to compilation.
+ They provide a way to use Cheetah as a code generator for Cheetah
+ code. In other words, you use one Cheetah template to output the
+ source code for another Cheetah template.
+
+ The major expected use cases are:
+
+ a) 'compile-time caching' aka 'partial template binding',
+ wherein an intermediate Cheetah template is used to output
+ the source for the final Cheetah template. The intermediate
+ template is a mix of a modified Cheetah syntax (the
+ 'preprocess syntax') and standard Cheetah syntax. The
+ preprocessor syntax is executed at compile time and outputs
+ Cheetah code which is then compiled in turn. This approach
+ allows one to completely soft-code all the elements in the
+ template which are subject to change yet have it compile to
+ extremely efficient Python code with everything but the
+ elements that must be variable at runtime (per browser
+ request, etc.) compiled as static strings. Examples of this
+ usage pattern will be added to the Cheetah Users' Guide.
+
+ The'preprocess syntax' is just Cheetah's standard one with
+ alternatives for the $ and # tokens:
+
+ e.g. '@' and '%' for code like this
+ @aPreprocessVar $aRuntimeVar
+ %if aCompileTimeCondition then yyy else zzz
+ %% preprocessor comment
+
+ #if aRunTimeCondition then aaa else bbb
+ ## normal comment
+ $aRuntimeVar
+
+ b) adding #import and #extends directives dynamically based on
+ the source
+
+ If preprocessors are provided, Cheetah pipes the source code
+ through each one in the order provided. Each preprocessor should
+ accept the args (source, file) and should return a tuple (source,
+ file).
+
+ The argument value should be a list, but a single non-list value
+ is acceptable and will automatically be converted into a list.
+ Each item in the list will be passed through
+ Template._normalizePreprocessor(). The items should either match
+ one of the following forms:
+
+ - an object with a .preprocess(source, file) method
+ - a callable with the following signature:
+ source, file = f(source, file)
+
+ or one of the forms below:
+
+ - a single string denoting the 2 'tokens' for the preprocess
+ syntax. The tokens should be in the order (placeholderToken,
+ directiveToken) and should separated with a space:
+ e.g. '@ %'
+ klass = Template.compile(src, preprocessors='@ %')
+ # or
+ klass = Template.compile(src, preprocessors=['@ %'])
+
+ - a dict with the following keys or an object with the
+ following attributes (all are optional, but nothing will
+ happen if you don't provide at least one):
+ - tokens: same as the single string described above. You can
+ also provide a tuple of 2 strings.
+ - searchList: the searchList used for preprocess $placeholders
+ - compilerSettings: used in the compilation of the intermediate
+ template
+ - templateAPIClass: an optional subclass of `Template`
+ - outputTransformer: a simple hook for passing in a callable
+ which can do further transformations of the preprocessor
+ output, or do something else like debug logging. The
+ default is str().
+ + any keyword arguments to Template.compile which you want to
+ provide for the compilation of the intermediate template.
+
+ klass = Template.compile(src,
+ preprocessors=[ dict(tokens='@ %', searchList=[...]) ] )
+
+ """
+ ##################################################
+ ## normalize and validate args
+ try:
+ vt = VerifyType.VerifyType
+ vtc = VerifyType.VerifyTypeClass
+ N = types.NoneType; S = types.StringType; U = types.UnicodeType
+ D = types.DictType; F = types.FileType
+ C = types.ClassType; M = types.ModuleType
+ I = types.IntType
+
+ if boolTypeAvailable:
+ B = types.BooleanType
+
+ vt(source, 'source', [N,S,U], 'string or None')
+ vt(file, 'file',[N,S,U,F], 'string, file-like object, or None')
+
+ baseclass = valOrDefault(baseclass, klass._CHEETAH_defaultBaseclassForTemplates)
+ if isinstance(baseclass, Template):
+ baseclass = baseclass.__class__
+ vt(baseclass, 'baseclass', [N,S,C,type], 'string, class or None')
+
+ cacheCompilationResults = valOrDefault(
+ cacheCompilationResults, klass._CHEETAH_cacheCompilationResults)
+ if boolTypeAvailable:
+ vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
+
+ useCache = valOrDefault(useCache, klass._CHEETAH_useCompilationCache)
+ if boolTypeAvailable:
+ vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
+
+ compilerSettings = valOrDefault(
+ compilerSettings, klass._getCompilerSettings(source, file) or {})
+ vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
+
+ compilerClass = valOrDefault(compilerClass, klass._getCompilerClass(source, file))
+ preprocessors = valOrDefault(preprocessors, klass._CHEETAH_preprocessors)
+
+ keepRefToGeneratedCode = valOrDefault(
+ keepRefToGeneratedCode, klass._CHEETAH_keepRefToGeneratedCode)
+ if boolTypeAvailable:
+ vt(cacheCompilationResults, 'cacheCompilationResults', [I,B], 'boolean')
+
+ vt(moduleName, 'moduleName', [N,S], 'string or None')
+ __orig_file__ = None
+ if not moduleName:
+ if file and type(file) in StringTypes:
+ moduleName = convertTmplPathToModuleName(file)
+ __orig_file__ = file
+ else:
+ moduleName = klass._CHEETAH_defaultModuleNameForTemplates
+
+ className = valOrDefault(
+ className, klass._CHEETAH_defaultClassNameForTemplates)
+ vt(className, 'className', [N,S], 'string or None')
+ className = className or moduleName
+
+ mainMethodName = valOrDefault(
+ mainMethodName, klass._CHEETAH_defaultMainMethodNameForTemplates)
+ vt(mainMethodName, 'mainMethodName', [N,S], 'string or None')
+
+ moduleGlobals = valOrDefault(
+ moduleGlobals, klass._CHEETAH_defaultModuleGlobalsForTemplates)
+
+ cacheModuleFilesForTracebacks = valOrDefault(
+ cacheModuleFilesForTracebacks, klass._CHEETAH_cacheModuleFilesForTracebacks)
+ if boolTypeAvailable:
+ vt(cacheModuleFilesForTracebacks, 'cacheModuleFilesForTracebacks', [I,B], 'boolean')
+
+ cacheDirForModuleFiles = valOrDefault(
+ cacheDirForModuleFiles, klass._CHEETAH_cacheDirForModuleFiles)
+ vt(cacheDirForModuleFiles, 'cacheDirForModuleFiles', [N,S], 'string or None')
+
+ except TypeError, reason:
+ raise TypeError(reason)
+
+ ##################################################
+ ## handle any preprocessors
+ if preprocessors:
+ origSrc = source
+ source, file = klass._preprocessSource(source, file, preprocessors)
+
+ ##################################################
+ ## compilation, using cache if requested/possible
+ baseclassValue = None
+ baseclassName = None
+ if baseclass:
+ if type(baseclass) in StringTypes:
+ baseclassName = baseclass
+ elif type(baseclass) in (ClassType, type):
+ # @@TR: should soft-code this
+ baseclassName = 'CHEETAH_dynamicallyAssignedBaseClass_'+baseclass.__name__
+ baseclassValue = baseclass
+
+
+ cacheHash = None
+ cacheItem = None
+ if source or isinstance(file, basestring):
+ compilerSettingsHash = None
+ if compilerSettings:
+ compilerSettingsHash = hashDict(compilerSettings)
+
+ moduleGlobalsHash = None
+ if moduleGlobals:
+ moduleGlobalsHash = hashDict(moduleGlobals)
+
+ fileHash = None
+ if file:
+ fileHash = str(hash(file))
+ if globals()['__checkFileMtime']:
+ fileHash += str(os.path.getmtime(file))
+
+ try:
+ # @@TR: find some way to create a cacheHash that is consistent
+ # between process restarts. It would allow for caching the
+ # compiled module on disk and thereby reduce the startup time
+ # for applications that use a lot of dynamically compiled
+ # templates.
+ cacheHash = ''.join([str(v) for v in
+ [hash(source),
+ fileHash,
+ className,
+ moduleName,
+ mainMethodName,
+ hash(compilerClass),
+ hash(baseclass),
+ compilerSettingsHash,
+ moduleGlobalsHash,
+ hash(cacheDirForModuleFiles),
+ ]])
+ except:
+ #@@TR: should add some logging to this
+ pass
+ outputEncoding = 'ascii'
+ if useCache and cacheHash and cacheHash in klass._CHEETAH_compileCache:
+ cacheItem = klass._CHEETAH_compileCache[cacheHash]
+ generatedModuleCode = cacheItem.code
+ else:
+ compiler = compilerClass(source, file,
+ moduleName=moduleName,
+ mainClassName=className,
+ baseclassName=baseclassName,
+ mainMethodName=mainMethodName,
+ settings=(compilerSettings or {}))
+ if commandlineopts:
+ compiler.setShBang(commandlineopts.shbang)
+ compiler.compile()
+ generatedModuleCode = compiler.getModuleCode()
+ outputEncoding = compiler.getModuleEncoding()
+
+ if not returnAClass:
+ # This is a bit of a hackish solution to make sure we're setting the proper
+ # encoding on generated code that is destined to be written to a file
+ if not outputEncoding == 'ascii':
+ generatedModuleCode = generatedModuleCode.split('\n')
+ generatedModuleCode.insert(1, '# -*- coding: %s -*-' % outputEncoding)
+ generatedModuleCode = '\n'.join(generatedModuleCode)
+ return generatedModuleCode.encode(outputEncoding)
+ else:
+ if cacheItem:
+ cacheItem.lastCheckoutTime = time.time()
+ return cacheItem.klass
+
+ try:
+ klass._CHEETAH_compileLock.acquire()
+ uniqueModuleName = _genUniqueModuleName(moduleName)
+ __file__ = uniqueModuleName+'.py' # relative file path with no dir part
+
+ if cacheModuleFilesForTracebacks:
+ if not os.path.exists(cacheDirForModuleFiles):
+ raise Exception('%s does not exist'%cacheDirForModuleFiles)
+
+ __file__ = os.path.join(cacheDirForModuleFiles, __file__)
+ # @@TR: might want to assert that it doesn't already exist
+ open(__file__, 'w').write(generatedModuleCode)
+ # @@TR: should probably restrict the perms, etc.
+
+ mod = new.module(str(uniqueModuleName))
+ if moduleGlobals:
+ for k, v in moduleGlobals.items():
+ setattr(mod, k, v)
+ mod.__file__ = __file__
+ if __orig_file__ and os.path.exists(__orig_file__):
+ # this is used in the WebKit filemonitoring code
+ mod.__orig_file__ = __orig_file__
+
+ if baseclass and baseclassValue:
+ setattr(mod, baseclassName, baseclassValue)
+ ##
+ try:
+ co = compile(generatedModuleCode.encode(outputEncoding), __file__, 'exec')
+ exec co in mod.__dict__
+ except SyntaxError, e:
+ try:
+ parseError = genParserErrorFromPythonException(
+ source, file, generatedModuleCode, exception=e)
+ except:
+ updateLinecache(__file__, generatedModuleCode)
+ e.generatedModuleCode = generatedModuleCode
+ raise e
+ else:
+ raise parseError
+ except Exception, e:
+ updateLinecache(__file__, generatedModuleCode)
+ e.generatedModuleCode = generatedModuleCode
+ raise
+ ##
+ sys.modules[uniqueModuleName] = mod
+ finally:
+ klass._CHEETAH_compileLock.release()
+
+ templateClass = getattr(mod, className)
+
+ if (cacheCompilationResults
+ and cacheHash
+ and cacheHash not in klass._CHEETAH_compileCache):
+
+ cacheItem = CompileCacheItem()
+ cacheItem.cacheTime = cacheItem.lastCheckoutTime = time.time()
+ cacheItem.code = generatedModuleCode
+ cacheItem.klass = templateClass
+ templateClass._CHEETAH_isInCompilationCache = True
+ klass._CHEETAH_compileCache[cacheHash] = cacheItem
+ else:
+ templateClass._CHEETAH_isInCompilationCache = False
+
+ if keepRefToGeneratedCode or cacheCompilationResults:
+ templateClass._CHEETAH_generatedModuleCode = generatedModuleCode
+
+ return templateClass
+ compile = classmethod(compile)
+
+ def subclass(klass, *args, **kws):
+ """Takes the same args as the .compile() classmethod and returns a
+ template that is a subclass of the template this method is called from.
+
+ T1 = Template.compile(' foo - $meth1 - bar\n#def meth1: this is T1.meth1')
+ T2 = T1.subclass('#implements meth1\n this is T2.meth1')
+ """
+ kws['baseclass'] = klass
+ if isinstance(klass, Template):
+ templateAPIClass = klass
+ else:
+ templateAPIClass = Template
+ return templateAPIClass.compile(*args, **kws)
+ subclass = classmethod(subclass)
+
+ def _preprocessSource(klass, source, file, preprocessors):
+ """Iterates through the .compile() classmethod's preprocessors argument
+ and pipes the source code through each each preprocessor.
+
+ It returns the tuple (source, file) which is then used by
+ Template.compile to finish the compilation.
+ """
+ if not isinstance(preprocessors, (list, tuple)):
+ preprocessors = [preprocessors]
+ for preprocessor in preprocessors:
+ preprocessor = klass._normalizePreprocessorArg(preprocessor)
+ source, file = preprocessor.preprocess(source, file)
+ return source, file
+ _preprocessSource = classmethod(_preprocessSource)
+
+ def _normalizePreprocessorArg(klass, arg):
+ """Used to convert the items in the .compile() classmethod's
+ preprocessors argument into real source preprocessors. This permits the
+ use of several shortcut forms for defining preprocessors.
+ """
+
+ if hasattr(arg, 'preprocess'):
+ return arg
+ elif callable(arg):
+ class WrapperPreprocessor:
+ def preprocess(self, source, file):
+ return arg(source, file)
+ return WrapperPreprocessor()
+ else:
+ class Settings(object):
+ placeholderToken = None
+ directiveToken = None
+ settings = Settings()
+ if isinstance(arg, str) or isinstance(arg, (list, tuple)):
+ settings.tokens = arg
+ elif isinstance(arg, dict):
+ for k, v in arg.items():
+ setattr(settings, k, v)
+ else:
+ settings = arg
+
+ settings = klass._normalizePreprocessorSettings(settings)
+ return klass._CHEETAH_defaultPreprocessorClass(settings)
+
+ _normalizePreprocessorArg = classmethod(_normalizePreprocessorArg)
+
+ def _normalizePreprocessorSettings(klass, settings):
+ settings.keepRefToGeneratedCode = True
+
+ def normalizeSearchList(searchList):
+ if not isinstance(searchList, (list, tuple)):
+ searchList = [searchList]
+ return searchList
+
+ def normalizeTokens(tokens):
+ if isinstance(tokens, str):
+ return tokens.split() # space delimited string e.g.'@ %'
+ elif isinstance(tokens, (list, tuple)):
+ return tokens
+ else:
+ raise PreprocessError('invalid tokens argument: %r'%tokens)
+
+ if hasattr(settings, 'tokens'):
+ (settings.placeholderToken,
+ settings.directiveToken) = normalizeTokens(settings.tokens)
+
+ if (not getattr(settings,'compilerSettings', None)
+ and not getattr(settings, 'placeholderToken', None) ):
+
+ raise TypeError(
+ 'Preprocessor requires either a "tokens" or a "compilerSettings" arg.'
+ ' Neither was provided.')
+
+ if not hasattr(settings, 'templateInitArgs'):
+ settings.templateInitArgs = {}
+ if 'searchList' not in settings.templateInitArgs:
+ if not hasattr(settings, 'searchList') and hasattr(settings, 'namespaces'):
+ settings.searchList = settings.namespaces
+ elif not hasattr(settings, 'searchList'):
+ settings.searchList = []
+ settings.templateInitArgs['searchList'] = settings.searchList
+ settings.templateInitArgs['searchList'] = (
+ normalizeSearchList(settings.templateInitArgs['searchList']))
+
+ if not hasattr(settings, 'outputTransformer'):
+ settings.outputTransformer = unicode
+
+ if not hasattr(settings, 'templateAPIClass'):
+ class PreprocessTemplateAPIClass(klass): pass
+ settings.templateAPIClass = PreprocessTemplateAPIClass
+
+ if not hasattr(settings, 'compilerSettings'):
+ settings.compilerSettings = {}
+
+ klass._updateSettingsWithPreprocessTokens(
+ compilerSettings=settings.compilerSettings,
+ placeholderToken=settings.placeholderToken,
+ directiveToken=settings.directiveToken
+ )
+ return settings
+ _normalizePreprocessorSettings = classmethod(_normalizePreprocessorSettings)
+
+ def _updateSettingsWithPreprocessTokens(
+ klass, compilerSettings, placeholderToken, directiveToken):
+
+ if (placeholderToken and 'cheetahVarStartToken' not in compilerSettings):
+ compilerSettings['cheetahVarStartToken'] = placeholderToken
+ if directiveToken:
+ if 'directiveStartToken' not in compilerSettings:
+ compilerSettings['directiveStartToken'] = directiveToken
+ if 'directiveEndToken' not in compilerSettings:
+ compilerSettings['directiveEndToken'] = directiveToken
+ if 'commentStartToken' not in compilerSettings:
+ compilerSettings['commentStartToken'] = directiveToken*2
+ if 'multiLineCommentStartToken' not in compilerSettings:
+ compilerSettings['multiLineCommentStartToken'] = (
+ directiveToken+'*')
+ if 'multiLineCommentEndToken' not in compilerSettings:
+ compilerSettings['multiLineCommentEndToken'] = (
+ '*'+directiveToken)
+ if 'EOLSlurpToken' not in compilerSettings:
+ compilerSettings['EOLSlurpToken'] = directiveToken
+ _updateSettingsWithPreprocessTokens = classmethod(_updateSettingsWithPreprocessTokens)
+
+ def _addCheetahPlumbingCodeToClass(klass, concreteTemplateClass):
+ """If concreteTemplateClass is not a subclass of Cheetah.Template, add
+ the required cheetah methods and attributes to it.
+
+ This is called on each new template class after it has been compiled.
+ If concreteTemplateClass is not a subclass of Cheetah.Template but
+ already has method with the same name as one of the required cheetah
+ methods, this will skip that method.
+ """
+ for methodname in klass._CHEETAH_requiredCheetahMethods:
+ if not hasattr(concreteTemplateClass, methodname):
+ method = getattr(Template, methodname)
+ newMethod = new.instancemethod(method.im_func, None, concreteTemplateClass)
+ #print methodname, method
+ setattr(concreteTemplateClass, methodname, newMethod)
+
+ for classMethName in klass._CHEETAH_requiredCheetahClassMethods:
+ if not hasattr(concreteTemplateClass, classMethName):
+ meth = getattr(klass, classMethName)
+ setattr(concreteTemplateClass, classMethName, classmethod(meth.im_func))
+
+ for attrname in klass._CHEETAH_requiredCheetahClassAttributes:
+ attrname = '_CHEETAH_'+attrname
+ if not hasattr(concreteTemplateClass, attrname):
+ attrVal = getattr(klass, attrname)
+ setattr(concreteTemplateClass, attrname, attrVal)
+
+ if (not hasattr(concreteTemplateClass, '__str__')
+ or concreteTemplateClass.__str__ is object.__str__):
+
+ mainMethNameAttr = '_mainCheetahMethod_for_'+concreteTemplateClass.__name__
+ mainMethName = getattr(concreteTemplateClass,mainMethNameAttr, None)
+ if mainMethName:
+ def __str__(self):
+ return getattr(self, mainMethName)()
+ elif (hasattr(concreteTemplateClass, 'respond')
+ and concreteTemplateClass.respond!=Servlet.respond):
+ def __str__(self):
+ return self.respond()
+ else:
+ def __str__(self):
+ if hasattr(self, mainMethNameAttr):
+ return getattr(self,mainMethNameAttr)()
+ elif hasattr(self, 'respond'):
+ return self.respond()
+ else:
+ return super(self.__class__, self).__str__()
+
+ __str__ = new.instancemethod(__str__, None, concreteTemplateClass)
+ setattr(concreteTemplateClass, '__str__', __str__)
+
+ _addCheetahPlumbingCodeToClass = classmethod(_addCheetahPlumbingCodeToClass)
+
+ ## end classmethods ##
+
+ def __init__(self, source=None,
+
+ namespaces=None, searchList=None,
+ # use either or. They are aliases for the same thing.
+
+ file=None,
+ filter='RawOrEncodedUnicode', # which filter from Cheetah.Filters
+ filtersLib=Filters,
+ errorCatcher=None,
+
+ compilerSettings=Unspecified, # control the behaviour of the compiler
+ _globalSetVars=None, # used internally for #include'd templates
+ _preBuiltSearchList=None # used internally for #include'd templates
+ ):
+ """a) compiles a new template OR b) instantiates an existing template.
+
+ Read this docstring carefully as there are two distinct usage patterns.
+ You should also read this class' main docstring.
+
+ a) to compile a new template:
+ t = Template(source=aSourceString)
+ # or
+ t = Template(file='some/path')
+ # or
+ t = Template(file=someFileObject)
+ # or
+ namespaces = [{'foo':'bar'}]
+ t = Template(source=aSourceString, namespaces=namespaces)
+ # or
+ t = Template(file='some/path', namespaces=namespaces)
+
+ print t
+
+ b) to create an instance of an existing, precompiled template class:
+ ## i) first you need a reference to a compiled template class:
+ tclass = Template.compile(source=src) # or just Template.compile(src)
+ # or
+ tclass = Template.compile(file='some/path')
+ # or
+ tclass = Template.compile(file=someFileObject)
+ # or
+ # if you used the command line compiler or have Cheetah's ImportHooks
+ # installed your template class is also available via Python's
+ # standard import mechanism:
+ from ACompileTemplate import AcompiledTemplate as tclass
+
+ ## ii) then you create an instance
+ t = tclass(namespaces=namespaces)
+ # or
+ t = tclass(namespaces=namespaces, filter='RawOrEncodedUnicode')
+ print t
+
+ Arguments:
+ for usage pattern a)
+ If you are compiling a new template, you must provide either a
+ 'source' or 'file' arg, but not both:
+ - source (string or None)
+ - file (string path, file-like object, or None)
+
+ Optional args (see below for more) :
+ - compilerSettings
+ Default: Template._CHEETAH_compilerSettings=None
+
+ a dictionary of settings to override those defined in
+ DEFAULT_COMPILER_SETTINGS. See
+ Cheetah.Template.DEFAULT_COMPILER_SETTINGS and the Users' Guide
+ for details.
+
+ You can pass the source arg in as a positional arg with this usage
+ pattern. Use keywords for all other args.
+
+ for usage pattern b)
+ Do not use positional args with this usage pattern, unless your
+ template subclasses something other than Cheetah.Template and you
+ want to pass positional args to that baseclass. E.g.:
+ dictTemplate = Template.compile('hello $name from $caller', baseclass=dict)
+ tmplvars = dict(name='world', caller='me')
+ print dictTemplate(tmplvars)
+ This usage requires all Cheetah args to be passed in as keyword args.
+
+ optional args for both usage patterns:
+
+ - namespaces (aka 'searchList')
+ Default: None
+
+ an optional list of namespaces (dictionaries, objects, modules,
+ etc.) which Cheetah will search through to find the variables
+ referenced in $placeholders.
+
+ If you provide a single namespace instead of a list, Cheetah will
+ automatically convert it into a list.
+
+ NOTE: Cheetah does NOT force you to use the namespaces search list
+ and related features. It's on by default, but you can turn if off
+ using the compiler settings useSearchList=False or
+ useNameMapper=False.
+
+ - filter
+ Default: 'EncodeUnicode'
+
+ Which filter should be used for output filtering. This should
+ either be a string which is the name of a filter in the
+ 'filtersLib' or a subclass of Cheetah.Filters.Filter. . See the
+ Users' Guide for more details.
+
+ - filtersLib
+ Default: Cheetah.Filters
+
+ A module containing subclasses of Cheetah.Filters.Filter. See the
+ Users' Guide for more details.
+
+ - errorCatcher
+ Default: None
+
+ This is a debugging tool. See the Users' Guide for more details.
+ Do not use this or the #errorCatcher diretive with live
+ production systems.
+
+ Do NOT mess with the args _globalSetVars or _preBuiltSearchList!
+
+ """
+
+ ##################################################
+ ## Verify argument keywords and types
+
+ S = types.StringType; U = types.UnicodeType
+ L = types.ListType; T = types.TupleType
+ D = types.DictType; F = types.FileType
+ C = types.ClassType; M = types.ModuleType
+ N = types.NoneType
+ vt = VerifyType.VerifyType
+ vtc = VerifyType.VerifyTypeClass
+ try:
+ vt(source, 'source', [N,S,U], 'string or None')
+ vt(file, 'file', [N,S,U,F], 'string, file open for reading, or None')
+ vtc(filter, 'filter', [S,C,type], 'string or class',
+ Filters.Filter,
+ '(if class, must be subclass of Cheetah.Filters.Filter)')
+ vt(filtersLib, 'filtersLib', [S,M], 'string or module',
+ '(if module, must contain subclasses of Cheetah.Filters.Filter)')
+ vtc(errorCatcher, 'errorCatcher', [N,S,C,type], 'string, class or None',
+ ErrorCatchers.ErrorCatcher,
+ '(if class, must be subclass of Cheetah.ErrorCatchers.ErrorCatcher)')
+ if compilerSettings is not Unspecified:
+ vt(compilerSettings, 'compilerSettings', [D], 'dictionary')
+
+ except TypeError, reason:
+ # Re-raise the exception here so that the traceback will end in
+ # this function rather than in some utility function.
+ raise TypeError(reason)
+
+ if source is not None and file is not None:
+ raise TypeError("you must supply either a source string or the" +
+ " 'file' keyword argument, but not both")
+
+ ##################################################
+ ## Do superclass initialization.
+ super(Template, self).__init__()
+
+ ##################################################
+ ## Do required version check
+ if not hasattr(self, '_CHEETAH_versionTuple'):
+ try:
+ mod = sys.modules[self.__class__.__module__]
+ compiledVersion = mod.__CHEETAH_version__
+ compiledVersionTuple = convertVersionStringToTuple(compiledVersion)
+ if compiledVersionTuple < MinCompatibleVersionTuple:
+ raise AssertionError(
+ 'This template was compiled with Cheetah version'
+ ' %s. Templates compiled before version %s must be recompiled.'%(
+ compiledVersion, MinCompatibleVersion))
+ except AssertionError:
+ raise
+ except:
+ pass
+
+ ##################################################
+ ## Setup instance state attributes used during the life of template
+ ## post-compile
+ reserved_searchlist = dir(self)
+ if searchList:
+ for namespace in searchList:
+ if isinstance(namespace, dict):
+ intersection = set(reserved_searchlist) & set(namespace.keys())
+ warn = False
+ if intersection:
+ warn = True
+ if isinstance(compilerSettings, dict) and compilerSettings.get('prioritizeSearchListOverSelf'):
+ warn = False
+ if warn:
+ print
+ print ''' *** WARNING *** '''
+ print ''' The following keys are members of the Template class and will result in NameMapper collisions! '''
+ print ''' > %s ''' % ', '.join(list(intersection))
+ print
+ print ''' Please change the key's name or use the compiler setting "prioritizeSearchListOverSelf=True" to prevent the NameMapper from using '''
+ print ''' the Template member in place of your searchList variable '''
+ print ''' *************** '''
+ print
+
+ self._initCheetahInstance(
+ searchList=searchList, namespaces=namespaces,
+ filter=filter, filtersLib=filtersLib,
+ errorCatcher=errorCatcher,
+ _globalSetVars=_globalSetVars,
+ compilerSettings=compilerSettings,
+ _preBuiltSearchList=_preBuiltSearchList)
+
+ ##################################################
+ ## Now, compile if we're meant to
+ if (source is not None) or (file is not None):
+ self._compile(source, file, compilerSettings=compilerSettings)
+
+ def generatedModuleCode(self):
+ """Return the module code the compiler generated, or None if no
+ compilation took place.
+ """
+
+ return self._CHEETAH_generatedModuleCode
+
+ def generatedClassCode(self):
+ """Return the class code the compiler generated, or None if no
+ compilation took place.
+ """
+
+ return self._CHEETAH_generatedModuleCode[
+ self._CHEETAH_generatedModuleCode.find('\nclass '):
+ self._CHEETAH_generatedModuleCode.find('\n## END CLASS DEFINITION')]
+
+ def searchList(self):
+ """Return a reference to the searchlist
+ """
+ return self._CHEETAH__searchList
+
+ def errorCatcher(self):
+ """Return a reference to the current errorCatcher
+ """
+ return self._CHEETAH__errorCatcher
+
+ ## cache methods ##
+ def _getCacheStore(self):
+ if not self._CHEETAH__cacheStore:
+ if self._CHEETAH_cacheStore is not None:
+ self._CHEETAH__cacheStore = self._CHEETAH_cacheStore
+ else:
+ # @@TR: might want to provide a way to provide init args
+ self._CHEETAH__cacheStore = self._CHEETAH_cacheStoreClass()
+
+ return self._CHEETAH__cacheStore
+
+ def _getCacheStoreIdPrefix(self):
+ if self._CHEETAH_cacheStoreIdPrefix is not None:
+ return self._CHEETAH_cacheStoreIdPrefix
+ else:
+ return str(id(self))
+
+ def _createCacheRegion(self, regionID):
+ return self._CHEETAH_cacheRegionClass(
+ regionID=regionID,
+ templateCacheIdPrefix=self._getCacheStoreIdPrefix(),
+ cacheStore=self._getCacheStore())
+
+ def getCacheRegion(self, regionID, cacheInfo=None, create=True):
+ cacheRegion = self._CHEETAH__cacheRegions.get(regionID)
+ if not cacheRegion and create:
+ cacheRegion = self._createCacheRegion(regionID)
+ self._CHEETAH__cacheRegions[regionID] = cacheRegion
+ return cacheRegion
+
+ def getCacheRegions(self):
+ """Returns a dictionary of the 'cache regions' initialized in a
+ template.
+
+ Each #cache directive block or $*cachedPlaceholder is a separate 'cache
+ region'.
+ """
+ # returns a copy to prevent users mucking it up
+ return self._CHEETAH__cacheRegions.copy()
+
+ def refreshCache(self, cacheRegionId=None, cacheItemId=None):
+ """Refresh a cache region or a specific cache item within a region.
+ """
+
+ if not cacheRegionId:
+ for key, cregion in self.getCacheRegions():
+ cregion.clear()
+ else:
+ cregion = self._CHEETAH__cacheRegions.get(cacheRegionId)
+ if not cregion:
+ return
+ if not cacheItemId: # clear the desired region and all its cacheItems
+ cregion.clear()
+ else: # clear one specific cache of a specific region
+ cache = cregion.getCacheItem(cacheItemId)
+ if cache:
+ cache.clear()
+
+ ## end cache methods ##
+
+ def shutdown(self):
+ """Break reference cycles before discarding a servlet.
+ """
+ try:
+ Servlet.shutdown(self)
+ except:
+ pass
+ self._CHEETAH__searchList = None
+ self.__dict__ = {}
+
+ ## utility functions ##
+
+ def getVar(self, varName, default=Unspecified, autoCall=True):
+ """Get a variable from the searchList. If the variable can't be found
+ in the searchList, it returns the default value if one was given, or
+ raises NameMapper.NotFound.
+ """
+
+ try:
+ return valueFromSearchList(self.searchList(), varName.replace('$',''), autoCall)
+ except NotFound:
+ if default is not Unspecified:
+ return default
+ else:
+ raise
+
+ def varExists(self, varName, autoCall=True):
+ """Test if a variable name exists in the searchList.
+ """
+ try:
+ valueFromSearchList(self.searchList(), varName.replace('$',''), autoCall)
+ return True
+ except NotFound:
+ return False
+
+
+ hasVar = varExists
+
+
+ def i18n(self, message,
+ plural=None,
+ n=None,
+
+ id=None,
+ domain=None,
+ source=None,
+ target=None,
+ comment=None
+ ):
+ """This is just a stub at this time.
+
+ plural = the plural form of the message
+ n = a sized argument to distinguish between single and plural forms
+
+ id = msgid in the translation catalog
+ domain = translation domain
+ source = source lang
+ target = a specific target lang
+ comment = a comment to the translation team
+
+ See the following for some ideas
+ http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport
+
+ Other notes:
+ - There is no need to replicate the i18n:name attribute from plone / PTL,
+ as cheetah placeholders serve the same purpose
+
+
+ """
+
+ return message
+
+ def getFileContents(self, path):
+ """A hook for getting the contents of a file. The default
+ implementation just uses the Python open() function to load local files.
+ This method could be reimplemented to allow reading of remote files via
+ various protocols, as PHP allows with its 'URL fopen wrapper'
+ """
+
+ fp = open(path,'r')
+ output = fp.read()
+ fp.close()
+ return output
+
+ def runAsMainProgram(self):
+ """Allows the Template to function as a standalone command-line program
+ for static page generation.
+
+ Type 'python yourtemplate.py --help to see what it's capabable of.
+ """
+
+ from TemplateCmdLineIface import CmdLineIface
+ CmdLineIface(templateObj=self).run()
+
+ ##################################################
+ ## internal methods -- not to be called by end-users
+
+ def _initCheetahInstance(self,
+ searchList=None,
+ namespaces=None,
+ filter='RawOrEncodedUnicode', # which filter from Cheetah.Filters
+ filtersLib=Filters,
+ errorCatcher=None,
+ _globalSetVars=None,
+ compilerSettings=None,
+ _preBuiltSearchList=None):
+ """Sets up the instance attributes that cheetah templates use at
+ run-time.
+
+ This is automatically called by the __init__ method of compiled
+ templates.
+
+ Note that the names of instance attributes used by Cheetah are prefixed
+ with '_CHEETAH__' (2 underscores), where class attributes are prefixed
+ with '_CHEETAH_' (1 underscore).
+ """
+ if getattr(self, '_CHEETAH__instanceInitialized', False):
+ return
+
+ if namespaces is not None:
+ assert searchList is None, (
+ 'Provide "namespaces" or "searchList", not both!')
+ searchList = namespaces
+ if searchList is not None and not isinstance(searchList, (list, tuple)):
+ searchList = [searchList]
+
+ self._CHEETAH__globalSetVars = {}
+ if _globalSetVars is not None:
+ # this is intended to be used internally by Nested Templates in #include's
+ self._CHEETAH__globalSetVars = _globalSetVars
+
+ if _preBuiltSearchList is not None:
+ # happens with nested Template obj creation from #include's
+ self._CHEETAH__searchList = list(_preBuiltSearchList)
+ self._CHEETAH__searchList.append(self)
+ else:
+ # create our own searchList
+ self._CHEETAH__searchList = [self._CHEETAH__globalSetVars, self]
+ if searchList is not None:
+ if isinstance(compilerSettings, dict) and compilerSettings.get('prioritizeSearchListOverSelf'):
+ self._CHEETAH__searchList = searchList + self._CHEETAH__searchList
+ else:
+ self._CHEETAH__searchList.extend(list(searchList))
+ self._CHEETAH__cheetahIncludes = {}
+ self._CHEETAH__cacheRegions = {}
+ self._CHEETAH__indenter = Indenter()
+
+ # @@TR: consider allowing simple callables as the filter argument
+ self._CHEETAH__filtersLib = filtersLib
+ self._CHEETAH__filters = {}
+ if type(filter) in StringTypes:
+ filterName = filter
+ klass = getattr(self._CHEETAH__filtersLib, filterName)
+ else:
+ klass = filter
+ filterName = klass.__name__
+ self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName] = klass(self).filter
+ self._CHEETAH__initialFilter = self._CHEETAH__currentFilter
+
+ self._CHEETAH__errorCatchers = {}
+ if errorCatcher:
+ if type(errorCatcher) in StringTypes:
+ errorCatcherClass = getattr(ErrorCatchers, errorCatcher)
+ elif type(errorCatcher) == ClassType:
+ errorCatcherClass = errorCatcher
+
+ self._CHEETAH__errorCatcher = ec = errorCatcherClass(self)
+ self._CHEETAH__errorCatchers[errorCatcher.__class__.__name__] = ec
+
+ else:
+ self._CHEETAH__errorCatcher = None
+ self._CHEETAH__initErrorCatcher = self._CHEETAH__errorCatcher
+
+ if not hasattr(self, 'transaction'):
+ self.transaction = None
+ self._CHEETAH__instanceInitialized = True
+ self._CHEETAH__isBuffering = False
+ self._CHEETAH__isControlledByWebKit = False
+
+ self._CHEETAH__cacheStore = None
+ if self._CHEETAH_cacheStore is not None:
+ self._CHEETAH__cacheStore = self._CHEETAH_cacheStore
+
+ def _compile(self, source=None, file=None, compilerSettings=Unspecified,
+ moduleName=None, mainMethodName=None):
+ """Compile the template. This method is automatically called by
+ Template.__init__ it is provided with 'file' or 'source' args.
+
+ USERS SHOULD *NEVER* CALL THIS METHOD THEMSELVES. Use Template.compile
+ instead.
+ """
+ if compilerSettings is Unspecified:
+ compilerSettings = self._getCompilerSettings(source, file) or {}
+ mainMethodName = mainMethodName or self._CHEETAH_defaultMainMethodName
+ self._fileMtime = None
+ self._fileDirName = None
+ self._fileBaseName = None
+ if file and type(file) in StringTypes:
+ file = self.serverSidePath(file)
+ self._fileMtime = os.path.getmtime(file)
+ self._fileDirName, self._fileBaseName = os.path.split(file)
+ self._filePath = file
+ templateClass = self.compile(source, file,
+ moduleName=moduleName,
+ mainMethodName=mainMethodName,
+ compilerSettings=compilerSettings,
+ keepRefToGeneratedCode=True)
+ self.__class__ = templateClass
+ # must initialize it so instance attributes are accessible
+ templateClass.__init__(self,
+ #_globalSetVars=self._CHEETAH__globalSetVars,
+ #_preBuiltSearchList=self._CHEETAH__searchList
+ )
+ if not hasattr(self, 'transaction'):
+ self.transaction = None
+
+ def _handleCheetahInclude(self, srcArg, trans=None, includeFrom='file', raw=False):
+ """Called at runtime to handle #include directives.
+ """
+ _includeID = srcArg
+ if not self._CHEETAH__cheetahIncludes.has_key(_includeID):
+ if not raw:
+ if includeFrom == 'file':
+ source = None
+ if type(srcArg) in StringTypes:
+ if hasattr(self, 'serverSidePath'):
+ file = path = self.serverSidePath(srcArg)
+ else:
+ file = path = os.path.normpath(srcArg)
+ else:
+ file = srcArg ## a file-like object
+ else:
+ source = srcArg
+ file = None
+ # @@TR: might want to provide some syntax for specifying the
+ # Template class to be used for compilation so compilerSettings
+ # can be changed.
+ compiler = self._getTemplateAPIClassForIncludeDirectiveCompilation(source, file)
+ nestedTemplateClass = compiler.compile(source=source,file=file)
+ nestedTemplate = nestedTemplateClass(_preBuiltSearchList=self.searchList(),
+ _globalSetVars=self._CHEETAH__globalSetVars)
+ # Set the inner template filters to the initial filter of the
+ # outer template:
+ # this is the only really safe way to use
+ # filter='WebSafe'.
+ nestedTemplate._CHEETAH__initialFilter = self._CHEETAH__initialFilter
+ nestedTemplate._CHEETAH__currentFilter = self._CHEETAH__initialFilter
+ self._CHEETAH__cheetahIncludes[_includeID] = nestedTemplate
+ else:
+ if includeFrom == 'file':
+ path = self.serverSidePath(srcArg)
+ self._CHEETAH__cheetahIncludes[_includeID] = self.getFileContents(path)
+ else:
+ self._CHEETAH__cheetahIncludes[_includeID] = srcArg
+ ##
+ if not raw:
+ self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
+ else:
+ trans.response().write(self._CHEETAH__cheetahIncludes[_includeID])
+
+ def _getTemplateAPIClassForIncludeDirectiveCompilation(self, source, file):
+ """Returns the subclass of Template which should be used to compile
+ #include directives.
+
+ This abstraction allows different compiler settings to be used in the
+ included template than were used in the parent.
+ """
+ if issubclass(self.__class__, Template):
+ return self.__class__
+ else:
+ return Template
+
+ ## functions for using templates as CGI scripts
+ def webInput(self, names, namesMulti=(), default='', src='f',
+ defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):
+ """Method for importing web transaction variables in bulk.
+
+ This works for GET/POST fields both in Webware servlets and in CGI
+ scripts, and for cookies and session variables in Webware servlets. If
+ you try to read a cookie or session variable in a CGI script, you'll get
+ a RuntimeError. 'In a CGI script' here means 'not running as a Webware
+ servlet'. If the CGI environment is not properly set up, Cheetah will
+ act like there's no input.
+
+ The public method provided is:
+
+ def webInput(self, names, namesMulti=(), default='', src='f',
+ defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):
+
+ This method places the specified GET/POST fields, cookies or session
+ variables into a dictionary, which is both returned and put at the
+ beginning of the searchList. It handles:
+
+ * single vs multiple values
+ * conversion to integer or float for specified names
+ * default values/exceptions for missing or bad values
+ * printing a snapshot of all values retrieved for debugging
+
+ All the 'default*' and 'bad*' arguments have 'use or raise' behavior,
+ meaning that if they're a subclass of Exception, they're raised. If
+ they're anything else, that value is substituted for the missing/bad
+ value.
+
+
+ The simplest usage is:
+
+ #silent $webInput(['choice'])
+ $choice
+
+ dic = self.webInput(['choice'])
+ write(dic['choice'])
+
+ Both these examples retrieves the GET/POST field 'choice' and print it.
+ If you leave off the'#silent', all the values would be printed too. But
+ a better way to preview the values is
+
+ #silent $webInput(['name'], $debug=1)
+
+ because this pretty-prints all the values inside HTML <PRE> tags.
+
+ ** KLUDGE: 'debug' is supposed to insert into the template output, but it
+ wasn't working so I changed it to a'print' statement. So the debugging
+ output will appear wherever standard output is pointed, whether at the
+ terminal, in a Webware log file, or whatever. ***
+
+ Since we didn't specify any coversions, the value is a string. It's a
+ 'single' value because we specified it in 'names' rather than
+ 'namesMulti'. Single values work like this:
+
+ * If one value is found, take it.
+ * If several values are found, choose one arbitrarily and ignore the rest.
+ * If no values are found, use or raise the appropriate 'default*' value.
+
+ Multi values work like this:
+ * If one value is found, put it in a list.
+ * If several values are found, leave them in a list.
+ * If no values are found, use the empty list ([]). The 'default*'
+ arguments are *not* consulted in this case.
+
+ Example: assume 'days' came from a set of checkboxes or a multiple combo
+ box on a form, and the user chose'Monday', 'Tuesday' and 'Thursday'.
+
+ #silent $webInput([], ['days'])
+ The days you chose are: #slurp
+ #for $day in $days
+ $day #slurp
+ #end for
+
+ dic = self.webInput([], ['days'])
+ write('The days you chose are: ')
+ for day in dic['days']:
+ write(day + ' ')
+
+ Both these examples print: 'The days you chose are: Monday Tuesday Thursday'.
+
+ By default, missing strings are replaced by '' and missing/bad numbers
+ by zero. (A'bad number' means the converter raised an exception for
+ it, usually because of non-numeric characters in the value.) This
+ mimics Perl/PHP behavior, and simplifies coding for many applications
+ where missing/bad values *should* be blank/zero. In those relatively
+ few cases where you must distinguish between empty-string/zero on the
+ one hand and missing/bad on the other, change the appropriate
+ 'default*' and 'bad*' arguments to something like:
+
+ * None
+ * another constant value
+ * $NonNumericInputError/self.NonNumericInputError
+ * $ValueError/ValueError
+
+ (NonNumericInputError is defined in this class and is useful for
+ distinguishing between bad input vs a TypeError/ValueError thrown for
+ some other rason.)
+
+ Here's an example using multiple values to schedule newspaper
+ deliveries. 'checkboxes' comes from a form with checkboxes for all the
+ days of the week. The days the user previously chose are preselected.
+ The user checks/unchecks boxes as desired and presses Submit. The value
+ of 'checkboxes' is a list of checkboxes that were checked when Submit
+ was pressed. Our task now is to turn on the days the user checked, turn
+ off the days he unchecked, and leave on or off the days he didn't
+ change.
+
+ dic = self.webInput([], ['dayCheckboxes'])
+ wantedDays = dic['dayCheckboxes'] # The days the user checked.
+ for day, on in self.getAllValues():
+ if not on and wantedDays.has_key(day):
+ self.TurnOn(day)
+ # ... Set a flag or insert a database record ...
+ elif on and not wantedDays.has_key(day):
+ self.TurnOff(day)
+ # ... Unset a flag or delete a database record ...
+
+ 'source' allows you to look up the variables from a number of different
+ sources:
+ 'f' fields (CGI GET/POST parameters)
+ 'c' cookies
+ 's' session variables
+ 'v' 'values', meaning fields or cookies
+
+ In many forms, you're dealing only with strings, which is why the
+ 'default' argument is third and the numeric arguments are banished to
+ the end. But sometimes you want automatic number conversion, so that
+ you can do numeric comparisions in your templates without having to
+ write a bunch of conversion/exception handling code. Example:
+
+ #silent $webInput(['name', 'height:int'])
+ $name is $height cm tall.
+ #if $height >= 300
+ Wow, you're tall!
+ #else
+ Pshaw, you're short.
+ #end if
+
+ dic = self.webInput(['name', 'height:int'])
+ name = dic[name]
+ height = dic[height]
+ write('%s is %s cm tall.' % (name, height))
+ if height > 300:
+ write('Wow, you're tall!')
+ else:
+ write('Pshaw, you're short.')
+
+ To convert a value to a number, suffix ':int' or ':float' to the name.
+ The method will search first for a 'height:int' variable and then for a
+ 'height' variable. (It will be called 'height' in the final
+ dictionary.) If a numeric conversion fails, use or raise 'badInt' or
+ 'badFloat'. Missing values work the same way as for strings, except the
+ default is 'defaultInt' or 'defaultFloat' instead of 'default'.
+
+ If a name represents an uploaded file, the entire file will be read into
+ memory. For more sophistocated file-upload handling, leave that name
+ out of the list and do your own handling, or wait for
+ Cheetah.Utils.UploadFileMixin.
+
+ This only in a subclass that also inherits from Webware's Servlet or
+ HTTPServlet. Otherwise you'll get an AttributeError on 'self.request'.
+
+ EXCEPTIONS: ValueError if 'source' is not one of the stated characters.
+ TypeError if a conversion suffix is not ':int' or ':float'.
+
+ FUTURE EXPANSION: a future version of this method may allow source
+ cascading; e.g., 'vs' would look first in 'values' and then in session
+ variables.
+
+ Meta-Data
+ ================================================================================
+ Author: Mike Orr <iron at mso.oz.net>
+ License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+ Version: $Revision: 1.186 $
+ Start Date: 2002/03/17
+ Last Revision Date: $Date: 2008/03/10 04:48:11 $
+ """
+ src = src.lower()
+ isCgi = not self._CHEETAH__isControlledByWebKit
+ if isCgi and src in ('f', 'v'):
+ global _formUsedByWebInput
+ if _formUsedByWebInput is None:
+ _formUsedByWebInput = cgi.FieldStorage()
+ source, func = 'field', _formUsedByWebInput.getvalue
+ elif isCgi and src == 'c':
+ raise RuntimeError("can't get cookies from a CGI script")
+ elif isCgi and src == 's':
+ raise RuntimeError("can't get session variables from a CGI script")
+ elif isCgi and src == 'v':
+ source, func = 'value', self.request().value
+ elif isCgi and src == 's':
+ source, func = 'session', self.request().session().value
+ elif src == 'f':
+ source, func = 'field', self.request().field
+ elif src == 'c':
+ source, func = 'cookie', self.request().cookie
+ elif src == 'v':
+ source, func = 'value', self.request().value
+ elif src == 's':
+ source, func = 'session', self.request().session().value
+ else:
+ raise TypeError("arg 'src' invalid")
+ sources = source + 's'
+ converters = {
+ '' : _Converter('string', None, default, default ),
+ 'int' : _Converter('int', int, defaultInt, badInt ),
+ 'float': _Converter('float', float, defaultFloat, badFloat), }
+ #pprint.pprint(locals()); return {}
+ dic = {} # Destination.
+ for name in names:
+ k, v = _lookup(name, func, False, converters)
+ dic[k] = v
+ for name in namesMulti:
+ k, v = _lookup(name, func, True, converters)
+ dic[k] = v
+ # At this point, 'dic' contains all the keys/values we want to keep.
+ # We could split the method into a superclass
+ # method for Webware/WebwareExperimental and a subclass for Cheetah.
+ # The superclass would merely 'return dic'. The subclass would
+ # 'dic = super(ThisClass, self).webInput(names, namesMulti, ...)'
+ # and then the code below.
+ if debug:
+ print "<PRE>\n" + pprint.pformat(dic) + "\n</PRE>\n\n"
+ self.searchList().insert(0, dic)
+ return dic
+
+T = Template # Short and sweet for debugging at the >>> prompt.
+
+
+def genParserErrorFromPythonException(source, file, generatedPyCode, exception):
+
+ #print dir(exception)
+
+ filename = isinstance(file, (str, unicode)) and file or None
+
+ sio = StringIO.StringIO()
+ traceback.print_exc(1, sio)
+ formatedExc = sio.getvalue()
+
+ if hasattr(exception, 'lineno'):
+ pyLineno = exception.lineno
+ else:
+ pyLineno = int(re.search('[ \t]*File.*line (\d+)', formatedExc).group(1))
+
+ lines = generatedPyCode.splitlines()
+
+ prevLines = [] # (i, content)
+ for i in range(1,4):
+ if pyLineno-i <=0:
+ break
+ prevLines.append( (pyLineno+1-i,lines[pyLineno-i]) )
+
+ nextLines = [] # (i, content)
+ for i in range(1,4):
+ if not pyLineno+i < len(lines):
+ break
+ nextLines.append( (pyLineno+i,lines[pyLineno+i]) )
+ nextLines.reverse()
+ report = 'Line|Python Code\n'
+ report += '----|-------------------------------------------------------------\n'
+ while prevLines:
+ lineInfo = prevLines.pop()
+ report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
+
+ if hasattr(exception, 'offset'):
+ report += ' '*(3+(exception.offset or 0)) + '^\n'
+
+ while nextLines:
+ lineInfo = nextLines.pop()
+ report += "%(row)-4d|%(line)s\n"% {'row':lineInfo[0], 'line':lineInfo[1]}
+
+
+ message = [
+ "Error in the Python code which Cheetah generated for this template:",
+ '='*80,
+ '',
+ str(exception),
+ '',
+ report,
+ '='*80,
+ ]
+ cheetahPosMatch = re.search('line (\d+), col (\d+)', formatedExc)
+ if cheetahPosMatch:
+ lineno = int(cheetahPosMatch.group(1))
+ col = int(cheetahPosMatch.group(2))
+ #if hasattr(exception, 'offset'):
+ # col = exception.offset
+ message.append('\nHere is the corresponding Cheetah code:\n')
+ else:
+ lineno = None
+ col = None
+ cheetahPosMatch = re.search('line (\d+), col (\d+)',
+ '\n'.join(lines[max(pyLineno-2, 0):]))
+ if cheetahPosMatch:
+ lineno = int(cheetahPosMatch.group(1))
+ col = int(cheetahPosMatch.group(2))
+ message.append('\nHere is the corresponding Cheetah code.')
+ message.append('** I had to guess the line & column numbers,'
+ ' so they are probably incorrect:\n')
+
+
+ message = '\n'.join(message)
+ reader = SourceReader(source, filename=filename)
+ return ParseError(reader, message, lineno=lineno,col=col)
+
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/TemplateCmdLineIface.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/TemplateCmdLineIface.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/TemplateCmdLineIface.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# $Id: TemplateCmdLineIface.py,v 1.13 2006/01/10 20:34:35 tavis_rudd Exp $
+
+"""Provides a command line interface to compiled Cheetah template modules.
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>
+Version: $Revision: 1.13 $
+Start Date: 2001/12/06
+Last Revision Date: $Date: 2006/01/10 20:34:35 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.13 $"[11:-2]
+
+import sys
+import os
+import getopt
+import os.path
+try:
+ from cPickle import load
+except ImportError:
+ from pickle import load
+
+from Cheetah.Version import Version
+
+class Error(Exception):
+ pass
+
+class CmdLineIface:
+ """A command line interface to compiled Cheetah template modules."""
+
+ def __init__(self, templateObj,
+ scriptName=os.path.basename(sys.argv[0]),
+ cmdLineArgs=sys.argv[1:]):
+
+ self._template = templateObj
+ self._scriptName = scriptName
+ self._cmdLineArgs = cmdLineArgs
+
+ def run(self):
+ """The main program controller."""
+
+ self._processCmdLineArgs()
+ print self._template
+
+ def _processCmdLineArgs(self):
+ try:
+ self._opts, self._args = getopt.getopt(
+ self._cmdLineArgs, 'h', ['help',
+ 'env',
+ 'pickle=',
+ ])
+
+ except getopt.GetoptError, v:
+ # print help information and exit:
+ print v
+ print self.usage()
+ sys.exit(2)
+
+ for o, a in self._opts:
+ if o in ('-h','--help'):
+ print self.usage()
+ sys.exit()
+ if o == '--env':
+ self._template.searchList().insert(0, os.environ)
+ if o == '--pickle':
+ if a == '-':
+ unpickled = load(sys.stdin)
+ self._template.searchList().insert(0, unpickled)
+ else:
+ f = open(a)
+ unpickled = load(f)
+ f.close()
+ self._template.searchList().insert(0, unpickled)
+
+ def usage(self):
+ return """Cheetah %(Version)s template module command-line interface
+
+Usage
+-----
+ %(scriptName)s [OPTION]
+
+Options
+-------
+ -h, --help Print this help information
+
+ --env Use shell ENVIRONMENT variables to fill the
+ $placeholders in the template.
+
+ --pickle <file> Use a variables from a dictionary stored in Python
+ pickle file to fill $placeholders in the template.
+ If <file> is - stdin is used:
+ '%(scriptName)s --pickle -'
+
+Description
+-----------
+
+This interface allows you to execute a Cheetah template from the command line
+and collect the output. It can prepend the shell ENVIRONMENT or a pickled
+Python dictionary to the template's $placeholder searchList, overriding the
+defaults for the $placeholders.
+
+""" % {'scriptName':self._scriptName,
+ 'Version':Version,
+ }
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+
+
+"""A Skeleton HTML page template, that provides basic structure and utility methods.
+"""
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+from os.path import getmtime, exists
+import time
+import types
+import __builtin__
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import DummyTransaction
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from Cheetah.Templates._SkeletonPage import _SkeletonPage
+
+##################################################
+## MODULE CONSTANTS
+try:
+ True, False
+except NameError:
+ True, False = (1==1), (1==0)
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.0rc6'
+__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 6)
+__CHEETAH_genTime__ = 1139107954.3640411
+__CHEETAH_genTimestamp__ = 'Sat Feb 4 18:52:34 2006'
+__CHEETAH_src__ = 'src/Templates/SkeletonPage.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Oct 7 11:37:30 2002'
+__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+ raise AssertionError(
+ 'This template was compiled with Cheetah version'
+ ' %s. Templates compiled before version %s must be recompiled.'%(
+ __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SkeletonPage(_SkeletonPage):
+
+ ##################################################
+ ## CHEETAH GENERATED METHODS
+
+
+ def __init__(self, *args, **KWs):
+
+ _SkeletonPage.__init__(self, *args, **KWs)
+ if not self._CHEETAH__instanceInitialized:
+ cheetahKWArgs = {}
+ allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+ for k,v in KWs.items():
+ if k in allowedKWs: cheetahKWArgs[k] = v
+ self._initCheetahInstance(**cheetahKWArgs)
+
+
+ def writeHeadTag(self, **KWS):
+
+
+
+ ## CHEETAH: generated from #block writeHeadTag at line 22, col 1.
+ trans = KWS.get("trans")
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+ write('<head>\n<title>')
+ _v = VFFSL(SL,"title",True) # '$title' on line 24, col 8
+ if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 24, col 8.
+ write('</title>\n')
+ _v = VFFSL(SL,"metaTags",True) # '$metaTags' on line 25, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$metaTags')) # from line 25, col 1.
+ write(' \n')
+ _v = VFFSL(SL,"stylesheetTags",True) # '$stylesheetTags' on line 26, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$stylesheetTags')) # from line 26, col 1.
+ write(' \n')
+ _v = VFFSL(SL,"javascriptTags",True) # '$javascriptTags' on line 27, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$javascriptTags')) # from line 27, col 1.
+ write('\n</head>\n')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+
+ def writeBody(self, **KWS):
+
+
+
+ ## CHEETAH: generated from #block writeBody at line 36, col 1.
+ trans = KWS.get("trans")
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+ write('This skeleton page has no flesh. Its body needs to be implemented.\n')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+
+ def respond(self, trans=None):
+
+
+
+ ## CHEETAH: main method generated for this template
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+
+ ## START CACHE REGION: ID=header. line 6, col 1 in the source.
+ _RECACHE_header = False
+ _cacheRegion_header = self.getCacheRegion(regionID='header', cacheInfo={'type': 2, 'id': 'header'})
+ if _cacheRegion_header.isNew():
+ _RECACHE_header = True
+ _cacheItem_header = _cacheRegion_header.getCacheItem('header')
+ if _cacheItem_header.hasExpired():
+ _RECACHE_header = True
+ if (not _RECACHE_header) and _cacheItem_header.getRefreshTime():
+ try:
+ _output = _cacheItem_header.renderOutput()
+ except KeyError:
+ _RECACHE_header = True
+ else:
+ write(_output)
+ del _output
+ if _RECACHE_header or not _cacheItem_header.getRefreshTime():
+ _orig_transheader = trans
+ trans = _cacheCollector_header = DummyTransaction()
+ write = _cacheCollector_header.response().write
+ _v = VFFSL(SL,"docType",True) # '$docType' on line 7, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$docType')) # from line 7, col 1.
+ write('\n')
+ _v = VFFSL(SL,"htmlTag",True) # '$htmlTag' on line 8, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$htmlTag')) # from line 8, col 1.
+ write('''
+<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org).
+Do not edit it directly!
+
+Copyright ''')
+ _v = VFFSL(SL,"currentYr",True) # '$currentYr' on line 12, col 11
+ if _v is not None: write(_filter(_v, rawExpr='$currentYr')) # from line 12, col 11.
+ write(' - ')
+ _v = VFFSL(SL,"siteCopyrightName",True) # '$siteCopyrightName' on line 12, col 24
+ if _v is not None: write(_filter(_v, rawExpr='$siteCopyrightName')) # from line 12, col 24.
+ write(' - All Rights Reserved.\nFeel free to copy any javascript or html you like on this site,\nprovided you remove all links and/or references to ')
+ _v = VFFSL(SL,"siteDomainName",True) # '$siteDomainName' on line 14, col 52
+ if _v is not None: write(_filter(_v, rawExpr='$siteDomainName')) # from line 14, col 52.
+ write('''
+However, please do not copy any content or images without permission.
+
+''')
+ _v = VFFSL(SL,"siteCredits",True) # '$siteCredits' on line 17, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$siteCredits')) # from line 17, col 1.
+ write('''
+
+-->
+
+
+''')
+ self.writeHeadTag(trans=trans)
+ write('\n')
+ trans = _orig_transheader
+ write = trans.response().write
+ _cacheData = _cacheCollector_header.response().getvalue()
+ _cacheItem_header.setData(_cacheData)
+ write(_cacheData)
+ del _cacheData
+ del _cacheCollector_header
+ del _orig_transheader
+ ## END CACHE REGION: header
+
+ write('\n')
+ _v = VFFSL(SL,"bodyTag",True) # '$bodyTag' on line 34, col 1
+ if _v is not None: write(_filter(_v, rawExpr='$bodyTag')) # from line 34, col 1.
+ write('\n\n')
+ self.writeBody(trans=trans)
+ write('''
+</body>
+</html>
+
+
+
+''')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+ ##################################################
+ ## CHEETAH GENERATED ATTRIBUTES
+
+
+ _CHEETAH__instanceInitialized = False
+
+ _CHEETAH_version = __CHEETAH_version__
+
+ _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+ _CHEETAH_genTime = __CHEETAH_genTime__
+
+ _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+ _CHEETAH_src = __CHEETAH_src__
+
+ _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+ _mainCheetahMethod_for_SkeletonPage= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(SkeletonPage, '_initCheetahAttributes'):
+ templateAPIClass = getattr(SkeletonPage, '_CHEETAH_templateClass', Template)
+ templateAPIClass._addCheetahPlumbingCodeToClass(SkeletonPage)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+ from Cheetah.TemplateCmdLineIface import CmdLineIface
+ CmdLineIface(templateObj=SkeletonPage()).run()
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/SkeletonPage.tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+##doc-module: A Skeleton HTML page template, that provides basic structure and utility methods.
+################################################################################
+#extends Cheetah.Templates._SkeletonPage
+#implements respond
+################################################################################
+#cache id='header'
+$docType
+$htmlTag
+<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org).
+Do not edit it directly!
+
+Copyright $currentYr - $siteCopyrightName - All Rights Reserved.
+Feel free to copy any javascript or html you like on this site,
+provided you remove all links and/or references to $siteDomainName
+However, please do not copy any content or images without permission.
+
+$siteCredits
+
+-->
+
+
+#block writeHeadTag
+<head>
+<title>$title</title>
+$metaTags
+$stylesheetTags
+$javascriptTags
+</head>
+#end block writeHeadTag
+
+#end cache header
+#################
+
+$bodyTag
+
+#block writeBody
+This skeleton page has no flesh. Its body needs to be implemented.
+#end block writeBody
+
+</body>
+</html>
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/_SkeletonPage.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/_SkeletonPage.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/_SkeletonPage.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+# $Id: _SkeletonPage.py,v 1.13 2002/10/01 17:52:02 tavis_rudd Exp $
+"""A baseclass for the SkeletonPage template
+
+Meta-Data
+==========
+Author: Tavis Rudd <tavis at damnsimple.com>,
+Version: $Revision: 1.13 $
+Start Date: 2001/04/05
+Last Revision Date: $Date: 2002/10/01 17:52:02 $
+"""
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.13 $"[11:-2]
+
+##################################################
+## DEPENDENCIES ##
+
+import time, types, os, sys
+
+# intra-package imports ...
+from Cheetah.Template import Template
+
+
+##################################################
+## GLOBALS AND CONSTANTS ##
+
+True = (1==1)
+False = (0==1)
+
+##################################################
+## CLASSES ##
+
+class _SkeletonPage(Template):
+ """A baseclass for the SkeletonPage template"""
+
+ docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ' + \
+ '"http://www.w3.org/TR/html4/loose.dtd">'
+
+ # docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' + \
+ #'"http://www.w3.org/TR/xhtml1l/DTD/transitional.dtd">'
+
+ title = ''
+ siteDomainName = 'www.example.com'
+ siteCredits = 'Designed & Implemented by Tavis Rudd'
+ siteCopyrightName = "Tavis Rudd"
+ htmlTag = '<html>'
+
+ def __init__(self, *args, **KWs):
+ Template.__init__(self, *args, **KWs)
+ self._metaTags = {'HTTP-EQUIV':{'keywords':'Cheetah',
+ 'Content-Type':'text/html; charset=iso-8859-1',
+ },
+ 'NAME':{'generator':'Cheetah: The Python-Powered Template Engine'}
+ }
+ # metaTags = {'HTTP_EQUIV':{'test':1234}, 'NAME':{'test':1234,'test2':1234} }
+ self._stylesheets = {}
+ # stylesheets = {'.cssClassName':'stylesheetCode'}
+ self._stylesheetsOrder = []
+ # stylesheetsOrder = ['.cssClassName',]
+ self._stylesheetLibs = {}
+ # stylesheetLibs = {'libName':'libSrcPath'}
+ self._javascriptLibs = {}
+ self._javascriptTags = {}
+ # self._javascriptLibs = {'libName':'libSrcPath'}
+ self._bodyTagAttribs = {}
+
+ def metaTags(self):
+ """Return a formatted vesion of the self._metaTags dictionary, using the
+ formatMetaTags function from Cheetah.Macros.HTML"""
+
+ return self.formatMetaTags(self._metaTags)
+
+ def stylesheetTags(self):
+ """Return a formatted version of the self._stylesheetLibs and
+ self._stylesheets dictionaries. The keys in self._stylesheets must
+ be listed in the order that they should appear in the list
+ self._stylesheetsOrder, to ensure that the style rules are defined in
+ the correct order."""
+
+ stylesheetTagsTxt = ''
+ for title, src in self._stylesheetLibs.items():
+ stylesheetTagsTxt += '<link rel="stylesheet" type="text/css" href="' + str(src) + '" />\n'
+
+ if not self._stylesheetsOrder:
+ return stylesheetTagsTxt
+
+ stylesheetTagsTxt += '<style type="text/css"><!--\n'
+ for identifier in self._stylesheetsOrder:
+ if not self._stylesheets.has_key(identifier):
+ warning = '# the identifier ' + identifier + \
+ 'was in stylesheetsOrder, but not in stylesheets'
+ print warning
+ stylesheetTagsTxt += warning
+ continue
+
+ attribsDict = self._stylesheets[identifier]
+ cssCode = ''
+ attribCode = ''
+ for k, v in attribsDict.items():
+ attribCode += str(k) + ': ' + str(v) + '; '
+ attribCode = attribCode[:-2] # get rid of the last semicolon
+
+ cssCode = '\n' + identifier + ' {' + attribCode + '}'
+ stylesheetTagsTxt += cssCode
+
+ stylesheetTagsTxt += '\n//--></style>\n'
+
+ return stylesheetTagsTxt
+
+ def javascriptTags(self):
+ """Return a formatted version of the javascriptTags and
+ javascriptLibs dictionaries. Each value in javascriptTags
+ should be a either a code string to include, or a list containing the
+ JavaScript version number and the code string. The keys can be anything.
+ The same applies for javascriptLibs, but the string should be the
+ SRC filename rather than a code string."""
+
+ javascriptTagsTxt = []
+ for key, details in self._javascriptTags.items():
+ if type(details) not in (types.ListType, types.TupleType):
+ details = ['',details]
+
+ javascriptTagsTxt += ['<script language="JavaScript', str(details[0]),
+ '" type="text/javascript"><!--\n',
+ str(details[0]), '\n//--></script>\n']
+
+
+ for key, details in self._javascriptLibs.items():
+ if type(details) not in (types.ListType, types.TupleType):
+ details = ['',details]
+
+ javascriptTagsTxt += ['<script language="JavaScript', str(details[0]),
+ '" type="text/javascript" src="',
+ str(details[1]), '" />\n']
+ return ''.join(javascriptTagsTxt)
+
+ def bodyTag(self):
+ """Create a body tag from the entries in the dict bodyTagAttribs."""
+ return self.formHTMLTag('body', self._bodyTagAttribs)
+
+
+ def imgTag(self, src, alt='', width=None, height=None, border=0):
+
+ """Dynamically generate an image tag. Cheetah will try to convert the
+ src argument to a WebKit serverSidePath relative to the servlet's
+ location. If width and height aren't specified they are calculated using
+ PIL or ImageMagick if available."""
+
+ src = self.normalizePath(src)
+
+
+ if not width or not height:
+ try: # see if the dimensions can be calc'd with PIL
+ import Image
+ im = Image.open(src)
+ calcWidth, calcHeight = im.size
+ del im
+ if not width: width = calcWidth
+ if not height: height = calcHeight
+
+ except:
+ try: # try imageMagick instead
+ calcWidth, calcHeight = os.popen(
+ 'identify -format "%w,%h" ' + src).read().split(',')
+ if not width: width = calcWidth
+ if not height: height = calcHeight
+
+ except:
+ pass
+
+ if width and height:
+ return ''.join(['<img src="', src, '" width="', str(width), '" height="', str(height),
+ '" alt="', alt, '" border="', str(border), '" />'])
+ elif width:
+ return ''.join(['<img src="', src, '" width="', str(width),
+ '" alt="', alt, '" border="', str(border), '" />'])
+ elif height:
+ return ''.join(['<img src="', src, '" height="', str(height),
+ '" alt="', alt, '" border="', str(border), '" />'])
+ else:
+ return ''.join(['<img src="', src, '" alt="', alt, '" border="', str(border),'" />'])
+
+
+ def currentYr(self):
+ """Return a string representing the current yr."""
+ return time.strftime("%Y",time.localtime(time.time()))
+
+ def currentDate(self, formatString="%b %d, %Y"):
+ """Return a string representing the current localtime."""
+ return time.strftime(formatString,time.localtime(time.time()))
+
+ def spacer(self, width=1,height=1):
+ return '<img src="spacer.gif" width="%s" height="%s" alt="" />'% (str(width), str(height))
+
+ def formHTMLTag(self, tagName, attributes={}):
+ """returns a string containing an HTML <tag> """
+ tagTxt = ['<', tagName.lower()]
+ for name, val in attributes.items():
+ tagTxt += [' ', name.lower(), '="', str(val),'"']
+ tagTxt.append('>')
+ return ''.join(tagTxt)
+
+ def formatMetaTags(self, metaTags):
+ """format a dict of metaTag definitions into an HTML version"""
+ metaTagsTxt = []
+ if metaTags.has_key('HTTP-EQUIV'):
+ for http_equiv, contents in metaTags['HTTP-EQUIV'].items():
+ metaTagsTxt += ['<meta http-equiv="', str(http_equiv), '" content="',
+ str(contents), '" />\n']
+
+ if metaTags.has_key('NAME'):
+ for name, contents in metaTags['NAME'].items():
+ metaTagsTxt += ['<meta name="', str(name), '" content="', str(contents),
+ '" />\n']
+ return ''.join(metaTagsTxt)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Templates/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#!/usr/bin/env python
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/CheetahWrapper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/CheetahWrapper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/CheetahWrapper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,550 @@
+#!/usr/bin/env python
+'''
+Tests for the 'cheetah' command.
+
+Besides unittest usage, recognizes the following command-line options:
+ --list CheetahWrapper.py
+ List all scenarios that are tested. The argument is the path
+ of this script.
+ --nodelete
+ Don't delete scratch directory at end.
+ --output
+ Show the output of each subcommand. (Normally suppressed.)
+'''
+import commands, os, shutil, sys, tempfile
+import unittest_local_copy as unittest
+
+import re # Used by listTests.
+from optparse import OptionParser
+from Cheetah.CheetahWrapper import CheetahWrapper # Used by NoBackup.
+
+
+DELETE = True # True to clean up after ourselves, False for debugging.
+OUTPUT = False # Normally False, True for debugging.
+
+BACKUP_SUFFIX = CheetahWrapper.BACKUP_SUFFIX
+
+def warn(msg):
+ sys.stderr.write(msg + '\n')
+
+class CFBase(unittest.TestCase):
+ """Base class for "cheetah compile" and "cheetah fill" unit tests.
+ """
+ srcDir = '' # Nonblank to create source directory.
+ subdirs = ('child', 'child/grandkid') # Delete in reverse order.
+ srcFiles = ('a.tmpl', 'child/a.tmpl', 'child/grandkid/a.tmpl')
+ expectError = False # Used by --list option.
+
+ def inform(self, message):
+ if self.verbose:
+ print message
+
+ def setUp(self):
+ """Create the top-level directories, subdirectories and .tmpl
+ files.
+ """
+ I = self.inform
+ # Step 1: Create the scratch directory and chdir into it.
+ self.scratchDir = scratchDir = tempfile.mktemp()
+ os.mkdir(scratchDir)
+ self.origCwd = os.getcwd()
+ os.chdir(scratchDir)
+ if self.srcDir:
+ os.mkdir(self.srcDir)
+ # Step 2: Create source subdirectories.
+ for dir in self.subdirs:
+ os.mkdir(dir)
+ # Step 3: Create the .tmpl files, each in its proper directory.
+ for fil in self.srcFiles:
+ f = open(fil, 'w')
+ f.write("Hello, world!\n")
+ f.close()
+
+
+ def tearDown(self):
+ os.chdir(self.origCwd)
+ if DELETE:
+ shutil.rmtree(self.scratchDir, True) # Ignore errors.
+ if os.path.exists(self.scratchDir):
+ warn("Warning: unable to delete scratch directory %s")
+ else:
+ warn("Warning: not deleting scratch directory %s" % self.scratchDir)
+
+
+ def _checkDestFileHelper(self, path, expected,
+ allowSurroundingText, errmsg):
+ """Low-level helper to check a destination file.
+
+ in : path, string, the destination path.
+ expected, string, the expected contents.
+ allowSurroundingtext, bool, allow the result to contain
+ additional text around the 'expected' substring?
+ errmsg, string, the error message. It may contain the
+ following "%"-operator keys: path, expected, result.
+ out: None
+ """
+ path = os.path.abspath(path)
+ exists = os.path.exists(path)
+ msg = "destination file missing: %s" % path
+ self.failUnless(exists, msg)
+ f = open(path, 'r')
+ result = f.read()
+ f.close()
+ if allowSurroundingText:
+ success = result.find(expected) != -1
+ else:
+ success = result == expected
+ msg = errmsg % locals()
+ self.failUnless(success, msg)
+
+
+ def checkCompile(self, path):
+ # Raw string to prevent "\n" from being converted to a newline.
+ #expected = R"write('Hello, world!\n')"
+ expected = "Hello, world!" # might output a u'' string
+ errmsg = """\
+destination file %(path)s doesn't contain expected substring:
+%(expected)r"""
+ self._checkDestFileHelper(path, expected, True, errmsg)
+
+
+ def checkFill(self, path):
+ expected = "Hello, world!\n"
+ errmsg = """\
+destination file %(path)s contains wrong result.
+Expected %(expected)r
+Found %(result)r"""
+ self._checkDestFileHelper(path, expected, False, errmsg)
+
+
+ def checkSubdirPyInit(self, path):
+ """Verify a destination subdirectory exists and contains an
+ __init__.py file.
+ """
+ exists = os.path.exists(path)
+ msg = "destination subdirectory %s misssing" % path
+ self.failUnless(exists, msg)
+ initPath = os.path.join(path, "__init__.py")
+ exists = os.path.exists(initPath)
+ msg = "destination init file missing: %s" % initPath
+ self.failUnless(exists, msg)
+
+
+ def checkNoBackup(self, path):
+ """Verify 'path' does not exist. (To check --nobackup.)
+ """
+ exists = os.path.exists(path)
+ msg = "backup file exists in spite of --nobackup: %s" % path
+ self.failIf(exists, msg)
+
+
+ def go(self, cmd, expectedStatus=0, expectedOutputSubstring=None):
+ """Run a "cheetah compile" or "cheetah fill" subcommand.
+
+ in : cmd, string, the command to run.
+ expectedStatus, int, subcommand's expected output status.
+ 0 if the subcommand is expected to succeed, 1-255 otherwise.
+ expectedOutputSubstring, string, substring which much appear
+ in the standard output or standard error. None to skip this
+ test.
+ out: None.
+ """
+ # Use commands.getstatusoutput instead of os.system so
+ # that we can mimic ">/dev/null 2>/dev/null" even on
+ # non-Unix platforms.
+ exit, output = commands.getstatusoutput(cmd)
+ status, signal = divmod(exit, 256)
+ if OUTPUT:
+ if output.endswith("\n"):
+ output = output[:-1]
+ print
+ print "SUBCOMMAND:", cmd
+ print output
+ print
+ msg = "subcommand killed by signal %d: %s" % (signal, cmd)
+ self.failUnlessEqual(signal, 0, msg)
+ msg = "subcommand exit status %d: %s" % (status, cmd)
+ if status!=expectedStatus:
+ print output
+ self.failUnlessEqual(status, expectedStatus, msg)
+ if expectedOutputSubstring is not None:
+ msg = "substring %r not found in subcommand output: %s" % \
+ (expectedOutputSubstring, cmd)
+ substringTest = output.find(expectedOutputSubstring) != -1
+ self.failUnless(substringTest, msg)
+
+
+ def goExpectError(self, cmd):
+ """Run a subcommand and expect it to fail.
+
+ in : cmd, string, the command to run.
+ out: None.
+ """
+ # Use commands.getstatusoutput instead of os.system so
+ # that we can mimic ">/dev/null 2>/dev/null" even on
+ # non-Unix platforms.
+ exit, output = commands.getstatusoutput(cmd)
+ status, signal = divmod(exit, 256)
+ msg = "subcommand killed by signal %s: %s" % (signal, cmd)
+ self.failUnlessEqual(signal, 0, msg) # Signal must be 0.
+ msg = "subcommand exit status %s: %s" % (status, cmd)
+ self.failIfEqual(status, 0, msg) # Status must *not* be 0.
+ if OUTPUT:
+ if output.endswith("\n"):
+ output = output[:-1]
+ print
+ print "SUBCOMMAND:", cmd
+ print output
+ print
+
+
+class CFIdirBase(CFBase):
+ """Subclass for tests with --idir.
+ """
+ srcDir = 'SRC'
+ subdirs = ('SRC/child', 'SRC/child/grandkid') # Delete in reverse order.
+ srcFiles = ('SRC/a.tmpl', 'SRC/child/a.tmpl', 'SRC/child/grandkid/a.tmpl')
+
+
+
+##################################################
+## TEST CASE CLASSES
+
+class OneFile(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile a.tmpl")
+ self.checkCompile("a.py")
+
+ def testFill(self):
+ self.go("cheetah fill a.tmpl")
+ self.checkFill("a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt a.tmpl")
+ self.checkFill("a.txt")
+
+
+class OneFileNoExtension(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile a")
+ self.checkCompile("a.py")
+
+ def testFill(self):
+ self.go("cheetah fill a")
+ self.checkFill("a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt a")
+ self.checkFill("a.txt")
+
+
+class SplatTmpl(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile *.tmpl")
+ self.checkCompile("a.py")
+
+ def testFill(self):
+ self.go("cheetah fill *.tmpl")
+ self.checkFill("a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt *.tmpl")
+ self.checkFill("a.txt")
+
+class ThreeFilesWithSubdirectories(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile a.tmpl child/a.tmpl child/grandkid/a.tmpl")
+ self.checkCompile("a.py")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill a.tmpl child/a.tmpl child/grandkid/a.tmpl")
+ self.checkFill("a.html")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt a.tmpl child/a.tmpl child/grandkid/a.tmpl")
+ self.checkFill("a.txt")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class ThreeFilesWithSubdirectoriesNoExtension(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile a child/a child/grandkid/a")
+ self.checkCompile("a.py")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill a child/a child/grandkid/a")
+ self.checkFill("a.html")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt a child/a child/grandkid/a")
+ self.checkFill("a.txt")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class SplatTmplWithSubdirectories(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile *.tmpl child/*.tmpl child/grandkid/*.tmpl")
+ self.checkCompile("a.py")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill *.tmpl child/*.tmpl child/grandkid/*.tmpl")
+ self.checkFill("a.html")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill --oext txt *.tmpl child/*.tmpl child/grandkid/*.tmpl")
+ self.checkFill("a.txt")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class OneFileWithOdir(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile --odir DEST a.tmpl")
+ self.checkSubdirPyInit("DEST")
+ self.checkCompile("DEST/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill --odir DEST a.tmpl")
+ self.checkFill("DEST/a.html")
+
+ def testText(self):
+ self.go("cheetah fill --odir DEST --oext txt a.tmpl")
+ self.checkFill("DEST/a.txt")
+
+
+class VarietyWithOdir(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile --odir DEST a.tmpl child/a child/grandkid/*.tmpl")
+ self.checkSubdirPyInit("DEST")
+ self.checkSubdirPyInit("DEST/child")
+ self.checkSubdirPyInit("DEST/child/grandkid")
+ self.checkCompile("DEST/a.py")
+ self.checkCompile("DEST/child/a.py")
+ self.checkCompile("DEST/child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill --odir DEST a.tmpl child/a child/grandkid/*.tmpl")
+ self.checkFill("DEST/a.html")
+ self.checkFill("DEST/child/a.html")
+ self.checkFill("DEST/child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill --odir DEST --oext txt a.tmpl child/a child/grandkid/*.tmpl")
+ self.checkFill("DEST/a.txt")
+ self.checkFill("DEST/child/a.txt")
+ self.checkFill("DEST/child/grandkid/a.txt")
+
+
+class RecurseExplicit(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile -R child")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill -R child")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill -R --oext txt child")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class RecurseImplicit(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile -R")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill -R")
+ self.checkFill("a.html")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill -R --oext txt")
+ self.checkFill("a.txt")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class RecurseExplicitWIthOdir(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile -R --odir DEST child")
+ self.checkSubdirPyInit("DEST/child")
+ self.checkSubdirPyInit("DEST/child/grandkid")
+ self.checkCompile("DEST/child/a.py")
+ self.checkCompile("DEST/child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill -R --odir DEST child")
+ self.checkFill("DEST/child/a.html")
+ self.checkFill("DEST/child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill -R --odir DEST --oext txt child")
+ self.checkFill("DEST/child/a.txt")
+ self.checkFill("DEST/child/grandkid/a.txt")
+
+
+class Flat(CFBase):
+ def testCompile(self):
+ self.go("cheetah compile --flat child/a.tmpl")
+ self.checkCompile("a.py")
+
+ def testFill(self):
+ self.go("cheetah fill --flat child/a.tmpl")
+ self.checkFill("a.html")
+
+ def testText(self):
+ self.go("cheetah fill --flat --oext txt child/a.tmpl")
+ self.checkFill("a.txt")
+
+
+class FlatRecurseCollision(CFBase):
+ expectError = True
+
+ def testCompile(self):
+ self.goExpectError("cheetah compile -R --flat")
+
+ def testFill(self):
+ self.goExpectError("cheetah fill -R --flat")
+
+ def testText(self):
+ self.goExpectError("cheetah fill -R --flat")
+
+
+class IdirRecurse(CFIdirBase):
+ def testCompile(self):
+ self.go("cheetah compile -R --idir SRC child")
+ self.checkSubdirPyInit("child")
+ self.checkSubdirPyInit("child/grandkid")
+ self.checkCompile("child/a.py")
+ self.checkCompile("child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill -R --idir SRC child")
+ self.checkFill("child/a.html")
+ self.checkFill("child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill -R --idir SRC --oext txt child")
+ self.checkFill("child/a.txt")
+ self.checkFill("child/grandkid/a.txt")
+
+
+class IdirOdirRecurse(CFIdirBase):
+ def testCompile(self):
+ self.go("cheetah compile -R --idir SRC --odir DEST child")
+ self.checkSubdirPyInit("DEST/child")
+ self.checkSubdirPyInit("DEST/child/grandkid")
+ self.checkCompile("DEST/child/a.py")
+ self.checkCompile("DEST/child/grandkid/a.py")
+
+ def testFill(self):
+ self.go("cheetah fill -R --idir SRC --odir DEST child")
+ self.checkFill("DEST/child/a.html")
+ self.checkFill("DEST/child/grandkid/a.html")
+
+ def testText(self):
+ self.go("cheetah fill -R --idir SRC --odir DEST --oext txt child")
+ self.checkFill("DEST/child/a.txt")
+ self.checkFill("DEST/child/grandkid/a.txt")
+
+
+class IdirFlatRecurseCollision(CFIdirBase):
+ expectError = True
+
+ def testCompile(self):
+ self.goExpectError("cheetah compile -R --flat --idir SRC")
+
+ def testFill(self):
+ self.goExpectError("cheetah fill -R --flat --idir SRC")
+
+ def testText(self):
+ self.goExpectError("cheetah fill -R --flat --idir SRC --oext txt")
+
+
+class NoBackup(CFBase):
+ """Run the command twice each time and verify a backup file is
+ *not* created.
+ """
+ def testCompile(self):
+ self.go("cheetah compile --nobackup a.tmpl")
+ self.go("cheetah compile --nobackup a.tmpl")
+ self.checkNoBackup("a.py" + BACKUP_SUFFIX)
+
+ def testFill(self):
+ self.go("cheetah fill --nobackup a.tmpl")
+ self.go("cheetah fill --nobackup a.tmpl")
+ self.checkNoBackup("a.html" + BACKUP_SUFFIX)
+
+ def testText(self):
+ self.go("cheetah fill --nobackup --oext txt a.tmpl")
+ self.go("cheetah fill --nobackup --oext txt a.tmpl")
+ self.checkNoBackup("a.txt" + BACKUP_SUFFIX)
+
+def listTests(cheetahWrapperFile):
+ """cheetahWrapperFile, string, path of this script.
+
+ XXX TODO: don't print test where expectError is true.
+ """
+ rx = re.compile( R'self\.go\("(.*?)"\)' )
+ f = open(cheetahWrapperFile)
+ while 1:
+ lin = f.readline()
+ if not lin:
+ break
+ m = rx.search(lin)
+ if m:
+ print m.group(1)
+ f.close()
+
+def main():
+ global DELETE, OUTPUT
+ parser = OptionParser()
+ parser.add_option("--list", action="store", dest="listTests")
+ parser.add_option("--nodelete", action="store_true")
+ parser.add_option("--output", action="store_true")
+ # The following options are passed to unittest.
+ parser.add_option("-e", "--explain", action="store_true")
+ parser.add_option("-v", "--verbose", action="store_true")
+ parser.add_option("-q", "--quiet", action="store_true")
+ opts, files = parser.parse_args()
+ if opts.nodelete:
+ DELETE = False
+ if opts.output:
+ OUTPUT = True
+ if opts.listTests:
+ listTests(opts.listTests)
+ else:
+ # Eliminate script-specific command-line arguments to prevent
+ # errors in unittest.
+ del sys.argv[1:]
+ for opt in ("explain", "verbose", "quiet"):
+ if getattr(opts, opt):
+ sys.argv.append("--" + opt)
+ sys.argv.extend(files)
+ unittest.main()
+
+if __name__ == '__main__':
+ main()
+
+# vim: sw=4 ts=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Filters.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Filters.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Filters.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+import sys
+
+import Cheetah.Template
+import Cheetah.Filters
+
+import unittest_local_copy as unittest
+
+majorVer, minorVer = sys.version_info[0], sys.version_info[1]
+versionTuple = (majorVer, minorVer)
+
+class BasicMarkdownFilterTest(unittest.TestCase):
+ '''
+ Test that our markdown filter works
+ '''
+ def test_BasicHeader(self):
+ template = '''
+#from Cheetah.Filters import Markdown
+#transform Markdown
+$foo
+
+Header
+======
+ '''
+ expected = '''<p>bar</p>
+<h1>Header</h1>'''
+ try:
+ template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
+ template = str(template)
+ assert template == expected
+ except Exception, ex:
+ if ex.__class__.__name__ == 'MarkdownException' and majorVer == 2 and minorVer < 5:
+ print '>>> NOTE: Support for the Markdown filter will be broken for you. Markdown says: %s' % ex
+ return
+ raise
+
+
+class BasicCodeHighlighterFilterTest(unittest.TestCase):
+ '''
+ Test that our code highlighter filter works
+ '''
+ def test_Python(self):
+ template = '''
+#from Cheetah.Filters import CodeHighlighter
+#transform CodeHighlighter
+
+def foo(self):
+ return '$foo'
+ '''
+ template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
+ template = str(template)
+ assert template, (template, 'We should have some content here...')
+
+ def test_Html(self):
+ template = '''
+#from Cheetah.Filters import CodeHighlighter
+#transform CodeHighlighter
+
+<html><head></head><body>$foo</body></html>
+ '''
+ template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}])
+ template = str(template)
+ assert template, (template, 'We should have some content here...')
+
+
+if __name__ == '__main__':
+ unittest.main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/NameMapper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/NameMapper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/NameMapper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,539 @@
+#!/usr/bin/env python
+# $Id: NameMapper.py,v 1.11 2006/01/15 20:45:22 tavis_rudd Exp $
+"""NameMapper Tests
+
+Meta-Data
+================================================================================
+Author: Tavis Rudd <tavis at damnsimple.com>,
+Version: $Revision: 1.11 $
+Start Date: 2001/10/01
+Last Revision Date: $Date: 2006/01/15 20:45:22 $
+"""
+from __future__ import generators
+__author__ = "Tavis Rudd <tavis at damnsimple.com>"
+__revision__ = "$Revision: 1.11 $"[11:-2]
+import sys
+import types
+import os
+import os.path
+
+import unittest_local_copy as unittest
+from Cheetah.NameMapper import NotFound, valueForKey, \
+ valueForName, valueFromSearchList, valueFromFrame, valueFromFrameOrSearchList
+
+
+##################################################
+## TEST DATA FOR USE IN THE TEMPLATES ##
+
+class DummyClass:
+ classVar1 = 123
+
+ def __init__(self):
+ self.instanceVar1 = 123
+
+ def __str__(self):
+ return 'object'
+
+ def meth(self, arg="arff"):
+ return str(arg)
+
+ def meth1(self, arg="doo"):
+ return arg
+
+ def meth2(self, arg1="a1", arg2="a2"):
+ raise ValueError
+
+ def meth3(self):
+ """Tests a bug that Jeff Johnson reported on Oct 1, 2001"""
+
+ x = 'A string'
+ try:
+ for i in [1,2,3,4]:
+ if x == 2:
+ pass
+
+ if x == 'xx':
+ pass
+ return x
+ except:
+ raise
+
+
+def dummyFunc(arg="Scooby"):
+ return arg
+
+def funcThatRaises():
+ raise ValueError
+
+
+testNamespace = {
+ 'aStr':'blarg',
+ 'anInt':1,
+ 'aFloat':1.5,
+ 'aDict': {'one':'item1',
+ 'two':'item2',
+ 'nestedDict':{'one':'nestedItem1',
+ 'two':'nestedItem2',
+ 'funcThatRaises':funcThatRaises,
+ 'aClass': DummyClass,
+ },
+ 'nestedFunc':dummyFunc,
+ },
+ 'aClass': DummyClass,
+ 'aFunc': dummyFunc,
+ 'anObj': DummyClass(),
+ 'aMeth': DummyClass().meth1,
+ 'none' : None,
+ 'emptyString':'',
+ 'funcThatRaises':funcThatRaises,
+ }
+
+autoCallResults = {'aFunc':'Scooby',
+ 'aMeth':'doo',
+ }
+
+results = testNamespace.copy()
+results.update({'anObj.meth1':'doo',
+ 'aDict.one':'item1',
+ 'aDict.nestedDict':testNamespace['aDict']['nestedDict'],
+ 'aDict.nestedDict.one':'nestedItem1',
+ 'aDict.nestedDict.aClass':DummyClass,
+ 'aDict.nestedFunc':'Scooby',
+ 'aClass.classVar1':123,
+ 'anObj.instanceVar1':123,
+ 'anObj.meth3':'A string',
+ })
+
+for k in testNamespace.keys():
+ # put them in the globals for the valueFromFrame tests
+ exec '%s = testNamespace[k]'%k
+
+##################################################
+## TEST BASE CLASSES
+
+class NameMapperTest(unittest.TestCase):
+ failureException = (NotFound,AssertionError)
+ _testNamespace = testNamespace
+ _results = results
+
+ def namespace(self):
+ return self._testNamespace
+
+ def VFN(self, name, autocall=True):
+ return valueForName(self.namespace(), name, autocall)
+
+ def VFS(self, searchList, name, autocall=True):
+ return valueFromSearchList(searchList, name, autocall)
+
+
+ # alias to be overriden later
+ get = VFN
+
+ def check(self, name):
+ got = self.get(name)
+ if autoCallResults.has_key(name):
+ expected = autoCallResults[name]
+ else:
+ expected = self._results[name]
+ assert got == expected
+
+
+##################################################
+## TEST CASE CLASSES
+
+class VFN(NameMapperTest):
+
+ def test1(self):
+ """string in dict lookup"""
+ self.check('aStr')
+
+ def test2(self):
+ """string in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aStr')
+
+ def test3(self):
+ """int in dict lookup"""
+ self.check('anInt')
+
+ def test4(self):
+ """int in dict lookup in a loop"""
+ for i in range(10):
+ self.check('anInt')
+
+ def test5(self):
+ """float in dict lookup"""
+ self.check('aFloat')
+
+ def test6(self):
+ """float in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aFloat')
+
+ def test7(self):
+ """class in dict lookup"""
+ self.check('aClass')
+
+ def test8(self):
+ """class in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aClass')
+
+ def test9(self):
+ """aFunc in dict lookup"""
+ self.check('aFunc')
+
+ def test10(self):
+ """aFunc in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aFunc')
+
+ def test11(self):
+ """aMeth in dict lookup"""
+ self.check('aMeth')
+
+ def test12(self):
+ """aMeth in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aMeth')
+
+ def test13(self):
+ """aMeth in dict lookup"""
+ self.check('aMeth')
+
+ def test14(self):
+ """aMeth in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aMeth')
+
+ def test15(self):
+ """anObj in dict lookup"""
+ self.check('anObj')
+
+ def test16(self):
+ """anObj in dict lookup in a loop"""
+ for i in range(10):
+ self.check('anObj')
+
+ def test17(self):
+ """aDict in dict lookup"""
+ self.check('aDict')
+
+ def test18(self):
+ """aDict in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict')
+
+ def test17(self):
+ """aDict in dict lookup"""
+ self.check('aDict')
+
+ def test18(self):
+ """aDict in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict')
+
+ def test19(self):
+ """aClass.classVar1 in dict lookup"""
+ self.check('aClass.classVar1')
+
+ def test20(self):
+ """aClass.classVar1 in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aClass.classVar1')
+
+
+ def test23(self):
+ """anObj.instanceVar1 in dict lookup"""
+ self.check('anObj.instanceVar1')
+
+ def test24(self):
+ """anObj.instanceVar1 in dict lookup in a loop"""
+ for i in range(10):
+ self.check('anObj.instanceVar1')
+
+ ## tests 22, 25, and 26 removed when the underscored lookup was removed
+
+ def test27(self):
+ """anObj.meth1 in dict lookup"""
+ self.check('anObj.meth1')
+
+ def test28(self):
+ """anObj.meth1 in dict lookup in a loop"""
+ for i in range(10):
+ self.check('anObj.meth1')
+
+ def test29(self):
+ """aDict.one in dict lookup"""
+ self.check('aDict.one')
+
+ def test30(self):
+ """aDict.one in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict.one')
+
+ def test31(self):
+ """aDict.nestedDict in dict lookup"""
+ self.check('aDict.nestedDict')
+
+ def test32(self):
+ """aDict.nestedDict in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict.nestedDict')
+
+ def test33(self):
+ """aDict.nestedDict.one in dict lookup"""
+ self.check('aDict.nestedDict.one')
+
+ def test34(self):
+ """aDict.nestedDict.one in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict.nestedDict.one')
+
+ def test35(self):
+ """aDict.nestedFunc in dict lookup"""
+ self.check('aDict.nestedFunc')
+
+ def test36(self):
+ """aDict.nestedFunc in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict.nestedFunc')
+
+ def test37(self):
+ """aDict.nestedFunc in dict lookup - without autocalling"""
+ assert self.get('aDict.nestedFunc', False) == dummyFunc
+
+ def test38(self):
+ """aDict.nestedFunc in dict lookup in a loop - without autocalling"""
+ for i in range(10):
+ assert self.get('aDict.nestedFunc', False) == dummyFunc
+
+ def test39(self):
+ """aMeth in dict lookup - without autocalling"""
+ assert self.get('aMeth', False) == self.namespace()['aMeth']
+
+ def test40(self):
+ """aMeth in dict lookup in a loop - without autocalling"""
+ for i in range(10):
+ assert self.get('aMeth', False) == self.namespace()['aMeth']
+
+ def test41(self):
+ """anObj.meth3 in dict lookup"""
+ self.check('anObj.meth3')
+
+ def test42(self):
+ """aMeth in dict lookup in a loop"""
+ for i in range(10):
+ self.check('anObj.meth3')
+
+ def test43(self):
+ """NotFound test"""
+
+ def test(self=self):
+ self.get('anObj.methX')
+ self.assertRaises(NotFound,test)
+
+ def test44(self):
+ """NotFound test in a loop"""
+ def test(self=self):
+ self.get('anObj.methX')
+
+ for i in range(10):
+ self.assertRaises(NotFound,test)
+
+ def test45(self):
+ """Other exception from meth test"""
+
+ def test(self=self):
+ self.get('anObj.meth2')
+ self.assertRaises(ValueError, test)
+
+ def test46(self):
+ """Other exception from meth test in a loop"""
+ def test(self=self):
+ self.get('anObj.meth2')
+
+ for i in range(10):
+ self.assertRaises(ValueError,test)
+
+ def test47(self):
+ """None in dict lookup"""
+ self.check('none')
+
+ def test48(self):
+ """None in dict lookup in a loop"""
+ for i in range(10):
+ self.check('none')
+
+ def test49(self):
+ """EmptyString in dict lookup"""
+ self.check('emptyString')
+
+ def test50(self):
+ """EmptyString in dict lookup in a loop"""
+ for i in range(10):
+ self.check('emptyString')
+
+ def test51(self):
+ """Other exception from func test"""
+
+ def test(self=self):
+ self.get('funcThatRaises')
+ self.assertRaises(ValueError, test)
+
+ def test52(self):
+ """Other exception from func test in a loop"""
+ def test(self=self):
+ self.get('funcThatRaises')
+
+ for i in range(10):
+ self.assertRaises(ValueError,test)
+
+
+ def test53(self):
+ """Other exception from func test"""
+
+ def test(self=self):
+ self.get('aDict.nestedDict.funcThatRaises')
+ self.assertRaises(ValueError, test)
+
+ def test54(self):
+ """Other exception from func test in a loop"""
+ def test(self=self):
+ self.get('aDict.nestedDict.funcThatRaises')
+
+ for i in range(10):
+ self.assertRaises(ValueError,test)
+
+ def test55(self):
+ """aDict.nestedDict.aClass in dict lookup"""
+ self.check('aDict.nestedDict.aClass')
+
+ def test56(self):
+ """aDict.nestedDict.aClass in dict lookup in a loop"""
+ for i in range(10):
+ self.check('aDict.nestedDict.aClass')
+
+ def test57(self):
+ """aDict.nestedDict.aClass in dict lookup - without autocalling"""
+ assert self.get('aDict.nestedDict.aClass', False) == DummyClass
+
+ def test58(self):
+ """aDict.nestedDict.aClass in dict lookup in a loop - without autocalling"""
+ for i in range(10):
+ assert self.get('aDict.nestedDict.aClass', False) == DummyClass
+
+ def test59(self):
+ """Other exception from func test -- but without autocalling shouldn't raise"""
+
+ self.get('aDict.nestedDict.funcThatRaises', False)
+
+ def test60(self):
+ """Other exception from func test in a loop -- but without autocalling shouldn't raise"""
+
+ for i in range(10):
+ self.get('aDict.nestedDict.funcThatRaises', False)
+
+class VFS(VFN):
+ _searchListLength = 1
+
+ def searchList(self):
+ lng = self._searchListLength
+ if lng == 1:
+ return [self.namespace()]
+ elif lng == 2:
+ return [self.namespace(),{'dummy':1234}]
+ elif lng == 3:
+ # a tuple for kicks
+ return ({'dummy':1234}, self.namespace(),{'dummy':1234})
+ elif lng == 4:
+ # a generator for more kicks
+ return self.searchListGenerator()
+
+ def searchListGenerator(self):
+ class Test:
+ pass
+ for i in [Test(),{'dummy':1234}, self.namespace(),{'dummy':1234}]:
+ yield i
+
+ def get(self, name, autocall=True):
+ return self.VFS(self.searchList(), name, autocall)
+
+class VFS_2namespaces(VFS):
+ _searchListLength = 2
+
+class VFS_3namespaces(VFS):
+ _searchListLength = 3
+
+class VFS_4namespaces(VFS):
+ _searchListLength = 4
+
+class VFF(VFN):
+ def get(self, name, autocall=True):
+ ns = self._testNamespace
+ aStr = ns['aStr']
+ aFloat = ns['aFloat']
+ none = 'some'
+ return valueFromFrame(name, autocall)
+
+ def setUp(self):
+ """Mod some of the data
+ """
+ self._testNamespace = ns = self._testNamespace.copy()
+ self._results = res = self._results.copy()
+ ns['aStr'] = res['aStr'] = 'BLARG'
+ ns['aFloat'] = res['aFloat'] = 0.1234
+ res['none'] = 'some'
+ res['True'] = True
+ res['False'] = False
+ res['None'] = None
+ res['eval'] = eval
+
+ def test_VFF_1(self):
+ """Builtins"""
+ self.check('True')
+ self.check('None')
+ self.check('False')
+ assert self.get('eval', False)==eval
+ assert self.get('range', False)==range
+
+class VFFSL(VFS):
+ _searchListLength = 1
+
+ def setUp(self):
+ """Mod some of the data
+ """
+ self._testNamespace = ns = self._testNamespace.copy()
+ self._results = res = self._results.copy()
+ ns['aStr'] = res['aStr'] = 'BLARG'
+ ns['aFloat'] = res['aFloat'] = 0.1234
+ res['none'] = 'some'
+
+ del ns['anInt'] # will be picked up by globals
+
+ def VFFSL(self, searchList, name, autocall=True):
+ anInt = 1
+ none = 'some'
+ return valueFromFrameOrSearchList(searchList, name, autocall)
+
+ def get(self, name, autocall=True):
+ return self.VFFSL(self.searchList(), name, autocall)
+
+class VFFSL_2(VFFSL):
+ _searchListLength = 2
+
+class VFFSL_3(VFFSL):
+ _searchListLength = 3
+
+class VFFSL_4(VFFSL):
+ _searchListLength = 4
+
+if sys.platform.startswith('java'):
+ del VFF, VFFSL, VFFSL_2, VFFSL_3, VFFSL_4
+
+
+##################################################
+## if run from the command line ##
+
+if __name__ == '__main__':
+ unittest.main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Regressions.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Regressions.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Regressions.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+import Cheetah.NameMapper
+import Cheetah.Template
+
+import pdb
+import sys
+
+import unittest_local_copy as unittest # This is just stupid
+
+majorVer, minorVer = sys.version_info[0], sys.version_info[1]
+versionTuple = (majorVer, minorVer)
+
+def isPython23():
+ ''' Python 2.3 is still supported by Cheetah, but doesn't support decorators '''
+ return majorVer == 2 and minorVer < 4
+
+class GetAttrException(Exception):
+ pass
+
+class CustomGetAttrClass(object):
+ def __getattr__(self, name):
+ raise GetAttrException('FAIL, %s' % name)
+
+class GetAttrTest(unittest.TestCase):
+ '''
+ Test for an issue occurring when __getatttr__() raises an exception
+ causing NameMapper to raise a NotFound exception
+ '''
+ def test_ValidException(self):
+ o = CustomGetAttrClass()
+ try:
+ print o.attr
+ except GetAttrException, e:
+ # expected
+ return
+ except:
+ self.fail('Invalid exception raised: %s' % e)
+ self.fail('Should have had an exception raised')
+
+ def test_NotFoundException(self):
+ template = '''
+ #def raiseme()
+ $obj.attr
+ #end def'''
+
+ template = Cheetah.Template.Template.compile(template, compilerSettings={}, keepRefToGeneratedCode=True)
+ template = template(searchList=[{'obj' : CustomGetAttrClass()}])
+ assert template, 'We should have a valid template object by now'
+
+ self.failUnlessRaises(GetAttrException, template.raiseme)
+
+
+class InlineImportTest(unittest.TestCase):
+ def test_FromFooImportThing(self):
+ '''
+ Verify that a bug introduced in v2.1.0 where an inline:
+ #from module import class
+ would result in the following code being generated:
+ import class
+ '''
+ template = '''
+ #def myfunction()
+ #if True
+ #from os import path
+ #return 17
+ Hello!
+ #end if
+ #end def
+ '''
+ template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
+ template = template(searchList=[{}])
+
+ assert template, 'We should have a valid template object by now'
+
+ rc = template.myfunction()
+ assert rc == 17, (template, 'Didn\'t get a proper return value')
+
+ def test_ImportFailModule(self):
+ template = '''
+ #try
+ #import invalidmodule
+ #except
+ #set invalidmodule = dict(FOO='BAR!')
+ #end try
+
+ $invalidmodule.FOO
+ '''
+ template = Cheetah.Template.Template.compile(template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
+ template = template(searchList=[{}])
+
+ assert template, 'We should have a valid template object by now'
+ assert str(template), 'We weren\'t able to properly generate the result from the template'
+
+ def test_ProperImportOfBadModule(self):
+ template = '''
+ #from invalid import fail
+
+ This should totally $fail
+ '''
+ self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : False}, keepRefToGeneratedCode=True)
+
+ def test_AutoImporting(self):
+ template = '''
+ #extends FakeyTemplate
+
+ Boo!
+ '''
+ self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template)
+
+ def test_StuffBeforeImport_Legacy(self):
+ template = '''
+###
+### I like comments before import
+###
+#extends Foo
+Bar
+'''
+ self.failUnlessRaises(ImportError, Cheetah.Template.Template.compile, template, compilerSettings={'useLegacyImportMode' : True}, keepRefToGeneratedCode=True)
+
+
+class Mantis_Issue_11_Regression_Test(unittest.TestCase):
+ '''
+ Test case for bug outlined in Mantis issue #11:
+
+ Output:
+ Traceback (most recent call last):
+ File "test.py", line 12, in <module>
+ t.respond()
+ File "DynamicallyCompiledCheetahTemplate.py", line 86, in respond
+ File "/usr/lib64/python2.6/cgi.py", line 1035, in escape
+ s = s.replace("&", "&") # Must be done first!
+ '''
+ def test_FailingBehavior(self):
+ import cgi
+ template = Cheetah.Template.Template("$escape($request)", searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}])
+ assert template
+ self.failUnlessRaises(AttributeError, template.respond)
+
+
+ def test_FailingBehaviorWithSetting(self):
+ import cgi
+ template = Cheetah.Template.Template("$escape($request)",
+ searchList=[{'escape' : cgi.escape, 'request' : 'foobar'}],
+ compilerSettings={'prioritizeSearchListOverSelf' : True})
+ assert template
+ assert template.respond()
+
+class Mantis_Issue_21_Regression_Test(unittest.TestCase):
+ '''
+ Test case for bug outlined in issue #21
+
+ Effectively @staticmethod and @classmethod
+ decorated methods in templates don't
+ properly define the _filter local, which breaks
+ when using the NameMapper
+ '''
+ def runTest(self):
+ if isPython23():
+ return
+ template = '''
+ #@staticmethod
+ #def testMethod()
+ This is my $output
+ #end def
+ '''
+ template = Cheetah.Template.Template.compile(template)
+ assert template
+ assert template.testMethod(output='bug') # raises a NameError: global name '_filter' is not defined
+
+
+class Mantis_Issue_22_Regression_Test(unittest.TestCase):
+ '''
+ Test case for bug outlined in issue #22
+
+ When using @staticmethod and @classmethod
+ in conjunction with the #filter directive
+ the generated code for the #filter is reliant
+ on the `self` local, breaking the function
+ '''
+ def test_NoneFilter(self):
+ # XXX: Disabling this test for now
+ return
+ if isPython23():
+ return
+ template = '''
+ #@staticmethod
+ #def testMethod()
+ #filter None
+ This is my $output
+ #end filter
+ #end def
+ '''
+ template = Cheetah.Template.Template.compile(template)
+ assert template
+ assert template.testMethod(output='bug')
+
+ def test_DefinedFilter(self):
+ # XXX: Disabling this test for now
+ return
+ if isPython23():
+ return
+ template = '''
+ #@staticmethod
+ #def testMethod()
+ #filter Filter
+ This is my $output
+ #end filter
+ #end def
+ '''
+ # The generated code for the template's testMethod() should look something
+ # like this in the 'error' case:
+ '''
+ @staticmethod
+ def testMethod(**KWS):
+ ## CHEETAH: generated from #def testMethod() at line 3, col 13.
+ trans = DummyTransaction()
+ _dummyTrans = True
+ write = trans.response().write
+ SL = [KWS]
+ _filter = lambda x, **kwargs: unicode(x)
+
+ ########################################
+ ## START - generated method body
+
+ _orig_filter_18517345 = _filter
+ filterName = u'Filter'
+ if self._CHEETAH__filters.has_key("Filter"):
+ _filter = self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName]
+ else:
+ _filter = self._CHEETAH__currentFilter = \
+ self._CHEETAH__filters[filterName] = getattr(self._CHEETAH__filtersLib, filterName)(self).filter
+ write(u' This is my ')
+ _v = VFFSL(SL,"output",True) # u'$output' on line 5, col 32
+ if _v is not None: write(_filter(_v, rawExpr=u'$output')) # from line 5, col 32.
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+ '''
+ template = Cheetah.Template.Template.compile(template)
+ assert template
+ assert template.testMethod(output='bug')
+
+
+if __name__ == '__main__':
+ unittest.main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/SyntaxAndOutput.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/SyntaxAndOutput.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/SyntaxAndOutput.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3227 @@
+#!/usr/bin/env python
+# -*- coding: latin-1 -*-
+
+'''
+Syntax and Output tests.
+
+TODO
+- #finally
+- #filter
+- #errorCatcher
+- #echo
+- #silent
+'''
+
+
+##################################################
+## DEPENDENCIES ##
+
+import sys
+import types
+import re
+from copy import deepcopy
+import os
+import os.path
+import new
+import pdb
+import warnings
+
+from Cheetah.NameMapper import NotFound
+from Cheetah.NameMapper import C_VERSION as NameMapper_C_VERSION
+from Cheetah.Template import Template
+from Cheetah.Parser import ParseError
+from Cheetah.Compiler import Compiler, DEFAULT_COMPILER_SETTINGS
+import unittest_local_copy as unittest
+
+class Unspecified(object):
+ pass
+
+majorVer, minorVer = sys.version_info[0], sys.version_info[1]
+versionTuple = (majorVer, minorVer)
+
+def testdecorator(func):
+ return func
+
+class DummyClass:
+ _called = False
+ def __str__(self):
+ return 'object'
+
+ def meth(self, arg="arff"):
+ return str(arg)
+
+ def meth1(self, arg="doo"):
+ return arg
+
+ def meth2(self, arg1="a1", arg2="a2"):
+ return str(arg1) + str(arg2)
+
+ def methWithPercentSignDefaultArg(self, arg1="110%"):
+ return str(arg1)
+
+ def callIt(self, arg=1234):
+ self._called = True
+ self._callArg = arg
+
+
+def dummyFunc(arg="Scooby"):
+ return arg
+
+defaultTestNameSpace = {
+ 'aStr':'blarg',
+ 'anInt':1,
+ 'aFloat':1.5,
+ 'aList': ['item0','item1','item2'],
+ 'aDict': {'one':'item1',
+ 'two':'item2',
+ 'nestedDict':{1:'nestedItem1',
+ 'two':'nestedItem2'
+ },
+ 'nestedFunc':dummyFunc,
+ },
+ 'aFunc': dummyFunc,
+ 'anObj': DummyClass(),
+ 'aMeth': DummyClass().meth1,
+ 'aStrToBeIncluded': "$aStr $anInt",
+ 'none' : None,
+ 'emptyString':'',
+ 'numOne':1,
+ 'numTwo':2,
+ 'zero':0,
+ 'tenDigits': 1234567890,
+ 'webSafeTest': 'abc <=> &',
+ 'strip1': ' \t strippable whitespace \t\t \n',
+ 'strip2': ' \t strippable whitespace \t\t ',
+ 'strip3': ' \t strippable whitespace \t\t\n1 2 3\n',
+
+ 'blockToBeParsed':"""$numOne $numTwo""",
+ 'includeBlock2':"""$numOne $numTwo $aSetVar""",
+
+ 'includeFileName':'parseTest.txt',
+ 'listOfLambdas':[lambda x: x, lambda x: x, lambda x: x,],
+ 'list': [
+ {'index': 0, 'numOne': 1, 'numTwo': 2},
+ {'index': 1, 'numOne': 1, 'numTwo': 2},
+ ],
+ 'nameList': [('john', 'doe'), ('jane', 'smith')],
+ 'letterList': ['a', 'b', 'c'],
+ '_': lambda x: 'Translated: ' + x,
+ 'unicodeData':u'aoeu12345\u1234',
+ }
+
+
+##################################################
+## TEST BASE CLASSES
+
+class OutputTest(unittest.TestCase):
+ report = '''
+Template output mismatch:
+
+ Input Template =
+%(template)s%(end)s
+
+ Expected Output =
+%(expected)s%(end)s
+
+ Actual Output =
+%(actual)s%(end)s'''
+
+ convertEOLs = True
+ _EOLreplacement = None
+ _debugEOLReplacement = False
+
+ DEBUGLEV = 0
+ _searchList = [defaultTestNameSpace]
+
+ _useNewStyleCompilation = True
+ #_useNewStyleCompilation = False
+
+ _extraCompileKwArgs = None
+
+ def searchList(self):
+ return self._searchList
+
+ def verify(self, input, expectedOutput,
+ inputEncoding=None,
+ outputEncoding=None,
+ convertEOLs=Unspecified):
+ if self._EOLreplacement:
+ if convertEOLs is Unspecified:
+ convertEOLs = self.convertEOLs
+ if convertEOLs:
+ input = input.replace('\n', self._EOLreplacement)
+ expectedOutput = expectedOutput.replace('\n', self._EOLreplacement)
+
+ self._input = input
+ if self._useNewStyleCompilation:
+ extraKwArgs = self._extraCompileKwArgs or {}
+
+ templateClass = Template.compile(
+ source=input,
+ compilerSettings=self._getCompilerSettings(),
+ keepRefToGeneratedCode=True,
+ **extraKwArgs
+ )
+ moduleCode = templateClass._CHEETAH_generatedModuleCode
+ self.template = templateObj = templateClass(searchList=self.searchList())
+ else:
+ self.template = templateObj = Template(
+ input,
+ searchList=self.searchList(),
+ compilerSettings=self._getCompilerSettings(),
+ )
+ moduleCode = templateObj._CHEETAH_generatedModuleCode
+ if self.DEBUGLEV >= 1:
+ print moduleCode
+ try:
+ output = templateObj.respond() # rather than __str__, because of unicode
+ assert output==expectedOutput, self._outputMismatchReport(output, expectedOutput)
+ finally:
+ templateObj.shutdown()
+
+ def _getCompilerSettings(self):
+ return {}
+
+ def _outputMismatchReport(self, output, expectedOutput):
+ if self._debugEOLReplacement and self._EOLreplacement:
+ EOLrepl = self._EOLreplacement
+ marker = '*EOL*'
+ return self.report % {'template': self._input.replace(EOLrepl,marker),
+ 'expected': expectedOutput.replace(EOLrepl,marker),
+ 'actual': output.replace(EOLrepl,marker),
+ 'end': '(end)'}
+ else:
+ return self.report % {'template': self._input,
+ 'expected': expectedOutput,
+ 'actual': output,
+ 'end': '(end)'}
+
+ def genClassCode(self):
+ if hasattr(self, 'template'):
+ return self.template.generatedClassCode()
+
+ def genModuleCode(self):
+ if hasattr(self, 'template'):
+ return self.template.generatedModuleCode()
+
+##################################################
+## TEST CASE CLASSES
+
+class EmptyTemplate(OutputTest):
+ convertEOLs = False
+ def test1(self):
+ """an empty string for the template"""
+
+ warnings.filterwarnings('error',
+ 'You supplied an empty string for the source!',
+ UserWarning)
+ try:
+ self.verify("", "")
+ except UserWarning:
+ pass
+ else:
+ self.fail("Should warn about empty source strings.")
+
+ try:
+ self.verify("#implements foo", "")
+ except NotImplementedError:
+ pass
+ else:
+ self.fail("This should barf about respond() not being implemented.")
+
+ self.verify("#implements respond", "")
+
+ self.verify("#implements respond(foo=1234)", "")
+
+
+class Backslashes(OutputTest):
+ convertEOLs = False
+
+ def setUp(self):
+ fp = open('backslashes.txt','w')
+ fp.write(r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
+ fp.flush()
+ fp.close
+
+ def tearDown(self):
+ if os.path.exists('backslashes.txt'):
+ os.remove('backslashes.txt')
+
+ def test1(self):
+ """ a single \\ using rawstrings"""
+ self.verify(r"\ ",
+ r"\ ")
+
+ def test2(self):
+ """ a single \\ using rawstrings and lots of lines"""
+ self.verify(r"\ " + "\n\n\n\n\n\n\n\n\n",
+ r"\ " + "\n\n\n\n\n\n\n\n\n")
+
+ def test3(self):
+ """ a single \\ without using rawstrings"""
+ self.verify("\ \ ",
+ "\ \ ")
+
+ def test4(self):
+ """ single line from an apache conf file"""
+ self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"',
+ r'#LogFormat "%h %l %u %t \"%r\" %>s %b"')
+
+ def test5(self):
+ """ single line from an apache conf file with many NEWLINES
+
+ The NEWLINES are used to make sure that MethodCompiler.commitStrConst()
+ is handling long and short strings in the same fashion. It uses
+ triple-quotes for strings with lots of \\n in them and repr(theStr) for
+ shorter strings with only a few newlines."""
+
+ self.verify(r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n',
+ r'#LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
+
+ def test6(self):
+ """ test backslash handling in an included file"""
+ self.verify(r'#include "backslashes.txt"',
+ r'\ #LogFormat "%h %l %u %t \"%r\" %>s %b"' + '\n\n\n\n\n\n\n')
+
+ def test7(self):
+ """ a single \\ without using rawstrings plus many NEWLINES"""
+ self.verify("\ \ " + "\n\n\n\n\n\n\n\n\n",
+ "\ \ " + "\n\n\n\n\n\n\n\n\n")
+
+ def test8(self):
+ """ single line from an apache conf file with single quotes and many NEWLINES
+ """
+
+ self.verify(r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n',
+ r"""#LogFormat '%h %l %u %t \"%r\" %>s %b'""" + '\n\n\n\n\n\n\n')
+
+class NonTokens(OutputTest):
+ def test1(self):
+ """dollar signs not in Cheetah $vars"""
+ self.verify("$ $$ $5 $. $ test",
+ "$ $$ $5 $. $ test")
+
+ def test2(self):
+ """hash not in #directives"""
+ self.verify("# \# #5 ",
+ "# # #5 ")
+
+ def test3(self):
+ """escapted comments"""
+ self.verify(" \##escaped comment ",
+ " ##escaped comment ")
+
+ def test4(self):
+ """escapted multi-line comments"""
+ self.verify(" \#*escaped comment \n*# ",
+ " #*escaped comment \n*# ")
+
+ def test5(self):
+ """1 dollar sign"""
+ self.verify("$",
+ "$")
+ def _X_test6(self):
+ """1 dollar sign followed by hash"""
+ self.verify("\n$#\n",
+ "\n$#\n")
+
+ def test6(self):
+ """1 dollar sign followed by EOL Slurp Token"""
+ if DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']:
+ self.verify("\n$%s\n"%DEFAULT_COMPILER_SETTINGS['EOLSlurpToken'],
+ "\n$")
+ else:
+ self.verify("\n$#\n",
+ "\n$#\n")
+
+class Comments_SingleLine(OutputTest):
+ def test1(self):
+ """## followed by WS"""
+ self.verify("## ",
+ "")
+
+ def test2(self):
+ """## followed by NEWLINE"""
+ self.verify("##\n",
+ "")
+
+ def test3(self):
+ """## followed by text then NEWLINE"""
+ self.verify("## oeuao aoe uaoe \n",
+ "")
+ def test4(self):
+ """## gobbles leading WS"""
+ self.verify(" ## oeuao aoe uaoe \n",
+ "")
+
+ def test5(self):
+ """## followed by text then NEWLINE, + leading WS"""
+ self.verify(" ## oeuao aoe uaoe \n",
+ "")
+
+ def test6(self):
+ """## followed by EOF"""
+ self.verify("##",
+ "")
+
+ def test7(self):
+ """## followed by EOF with leading WS"""
+ self.verify(" ##",
+ "")
+
+ def test8(self):
+ """## gobble line
+ with text on previous and following lines"""
+ self.verify("line1\n ## aoeu 1234 \nline2",
+ "line1\nline2")
+
+ def test9(self):
+ """## don't gobble line
+ with text on previous and following lines"""
+ self.verify("line1\n 12 ## aoeu 1234 \nline2",
+ "line1\n 12 \nline2")
+
+ def test10(self):
+ """## containing $placeholders
+ """
+ self.verify("##$a$b $c($d)",
+ "")
+
+ def test11(self):
+ """## containing #for directive
+ """
+ self.verify("##for $i in range(15)",
+ "")
+
+
+class Comments_MultiLine_NoGobble(OutputTest):
+ """
+ Multiline comments used to not gobble whitespace. They do now, but this can
+ be turned off with a compilerSetting
+ """
+
+ def _getCompilerSettings(self):
+ return {'gobbleWhitespaceAroundMultiLineComments':False}
+
+ def test1(self):
+ """#* *# followed by WS
+ Shouldn't gobble WS
+ """
+ self.verify("#* blarg *# ",
+ " ")
+
+ def test2(self):
+ """#* *# preceded and followed by WS
+ Shouldn't gobble WS
+ """
+ self.verify(" #* blarg *# ",
+ " ")
+
+ def test3(self):
+ """#* *# followed by WS, with NEWLINE
+ Shouldn't gobble WS
+ """
+ self.verify("#* \nblarg\n *# ",
+ " ")
+
+ def test4(self):
+ """#* *# preceded and followed by WS, with NEWLINE
+ Shouldn't gobble WS
+ """
+ self.verify(" #* \nblarg\n *# ",
+ " ")
+
+class Comments_MultiLine(OutputTest):
+ """
+ Note: Multiline comments don't gobble whitespace!
+ """
+
+ def test1(self):
+ """#* *# followed by WS
+ Should gobble WS
+ """
+ self.verify("#* blarg *# ",
+ "")
+
+ def test2(self):
+ """#* *# preceded and followed by WS
+ Should gobble WS
+ """
+ self.verify(" #* blarg *# ",
+ "")
+
+ def test3(self):
+ """#* *# followed by WS, with NEWLINE
+ Shouldn't gobble WS
+ """
+ self.verify("#* \nblarg\n *# ",
+ "")
+
+ def test4(self):
+ """#* *# preceded and followed by WS, with NEWLINE
+ Shouldn't gobble WS
+ """
+ self.verify(" #* \nblarg\n *# ",
+ "")
+
+ def test5(self):
+ """#* *# containing nothing
+ """
+ self.verify("#**#",
+ "")
+
+ def test6(self):
+ """#* *# containing only NEWLINES
+ """
+ self.verify(" #*\n\n\n\n\n\n\n\n*# ",
+ "")
+
+ def test7(self):
+ """#* *# containing $placeholders
+ """
+ self.verify("#* $var $var(1234*$c) *#",
+ "")
+
+ def test8(self):
+ """#* *# containing #for directive
+ """
+ self.verify("#* #for $i in range(15) *#",
+ "")
+
+ def test9(self):
+ """ text around #* *# containing #for directive
+ """
+ self.verify("foo\nfoo bar #* #for $i in range(15) *# foo\n",
+ "foo\nfoo bar foo\n")
+
+ def test9(self):
+ """ text around #* *# containing #for directive and trailing whitespace
+ which should be gobbled
+ """
+ self.verify("foo\nfoo bar #* #for $i in range(15) *# \ntest",
+ "foo\nfoo bar \ntest")
+
+ def test10(self):
+ """ text around #* *# containing #for directive and newlines: trailing whitespace
+ which should be gobbled.
+ """
+ self.verify("foo\nfoo bar #* \n\n#for $i in range(15) \n\n*# \ntest",
+ "foo\nfoo bar \ntest")
+
+class Placeholders(OutputTest):
+ def test1(self):
+ """1 placeholder"""
+ self.verify("$aStr", "blarg")
+
+ def test2(self):
+ """2 placeholders"""
+ self.verify("$aStr $anInt", "blarg 1")
+
+ def test3(self):
+ """2 placeholders, back-to-back"""
+ self.verify("$aStr$anInt", "blarg1")
+
+ def test4(self):
+ """1 placeholder enclosed in ()"""
+ self.verify("$(aStr)", "blarg")
+
+ def test5(self):
+ """1 placeholder enclosed in {}"""
+ self.verify("${aStr}", "blarg")
+
+ def test6(self):
+ """1 placeholder enclosed in []"""
+ self.verify("$[aStr]", "blarg")
+
+ def test7(self):
+ """1 placeholder enclosed in () + WS
+
+ Test to make sure that $(<WS><identifier>.. matches
+ """
+ self.verify("$( aStr )", "blarg")
+
+ def test8(self):
+ """1 placeholder enclosed in {} + WS"""
+ self.verify("${ aStr }", "blarg")
+
+ def test9(self):
+ """1 placeholder enclosed in [] + WS"""
+ self.verify("$[ aStr ]", "blarg")
+
+ def test10(self):
+ """1 placeholder enclosed in () + WS + * cache
+
+ Test to make sure that $*(<WS><identifier>.. matches
+ """
+ self.verify("$*( aStr )", "blarg")
+
+ def test11(self):
+ """1 placeholder enclosed in {} + WS + *cache"""
+ self.verify("$*{ aStr }", "blarg")
+
+ def test12(self):
+ """1 placeholder enclosed in [] + WS + *cache"""
+ self.verify("$*[ aStr ]", "blarg")
+
+ def test13(self):
+ """1 placeholder enclosed in {} + WS + *<int>*cache"""
+ self.verify("$*5*{ aStr }", "blarg")
+
+ def test14(self):
+ """1 placeholder enclosed in [] + WS + *<int>*cache"""
+ self.verify("$*5*[ aStr ]", "blarg")
+
+ def test15(self):
+ """1 placeholder enclosed in {} + WS + *<float>*cache"""
+ self.verify("$*0.5d*{ aStr }", "blarg")
+
+ def test16(self):
+ """1 placeholder enclosed in [] + WS + *<float>*cache"""
+ self.verify("$*.5*[ aStr ]", "blarg")
+
+ def test17(self):
+ """1 placeholder + *<int>*cache"""
+ self.verify("$*5*aStr", "blarg")
+
+ def test18(self):
+ """1 placeholder *<float>*cache"""
+ self.verify("$*0.5h*aStr", "blarg")
+
+ def test19(self):
+ """1 placeholder surrounded by single quotes and multiple newlines"""
+ self.verify("""'\n\n\n\n'$aStr'\n\n\n\n'""",
+ """'\n\n\n\n'blarg'\n\n\n\n'""")
+
+ def test20(self):
+ """silent mode $!placeholders """
+ self.verify("$!aStr$!nonExistant$!*nonExistant$!{nonExistant}", "blarg")
+
+ try:
+ self.verify("$!aStr$nonExistant",
+ "blarg")
+ except NotFound:
+ pass
+ else:
+ self.fail('should raise NotFound exception')
+
+ def test21(self):
+ """Make sure that $*caching is actually working"""
+ namesStr = 'You Me Them Everyone'
+ names = namesStr.split()
+
+ tmpl = Template.compile('#for name in $names: $name ', baseclass=dict)
+ assert str(tmpl({'names':names})).strip()==namesStr
+
+ tmpl = tmpl.subclass('#for name in $names: $*name ')
+ assert str(tmpl({'names':names}))=='You '*len(names)
+
+ tmpl = tmpl.subclass('#for name in $names: $*1*name ')
+ assert str(tmpl({'names':names}))=='You '*len(names)
+
+ tmpl = tmpl.subclass('#for name in $names: $*1*(name) ')
+ assert str(tmpl({'names':names}))=='You '*len(names)
+
+ if versionTuple > (2,2):
+ tmpl = tmpl.subclass('#for name in $names: $*1*(name) ')
+ assert str(tmpl(names=names))=='You '*len(names)
+
+class Placeholders_Vals(OutputTest):
+ convertEOLs = False
+ def test1(self):
+ """string"""
+ self.verify("$aStr", "blarg")
+
+ def test2(self):
+ """string - with whitespace"""
+ self.verify(" $aStr ", " blarg ")
+
+ def test3(self):
+ """empty string - with whitespace"""
+ self.verify("$emptyString", "")
+
+ def test4(self):
+ """int"""
+ self.verify("$anInt", "1")
+
+ def test5(self):
+ """float"""
+ self.verify("$aFloat", "1.5")
+
+ def test6(self):
+ """list"""
+ self.verify("$aList", "['item0', 'item1', 'item2']")
+
+ def test7(self):
+ """None
+
+ The default output filter is ReplaceNone.
+ """
+ self.verify("$none", "")
+
+ def test8(self):
+ """True, False
+ """
+ self.verify("$True $False", "%s %s"%(repr(True), repr(False)))
+
+ def test9(self):
+ """$_
+ """
+ self.verify("$_('foo')", "Translated: foo")
+
+class PlaceholderStrings(OutputTest):
+ def test1(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("$str(c'$aStr')", "blarg")
+
+ def test2(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("$str(c'$aStr.upper')", "BLARG")
+
+ def test3(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("$str(c'$(aStr.upper.replace(c\"A$str()\",\"\"))')", "BLRG")
+
+ def test4(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("#echo $str(c'$(aStr.upper)')", "BLARG")
+
+ def test5(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("#if 1 then $str(c'$(aStr.upper)') else 0", "BLARG")
+
+ def test6(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("#if 1\n$str(c'$(aStr.upper)')#slurp\n#else\n0#end if", "BLARG")
+
+ def test7(self):
+ """some c'text $placeholder text' strings"""
+ self.verify("#def foo(arg=c'$(\"BLARG\")')\n"
+ "$arg#slurp\n"
+ "#end def\n"
+ "$foo()$foo(c'$anInt')#slurp",
+
+ "BLARG1")
+
+
+
+class UnicodeStrings(OutputTest):
+ def test1(self):
+ """unicode data in placeholder
+ """
+ #self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData'], outputEncoding='utf8')
+ self.verify(u"$unicodeData", defaultTestNameSpace['unicodeData'])
+
+ def test2(self):
+ """unicode data in body
+ """
+ self.verify(u"aoeu12345\u1234", u"aoeu12345\u1234")
+ #self.verify(u"#encoding utf8#aoeu12345\u1234", u"aoeu12345\u1234")
+
+class EncodingDirective(OutputTest):
+ def test1(self):
+ """basic #encoding """
+ self.verify("#encoding utf-8\n1234",
+ "1234")
+
+ def test2(self):
+ """basic #encoding """
+ self.verify("#encoding ascii\n1234",
+ "1234")
+
+ def test3(self):
+ """basic #encoding """
+ self.verify("#encoding utf-8\n\xe1\x88\xb4",
+ u'\u1234', outputEncoding='utf8')
+
+ def test4(self):
+ """basic #encoding """
+ self.verify("#encoding latin-1\n\xe1\x88\xb4",
+ u"\xe1\x88\xb4")
+
+ def test5(self):
+ """basic #encoding """
+ self.verify("#encoding latin-1\nAndr\202",
+ u'Andr\202')
+
+class UnicodeDirective(OutputTest):
+ def test1(self):
+ """basic #unicode """
+ self.verify("#unicode utf-8\n1234",
+ u"1234")
+
+ self.verify("#unicode ascii\n1234",
+ u"1234")
+
+ self.verify("#unicode latin-1\n1234",
+ u"1234")
+
+ self.verify("#unicode latin-1\n1234ü",
+ u"1234ü")
+ self.verify("#unicode: latin-1\n1234ü",
+ u"1234ü")
+ self.verify("# unicode : latin-1\n1234ü",
+ u"1234ü")
+
+ self.verify(u"#unicode latin-1\n1234ü",
+ u"1234ü")
+
+ self.verify("#encoding latin-1\n1234ü",
+ u"1234ü")
+
+class Placeholders_Esc(OutputTest):
+ convertEOLs = False
+ def test1(self):
+ """1 escaped placeholder"""
+ self.verify("\$var",
+ "$var")
+
+ def test2(self):
+ """2 escaped placeholders"""
+ self.verify("\$var \$_",
+ "$var $_")
+
+ def test3(self):
+ """2 escaped placeholders - back to back"""
+ self.verify("\$var\$_",
+ "$var$_")
+
+ def test4(self):
+ """2 escaped placeholders - nested"""
+ self.verify("\$var(\$_)",
+ "$var($_)")
+
+ def test5(self):
+ """2 escaped placeholders - nested and enclosed"""
+ self.verify("\$(var(\$_)",
+ "$(var($_)")
+
+
+class Placeholders_Calls(OutputTest):
+ def test1(self):
+ """func placeholder - no ()"""
+ self.verify("$aFunc",
+ "Scooby")
+
+ def test2(self):
+ """func placeholder - with ()"""
+ self.verify("$aFunc()",
+ "Scooby")
+
+ def test3(self):
+ r"""func placeholder - with (\n\n)"""
+ self.verify("$aFunc(\n\n)",
+ "Scooby", convertEOLs=False)
+
+ def test4(self):
+ r"""func placeholder - with (\n\n) and $() enclosure"""
+ self.verify("$(aFunc(\n\n))",
+ "Scooby", convertEOLs=False)
+
+ def test5(self):
+ r"""func placeholder - with (\n\n) and ${} enclosure"""
+ self.verify("${aFunc(\n\n)}",
+ "Scooby", convertEOLs=False)
+
+ def test6(self):
+ """func placeholder - with (int)"""
+ self.verify("$aFunc(1234)",
+ "1234")
+
+ def test7(self):
+ r"""func placeholder - with (\nint\n)"""
+ self.verify("$aFunc(\n1234\n)",
+ "1234", convertEOLs=False)
+ def test8(self):
+ """func placeholder - with (string)"""
+ self.verify("$aFunc('aoeu')",
+ "aoeu")
+
+ def test9(self):
+ """func placeholder - with ('''string''')"""
+ self.verify("$aFunc('''aoeu''')",
+ "aoeu")
+ def test10(self):
+ r"""func placeholder - with ('''\nstring\n''')"""
+ self.verify("$aFunc('''\naoeu\n''')",
+ "\naoeu\n")
+
+ def test11(self):
+ r"""func placeholder - with ('''\nstring'\n''')"""
+ self.verify("$aFunc('''\naoeu'\n''')",
+ "\naoeu'\n")
+
+ def test12(self):
+ r'''func placeholder - with ("""\nstring\n""")'''
+ self.verify('$aFunc("""\naoeu\n""")',
+ "\naoeu\n")
+
+ def test13(self):
+ """func placeholder - with (string*int)"""
+ self.verify("$aFunc('aoeu'*2)",
+ "aoeuaoeu")
+
+ def test14(self):
+ """func placeholder - with (int*int)"""
+ self.verify("$aFunc(2*2)",
+ "4")
+
+ def test15(self):
+ """func placeholder - with (int*float)"""
+ self.verify("$aFunc(2*2.0)",
+ "4.0")
+
+ def test16(self):
+ r"""func placeholder - with (int\n*\nfloat)"""
+ self.verify("$aFunc(2\n*\n2.0)",
+ "4.0", convertEOLs=False)
+
+ def test17(self):
+ """func placeholder - with ($arg=float)"""
+ self.verify("$aFunc($arg=4.0)",
+ "4.0")
+
+ def test18(self):
+ """func placeholder - with (arg=float)"""
+ self.verify("$aFunc(arg=4.0)",
+ "4.0")
+
+ def test19(self):
+ """deeply nested argstring, no enclosure"""
+ self.verify("$aFunc($arg=$aMeth($arg=$aFunc(1)))",
+ "1")
+
+ def test20(self):
+ """deeply nested argstring, no enclosure + with WS"""
+ self.verify("$aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) )",
+ "1")
+ def test21(self):
+ """deeply nested argstring, () enclosure + with WS"""
+ self.verify("$(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
+ "1")
+
+ def test22(self):
+ """deeply nested argstring, {} enclosure + with WS"""
+ self.verify("${aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) }",
+ "1")
+
+ def test23(self):
+ """deeply nested argstring, [] enclosure + with WS"""
+ self.verify("$[aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) ]",
+ "1")
+
+ def test24(self):
+ """deeply nested argstring, () enclosure + *cache"""
+ self.verify("$*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
+ "1")
+ def test25(self):
+ """deeply nested argstring, () enclosure + *15*cache"""
+ self.verify("$*15*(aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ) )",
+ "1")
+
+ def test26(self):
+ """a function call with the Python None kw."""
+ self.verify("$aFunc(None)",
+ "")
+
+class NameMapper(OutputTest):
+ def test1(self):
+ """autocalling"""
+ self.verify("$aFunc! $aFunc().",
+ "Scooby! Scooby.")
+
+ def test2(self):
+ """nested autocalling"""
+ self.verify("$aFunc($aFunc).",
+ "Scooby.")
+
+ def test3(self):
+ """list subscription"""
+ self.verify("$aList[0]",
+ "item0")
+
+ def test4(self):
+ """list slicing"""
+ self.verify("$aList[:2]",
+ "['item0', 'item1']")
+
+ def test5(self):
+ """list slicing and subcription combined"""
+ self.verify("$aList[:2][0]",
+ "item0")
+
+ def test6(self):
+ """dictionary access - NameMapper style"""
+ self.verify("$aDict.one",
+ "item1")
+
+ def test7(self):
+ """dictionary access - Python style"""
+ self.verify("$aDict['one']",
+ "item1")
+
+ def test8(self):
+ """dictionary access combined with autocalled string method"""
+ self.verify("$aDict.one.upper",
+ "ITEM1")
+
+ def test9(self):
+ """dictionary access combined with string method"""
+ self.verify("$aDict.one.upper()",
+ "ITEM1")
+
+ def test10(self):
+ """nested dictionary access - NameMapper style"""
+ self.verify("$aDict.nestedDict.two",
+ "nestedItem2")
+
+ def test11(self):
+ """nested dictionary access - Python style"""
+ self.verify("$aDict['nestedDict']['two']",
+ "nestedItem2")
+
+ def test12(self):
+ """nested dictionary access - alternating style"""
+ self.verify("$aDict['nestedDict'].two",
+ "nestedItem2")
+
+ def test13(self):
+ """nested dictionary access using method - alternating style"""
+ self.verify("$aDict.get('nestedDict').two",
+ "nestedItem2")
+
+ def test14(self):
+ """nested dictionary access - NameMapper style - followed by method"""
+ self.verify("$aDict.nestedDict.two.upper",
+ "NESTEDITEM2")
+
+ def test15(self):
+ """nested dictionary access - alternating style - followed by method"""
+ self.verify("$aDict['nestedDict'].two.upper",
+ "NESTEDITEM2")
+
+ def test16(self):
+ """nested dictionary access - NameMapper style - followed by method, then slice"""
+ self.verify("$aDict.nestedDict.two.upper[:4]",
+ "NEST")
+
+ def test17(self):
+ """nested dictionary access - Python style using a soft-coded key"""
+ self.verify("$aDict[$anObj.meth('nestedDict')].two",
+ "nestedItem2")
+
+ def test18(self):
+ """object method access"""
+ self.verify("$anObj.meth1",
+ "doo")
+
+ def test19(self):
+ """object method access, followed by complex slice"""
+ self.verify("$anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]",
+ "do")
+
+ def test20(self):
+ """object method access, followed by a very complex slice
+ If it can pass this one, it's safe to say it works!!"""
+ self.verify("$( anObj.meth1[0:\n (\n(4/4*2)*2)/$anObj.meth1(2)\n ] )",
+ "do")
+
+ def test21(self):
+ """object method access with % in the default arg for the meth.
+
+ This tests a bug that Jeff Johnson found and submitted a patch to SF
+ for."""
+
+ self.verify("$anObj.methWithPercentSignDefaultArg",
+ "110%")
+
+
+#class NameMapperDict(OutputTest):
+#
+# _searchList = [{"update": "Yabba dabba doo!"}]
+#
+# def test1(self):
+# if NameMapper_C_VERSION:
+# return # This feature is not in the C version yet.
+# self.verify("$update", "Yabba dabba doo!")
+#
+
+class CacheDirective(OutputTest):
+
+ def test1(self):
+ r"""simple #cache """
+ self.verify("#cache:$anInt",
+ "1")
+
+ def test2(self):
+ r"""simple #cache + WS"""
+ self.verify(" #cache \n$anInt#end cache",
+ "1")
+
+ def test3(self):
+ r"""simple #cache ... #end cache"""
+ self.verify("""#cache id='cache1', timer=150m
+$anInt
+#end cache
+$aStr""",
+ "1\nblarg")
+
+ def test4(self):
+ r"""2 #cache ... #end cache blocks"""
+ self.verify("""#slurp
+#def foo
+#cache ID='cache1', timer=150m
+$anInt
+#end cache
+#cache id='cache2', timer=15s
+ #for $i in range(5)
+$i#slurp
+ #end for
+#end cache
+$aStr#slurp
+#end def
+$foo$foo$foo$foo$foo""",
+ "1\n01234blarg"*5)
+
+
+ def test5(self):
+ r"""nested #cache blocks"""
+ self.verify("""#slurp
+#def foo
+#cache ID='cache1', timer=150m
+$anInt
+#cache id='cache2', timer=15s
+ #for $i in range(5)
+$i#slurp
+ #end for
+$*(6)#slurp
+#end cache
+#end cache
+$aStr#slurp
+#end def
+$foo$foo$foo$foo$foo""",
+ "1\n012346blarg"*5)
+
+ def test6(self):
+ r"""Make sure that partial directives don't match"""
+ self.verify("#cache_foo",
+ "#cache_foo")
+ self.verify("#cached",
+ "#cached")
+
+class CallDirective(OutputTest):
+
+ def test1(self):
+ r"""simple #call """
+ self.verify("#call int\n$anInt#end call",
+ "1")
+ # single line version
+ self.verify("#call int: $anInt",
+ "1")
+ self.verify("#call int: 10\n$aStr",
+ "10\nblarg")
+
+ def test2(self):
+ r"""simple #call + WS"""
+ self.verify("#call int\n$anInt #end call",
+ "1")
+
+ def test3(self):
+ r"""a longer #call"""
+ self.verify('''\
+#def meth(arg)
+$arg.upper()#slurp
+#end def
+#call $meth
+$(1234+1) foo#slurp
+#end call''',
+ "1235 FOO")
+
+ def test4(self):
+ r"""#call with keyword #args"""
+ self.verify('''\
+#def meth(arg1, arg2)
+$arg1.upper() - $arg2.lower()#slurp
+#end def
+#call self.meth
+#arg arg1
+$(1234+1) foo#slurp
+#arg arg2
+UPPER#slurp
+#end call''',
+ "1235 FOO - upper")
+
+ def test5(self):
+ r"""#call with single-line keyword #args """
+ self.verify('''\
+#def meth(arg1, arg2)
+$arg1.upper() - $arg2.lower()#slurp
+#end def
+#call self.meth
+#arg arg1:$(1234+1) foo#slurp
+#arg arg2:UPPER#slurp
+#end call''',
+ "1235 FOO - upper")
+
+ def test6(self):
+ """#call with python kwargs and cheetah output for the 1s positional
+ arg"""
+
+ self.verify('''\
+#def meth(arg1, arg2)
+$arg1.upper() - $arg2.lower()#slurp
+#end def
+#call self.meth arg2="UPPER"
+$(1234+1) foo#slurp
+#end call''',
+ "1235 FOO - upper")
+
+ def test7(self):
+ """#call with python kwargs and #args"""
+ self.verify('''\
+#def meth(arg1, arg2, arg3)
+$arg1.upper() - $arg2.lower() - $arg3#slurp
+#end def
+#call self.meth arg2="UPPER", arg3=999
+#arg arg1:$(1234+1) foo#slurp
+#end call''',
+ "1235 FOO - upper - 999")
+
+ def test8(self):
+ """#call with python kwargs and #args, and using a function to get the
+ function that will be called"""
+ self.verify('''\
+#def meth(arg1, arg2, arg3)
+$arg1.upper() - $arg2.lower() - $arg3#slurp
+#end def
+#call getattr(self, "meth") arg2="UPPER", arg3=999
+#arg arg1:$(1234+1) foo#slurp
+#end call''',
+ "1235 FOO - upper - 999")
+
+ def test9(self):
+ """nested #call directives"""
+ self.verify('''\
+#def meth(arg1)
+$arg1#slurp
+#end def
+#def meth2(x,y)
+$x$y#slurp
+#end def
+##
+#call self.meth
+1#slurp
+#call self.meth
+2#slurp
+#call self.meth
+3#slurp
+#end call 3
+#set two = 2
+#call self.meth2 y=c"$(10/$two)"
+#arg x
+4#slurp
+#end call 4
+#end call 2
+#end call 1''',
+ "12345")
+
+
+
+class I18nDirective(OutputTest):
+ def test1(self):
+ r"""simple #call """
+ self.verify("#i18n \n$anInt#end i18n",
+ "1")
+
+ # single line version
+ self.verify("#i18n: $anInt",
+ "1")
+ self.verify("#i18n: 10\n$aStr",
+ "10\nblarg")
+
+
+class CaptureDirective(OutputTest):
+ def test1(self):
+ r"""simple #capture"""
+ self.verify('''\
+#capture cap1
+$(1234+1) foo#slurp
+#end capture
+$cap1#slurp
+''',
+ "1235 foo")
+
+
+ def test2(self):
+ r"""slightly more complex #capture"""
+ self.verify('''\
+#def meth(arg)
+$arg.upper()#slurp
+#end def
+#capture cap1
+$(1234+1) $anInt $meth("foo")#slurp
+#end capture
+$cap1#slurp
+''',
+ "1235 1 FOO")
+
+
+class SlurpDirective(OutputTest):
+ def test1(self):
+ r"""#slurp with 1 \n """
+ self.verify("#slurp\n",
+ "")
+
+ def test2(self):
+ r"""#slurp with 1 \n, leading whitespace
+ Should gobble"""
+ self.verify(" #slurp\n",
+ "")
+
+ def test3(self):
+ r"""#slurp with 1 \n, leading content
+ Shouldn't gobble"""
+ self.verify(" 1234 #slurp\n",
+ " 1234 ")
+
+ def test4(self):
+ r"""#slurp with WS then \n, leading content
+ Shouldn't gobble"""
+ self.verify(" 1234 #slurp \n",
+ " 1234 ")
+
+ def test5(self):
+ r"""#slurp with garbage chars then \n, leading content
+ Should eat the garbage"""
+ self.verify(" 1234 #slurp garbage \n",
+ " 1234 ")
+
+
+
+class EOLSlurpToken(OutputTest):
+ _EOLSlurpToken = DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']
+ def test1(self):
+ r"""#slurp with 1 \n """
+ self.verify("%s\n"%self._EOLSlurpToken,
+ "")
+
+ def test2(self):
+ r"""#slurp with 1 \n, leading whitespace
+ Should gobble"""
+ self.verify(" %s\n"%self._EOLSlurpToken,
+ "")
+ def test3(self):
+ r"""#slurp with 1 \n, leading content
+ Shouldn't gobble"""
+ self.verify(" 1234 %s\n"%self._EOLSlurpToken,
+ " 1234 ")
+
+ def test4(self):
+ r"""#slurp with WS then \n, leading content
+ Shouldn't gobble"""
+ self.verify(" 1234 %s \n"%self._EOLSlurpToken,
+ " 1234 ")
+
+ def test5(self):
+ r"""#slurp with garbage chars then \n, leading content
+ Should NOT eat the garbage"""
+ self.verify(" 1234 %s garbage \n"%self._EOLSlurpToken,
+ " 1234 %s garbage \n"%self._EOLSlurpToken)
+
+if not DEFAULT_COMPILER_SETTINGS['EOLSlurpToken']:
+ del EOLSlurpToken
+
+class RawDirective(OutputTest):
+ def test1(self):
+ """#raw till EOF"""
+ self.verify("#raw\n$aFunc().\n\n",
+ "$aFunc().\n\n")
+
+ def test2(self):
+ """#raw till #end raw"""
+ self.verify("#raw\n$aFunc().\n#end raw\n$anInt",
+ "$aFunc().\n1")
+
+ def test3(self):
+ """#raw till #end raw gobble WS"""
+ self.verify(" #raw \n$aFunc().\n #end raw \n$anInt",
+ "$aFunc().\n1")
+
+ def test4(self):
+ """#raw till #end raw using explicit directive closure
+ Shouldn't gobble"""
+ self.verify(" #raw #\n$aFunc().\n #end raw #\n$anInt",
+ " \n$aFunc().\n\n1")
+
+ def test5(self):
+ """single-line short form #raw: """
+ self.verify("#raw: $aFunc().\n\n",
+ "$aFunc().\n\n")
+
+ self.verify("#raw: $aFunc().\n$anInt",
+ "$aFunc().\n1")
+
+class BreakpointDirective(OutputTest):
+ def test1(self):
+ """#breakpoint part way through source code"""
+ self.verify("$aFunc(2).\n#breakpoint\n$anInt",
+ "2.\n")
+
+ def test2(self):
+ """#breakpoint at BOF"""
+ self.verify("#breakpoint\n$anInt",
+ "")
+
+ def test3(self):
+ """#breakpoint at EOF"""
+ self.verify("$anInt\n#breakpoint",
+ "1\n")
+
+
+class StopDirective(OutputTest):
+ def test1(self):
+ """#stop part way through source code"""
+ self.verify("$aFunc(2).\n#stop\n$anInt",
+ "2.\n")
+
+ def test2(self):
+ """#stop at BOF"""
+ self.verify("#stop\n$anInt",
+ "")
+
+ def test3(self):
+ """#stop at EOF"""
+ self.verify("$anInt\n#stop",
+ "1\n")
+
+ def test4(self):
+ """#stop in pos test block"""
+ self.verify("""$anInt
+#if 1
+inside the if block
+#stop
+#end if
+blarg""",
+ "1\ninside the if block\n")
+
+ def test5(self):
+ """#stop in neg test block"""
+ self.verify("""$anInt
+#if 0
+inside the if block
+#stop
+#end if
+blarg""",
+ "1\nblarg")
+
+
+class ReturnDirective(OutputTest):
+
+ def test1(self):
+ """#return'ing an int """
+ self.verify("""1
+$str($test-6)
+3
+#def test
+#if 1
+#return (3 *2) \
+ + 2
+#else
+aoeuoaeu
+#end if
+#end def
+""",
+ "1\n2\n3\n")
+
+ def test2(self):
+ """#return'ing an string """
+ self.verify("""1
+$str($test[1])
+3
+#def test
+#if 1
+#return '123'
+#else
+aoeuoaeu
+#end if
+#end def
+""",
+ "1\n2\n3\n")
+
+ def test3(self):
+ """#return'ing an string AND streaming other output via the transaction"""
+ self.verify("""1
+$str($test(trans=trans)[1])
+3
+#def test
+1.5
+#if 1
+#return '123'
+#else
+aoeuoaeu
+#end if
+#end def
+""",
+ "1\n1.5\n2\n3\n")
+
+
+class YieldDirective(OutputTest):
+ convertEOLs = False
+ def test1(self):
+ """simple #yield """
+
+ src1 = """#for i in range(10)\n#yield i\n#end for"""
+ src2 = """#for i in range(10)\n$i#slurp\n#yield\n#end for"""
+ src3 = ("#def iterator\n"
+ "#for i in range(10)\n#yield i\n#end for\n"
+ "#end def\n"
+ "#for i in $iterator\n$i#end for"
+ )
+
+
+ for src in (src1,src2,src3):
+ klass = Template.compile(src, keepRefToGeneratedCode=True)
+ #print klass._CHEETAH_generatedModuleCode
+ iter = klass().respond()
+ output = [str(i) for i in iter]
+ assert ''.join(output)=='0123456789'
+ #print ''.join(output)
+
+ # @@TR: need to expand this to cover error conditions etc.
+
+if versionTuple < (2,3):
+ del YieldDirective
+
+class ForDirective(OutputTest):
+
+ def test1(self):
+ """#for loop with one local var"""
+ self.verify("#for $i in range(5)\n$i\n#end for",
+ "0\n1\n2\n3\n4\n")
+
+ self.verify("#for $i in range(5):\n$i\n#end for",
+ "0\n1\n2\n3\n4\n")
+
+ self.verify("#for $i in range(5): ##comment\n$i\n#end for",
+ "0\n1\n2\n3\n4\n")
+
+ self.verify("#for $i in range(5) ##comment\n$i\n#end for",
+ "0\n1\n2\n3\n4\n")
+
+
+ def test2(self):
+ """#for loop with WS in loop"""
+ self.verify("#for $i in range(5)\n$i \n#end for",
+ "0 \n1 \n2 \n3 \n4 \n")
+
+ def test3(self):
+ """#for loop gobble WS"""
+ self.verify(" #for $i in range(5) \n$i \n #end for ",
+ "0 \n1 \n2 \n3 \n4 \n")
+
+ def test4(self):
+ """#for loop over list"""
+ self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j\n#end for",
+ "0,1\n2,3\n")
+
+ def test5(self):
+ """#for loop over list, with #slurp"""
+ self.verify("#for $i, $j in [(0,1),(2,3)]\n$i,$j#slurp\n#end for",
+ "0,12,3")
+
+ def test6(self):
+ """#for loop with explicit closures"""
+ self.verify("#for $i in range(5)#$i#end for#",
+ "01234")
+
+ def test7(self):
+ """#for loop with explicit closures and WS"""
+ self.verify(" #for $i in range(5)#$i#end for# ",
+ " 01234 ")
+
+ def test8(self):
+ """#for loop using another $var"""
+ self.verify(" #for $i in range($aFunc(5))#$i#end for# ",
+ " 01234 ")
+
+ def test9(self):
+ """test methods in for loops"""
+ self.verify("#for $func in $listOfLambdas\n$func($anInt)\n#end for",
+ "1\n1\n1\n")
+
+
+ def test10(self):
+ """#for loop over list, using methods of the items"""
+ self.verify("#for i, j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+ self.verify("#for $i, $j in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+
+ def test11(self):
+ """#for loop over list, using ($i,$j) style target list"""
+ self.verify("#for (i, j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+ self.verify("#for ($i, $j) in [('aa','bb'),('cc','dd')]\n$i.upper,$j.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+
+ def test12(self):
+ """#for loop over list, using i, (j,k) style target list"""
+ self.verify("#for i, (j, k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+ self.verify("#for $i, ($j, $k) in enumerate([('aa','bb'),('cc','dd')])\n$j.upper,$k.upper\n#end for",
+ "AA,BB\nCC,DD\n")
+
+ def test13(self):
+ """single line #for"""
+ self.verify("#for $i in range($aFunc(5)): $i",
+ "01234")
+
+ def test14(self):
+ """single line #for with 1 extra leading space"""
+ self.verify("#for $i in range($aFunc(5)): $i",
+ " 0 1 2 3 4")
+
+ def test15(self):
+ """2 times single line #for"""
+ self.verify("#for $i in range($aFunc(5)): $i#slurp\n"*2,
+ "01234"*2)
+
+ def test16(self):
+ """false single line #for """
+ self.verify("#for $i in range(5): \n$i\n#end for",
+ "0\n1\n2\n3\n4\n")
+
+if versionTuple < (2,3):
+ del ForDirective.test12
+
+class RepeatDirective(OutputTest):
+
+ def test1(self):
+ """basic #repeat"""
+ self.verify("#repeat 3\n1\n#end repeat",
+ "1\n1\n1\n")
+ self.verify("#repeat 3: \n1\n#end repeat",
+ "1\n1\n1\n")
+
+ self.verify("#repeat 3 ##comment\n1\n#end repeat",
+ "1\n1\n1\n")
+
+ self.verify("#repeat 3: ##comment\n1\n#end repeat",
+ "1\n1\n1\n")
+
+ def test2(self):
+ """#repeat with numeric expression"""
+ self.verify("#repeat 3*3/3\n1\n#end repeat",
+ "1\n1\n1\n")
+
+ def test3(self):
+ """#repeat with placeholder"""
+ self.verify("#repeat $numTwo\n1\n#end repeat",
+ "1\n1\n")
+
+ def test4(self):
+ """#repeat with placeholder * num"""
+ self.verify("#repeat $numTwo*1\n1\n#end repeat",
+ "1\n1\n")
+
+ def test5(self):
+ """#repeat with placeholder and WS"""
+ self.verify(" #repeat $numTwo \n1\n #end repeat ",
+ "1\n1\n")
+
+ def test6(self):
+ """single-line #repeat"""
+ self.verify("#repeat $numTwo: 1",
+ "11")
+ self.verify("#repeat $numTwo: 1\n"*2,
+ "1\n1\n"*2)
+
+ #false single-line
+ self.verify("#repeat 3: \n1\n#end repeat",
+ "1\n1\n1\n")
+
+
+class AttrDirective(OutputTest):
+
+ def test1(self):
+ """#attr with int"""
+ self.verify("#attr $test = 1234\n$test",
+ "1234")
+
+ def test2(self):
+ """#attr with string"""
+ self.verify("#attr $test = 'blarg'\n$test",
+ "blarg")
+
+ def test3(self):
+ """#attr with expression"""
+ self.verify("#attr $test = 'blarg'.upper()*2\n$test",
+ "BLARGBLARG")
+
+ def test4(self):
+ """#attr with string + WS
+ Should gobble"""
+ self.verify(" #attr $test = 'blarg' \n$test",
+ "blarg")
+
+ def test5(self):
+ """#attr with string + WS + leading text
+ Shouldn't gobble"""
+ self.verify(" -- #attr $test = 'blarg' \n$test",
+ " -- \nblarg")
+
+
+class DefDirective(OutputTest):
+
+ def test1(self):
+ """#def without argstring"""
+ self.verify("#def testMeth\n1234\n#end def\n$testMeth",
+ "1234\n")
+
+ self.verify("#def testMeth ## comment\n1234\n#end def\n$testMeth",
+ "1234\n")
+
+ self.verify("#def testMeth: ## comment\n1234\n#end def\n$testMeth",
+ "1234\n")
+
+ def test2(self):
+ """#def without argstring, gobble WS"""
+ self.verify(" #def testMeth \n1234\n #end def \n$testMeth",
+ "1234\n")
+
+ def test3(self):
+ """#def with argstring, gobble WS"""
+ self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth",
+ "1234-999\n")
+
+ def test4(self):
+ """#def with argstring, gobble WS, string used in call"""
+ self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth('ABC')",
+ "1234-ABC\n")
+
+ def test5(self):
+ """#def with argstring, gobble WS, list used in call"""
+ self.verify(" #def testMeth($a=999) \n1234-$a\n #end def\n$testMeth([1,2,3])",
+ "1234-[1, 2, 3]\n")
+
+ def test6(self):
+ """#def with 2 args, gobble WS, list used in call"""
+ self.verify(" #def testMeth($a, $b='default') \n1234-$a$b\n #end def\n$testMeth([1,2,3])",
+ "1234-[1, 2, 3]default\n")
+
+ def test7(self):
+ """#def with *args, gobble WS"""
+ self.verify(" #def testMeth($*args) \n1234-$args\n #end def\n$testMeth",
+ "1234-()\n")
+
+ def test8(self):
+ """#def with **KWs, gobble WS"""
+ self.verify(" #def testMeth($**KWs) \n1234-$KWs\n #end def\n$testMeth",
+ "1234-{}\n")
+
+ def test9(self):
+ """#def with *args + **KWs, gobble WS"""
+ self.verify(" #def testMeth($*args, $**KWs) \n1234-$args-$KWs\n #end def\n$testMeth",
+ "1234-()-{}\n")
+
+ def test10(self):
+ """#def with *args + **KWs, gobble WS"""
+ self.verify(
+ " #def testMeth($*args, $**KWs) \n1234-$args-$KWs.a\n #end def\n$testMeth(1,2, a=1)",
+ "1234-(1, 2)-1\n")
+
+
+ def test11(self):
+ """single line #def with extra WS"""
+ self.verify(
+ "#def testMeth: aoeuaoeu\n- $testMeth -",
+ "- aoeuaoeu -")
+
+ def test12(self):
+ """single line #def with extra WS and nested $placeholders"""
+ self.verify(
+ "#def testMeth: $anInt $aFunc(1234)\n- $testMeth -",
+ "- 1 1234 -")
+
+ def test13(self):
+ """single line #def escaped $placeholders"""
+ self.verify(
+ "#def testMeth: \$aFunc(\$anInt)\n- $testMeth -",
+ "- $aFunc($anInt) -")
+
+ def test14(self):
+ """single line #def 1 escaped $placeholders"""
+ self.verify(
+ "#def testMeth: \$aFunc($anInt)\n- $testMeth -",
+ "- $aFunc(1) -")
+
+ def test15(self):
+ """single line #def 1 escaped $placeholders + more WS"""
+ self.verify(
+ "#def testMeth : \$aFunc($anInt)\n- $testMeth -",
+ "- $aFunc(1) -")
+
+ def test16(self):
+ """multiline #def with $ on methodName"""
+ self.verify("#def $testMeth\n1234\n#end def\n$testMeth",
+ "1234\n")
+
+ def test17(self):
+ """single line #def with $ on methodName"""
+ self.verify("#def $testMeth:1234\n$testMeth",
+ "1234")
+
+ def test18(self):
+ """single line #def with an argument"""
+ self.verify("#def $testMeth($arg=1234):$arg\n$testMeth",
+ "1234")
+
+ def test19(self):
+ """#def that extends over two lines with arguments"""
+ self.verify("#def $testMeth($arg=1234,\n"
+ +" $arg2=5678)\n"
+ +"$arg $arg2\n"
+ +"#end def\n"
+ +"$testMeth",
+ "1234 5678\n")
+
+class DecoratorDirective(OutputTest):
+ def test1(self):
+ """single line #def with decorator"""
+
+ self.verify("#@ blah", "#@ blah")
+ self.verify("#@23 blah", "#@23 blah")
+ self.verify("#@@TR: comment", "#@@TR: comment")
+
+ self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
+ +"#@testdecorator"
+ +"\n#def $testMeth():1234\n$testMeth",
+
+ "1234")
+
+ self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
+ +"#@testdecorator"
+ +"\n#block $testMeth():1234",
+
+ "1234")
+
+ try:
+ self.verify(
+ "#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
+ +"#@testdecorator\n sdf"
+ +"\n#def $testMeth():1234\n$testMeth",
+
+ "1234")
+ except ParseError:
+ pass
+ else:
+ self.fail('should raise a ParseError')
+
+ def test2(self):
+ """#def with multiple decorators"""
+ self.verify("#from Cheetah.Tests.SyntaxAndOutput import testdecorator\n"
+ +"#@testdecorator\n"
+ +"#@testdecorator\n"
+ +"#def testMeth\n"
+ +"1234\n"
+ "#end def\n"
+ "$testMeth",
+ "1234\n")
+
+if versionTuple < (2,4):
+ del DecoratorDirective
+
+class BlockDirective(OutputTest):
+
+ def test1(self):
+ """#block without argstring"""
+ self.verify("#block testBlock\n1234\n#end block",
+ "1234\n")
+
+ self.verify("#block testBlock ##comment\n1234\n#end block",
+ "1234\n")
+
+ def test2(self):
+ """#block without argstring, gobble WS"""
+ self.verify(" #block testBlock \n1234\n #end block ",
+ "1234\n")
+
+ def test3(self):
+ """#block with argstring, gobble WS
+
+ Because blocks can be reused in multiple parts of the template arguments
+ (!!with defaults!!) can be given."""
+
+ self.verify(" #block testBlock($a=999) \n1234-$a\n #end block ",
+ "1234-999\n")
+
+ def test4(self):
+ """#block with 2 args, gobble WS"""
+ self.verify(" #block testBlock($a=999, $b=444) \n1234-$a$b\n #end block ",
+ "1234-999444\n")
+
+
+ def test5(self):
+ """#block with 2 nested blocks
+
+ Blocks can be nested to any depth and the name of the block is optional
+ for the #end block part: #end block OR #end block [name] """
+
+ self.verify("""#block testBlock
+this is a test block
+#block outerNest
+outer
+#block innerNest
+inner
+#end block innerNest
+#end block outerNest
+---
+#end block testBlock
+""",
+ "this is a test block\nouter\ninner\n---\n")
+
+
+ def test6(self):
+ """single line #block """
+ self.verify(
+ "#block testMeth: This is my block",
+ "This is my block")
+
+ def test7(self):
+ """single line #block with WS"""
+ self.verify(
+ "#block testMeth: This is my block",
+ "This is my block")
+
+ def test8(self):
+ """single line #block 1 escaped $placeholders"""
+ self.verify(
+ "#block testMeth: \$aFunc($anInt)",
+ "$aFunc(1)")
+
+ def test9(self):
+ """single line #block 1 escaped $placeholders + WS"""
+ self.verify(
+ "#block testMeth: \$aFunc( $anInt )",
+ "$aFunc( 1 )")
+
+ def test10(self):
+ """single line #block 1 escaped $placeholders + more WS"""
+ self.verify(
+ "#block testMeth : \$aFunc( $anInt )",
+ "$aFunc( 1 )")
+
+ def test11(self):
+ """multiline #block $ on argstring"""
+ self.verify("#block $testBlock\n1234\n#end block",
+ "1234\n")
+
+ def test12(self):
+ """single line #block with $ on methodName """
+ self.verify(
+ "#block $testMeth: This is my block",
+ "This is my block")
+
+ def test13(self):
+ """single line #block with an arg """
+ self.verify(
+ "#block $testMeth($arg='This is my block'): $arg",
+ "This is my block")
+
+ def test14(self):
+ """single line #block with None for content"""
+ self.verify(
+ """#block $testMeth: $None\ntest $testMeth-""",
+ "test -")
+
+ def test15(self):
+ """single line #block with nothing for content"""
+ self.verify(
+ """#block $testMeth: \nfoo\n#end block\ntest $testMeth-""",
+ "foo\ntest foo\n-")
+
+class IncludeDirective(OutputTest):
+
+ def setUp(self):
+ fp = open('parseTest.txt','w')
+ fp.write("$numOne $numTwo")
+ fp.flush()
+ fp.close
+
+ def tearDown(self):
+ if os.path.exists('parseTest.txt'):
+ os.remove('parseTest.txt')
+
+ def test1(self):
+ """#include raw of source $emptyString"""
+ self.verify("#include raw source=$emptyString",
+ "")
+
+ def test2(self):
+ """#include raw of source $blockToBeParsed"""
+ self.verify("#include raw source=$blockToBeParsed",
+ "$numOne $numTwo")
+
+ def test3(self):
+ """#include raw of 'parseTest.txt'"""
+ self.verify("#include raw 'parseTest.txt'",
+ "$numOne $numTwo")
+
+ def test4(self):
+ """#include raw of $includeFileName"""
+ self.verify("#include raw $includeFileName",
+ "$numOne $numTwo")
+
+ def test5(self):
+ """#include raw of $includeFileName, with WS"""
+ self.verify(" #include raw $includeFileName ",
+ "$numOne $numTwo")
+
+ def test6(self):
+ """#include raw of source= , with WS"""
+ self.verify(" #include raw source='This is my $Source '*2 ",
+ "This is my $Source This is my $Source ")
+
+ def test7(self):
+ """#include of $blockToBeParsed"""
+ self.verify("#include source=$blockToBeParsed",
+ "1 2")
+
+ def test8(self):
+ """#include of $blockToBeParsed, with WS"""
+ self.verify(" #include source=$blockToBeParsed ",
+ "1 2")
+
+ def test9(self):
+ """#include of 'parseTest.txt', with WS"""
+ self.verify(" #include source=$blockToBeParsed ",
+ "1 2")
+
+ def test10(self):
+ """#include of "parseTest.txt", with WS"""
+ self.verify(" #include source=$blockToBeParsed ",
+ "1 2")
+
+ def test11(self):
+ """#include of 'parseTest.txt', with WS and surrounding text"""
+ self.verify("aoeu\n #include source=$blockToBeParsed \naoeu",
+ "aoeu\n1 2aoeu")
+
+ def test12(self):
+ """#include of 'parseTest.txt', with WS and explicit closure"""
+ self.verify(" #include source=$blockToBeParsed# ",
+ " 1 2 ")
+
+
+class SilentDirective(OutputTest):
+
+ def test1(self):
+ """simple #silent"""
+ self.verify("#silent $aFunc",
+ "")
+
+ def test2(self):
+ """simple #silent"""
+ self.verify("#silent $anObj.callIt\n$anObj.callArg",
+ "1234")
+
+ self.verify("#silent $anObj.callIt ##comment\n$anObj.callArg",
+ "1234")
+
+ def test3(self):
+ """simple #silent"""
+ self.verify("#silent $anObj.callIt(99)\n$anObj.callArg",
+ "99")
+
+class SetDirective(OutputTest):
+
+ def test1(self):
+ """simple #set"""
+ self.verify("#set $testVar = 'blarg'\n$testVar",
+ "blarg")
+ self.verify("#set testVar = 'blarg'\n$testVar",
+ "blarg")
+
+
+ self.verify("#set testVar = 'blarg'##comment\n$testVar",
+ "blarg")
+
+ def test2(self):
+ """simple #set with no WS between operands"""
+ self.verify("#set $testVar='blarg'",
+ "")
+ def test3(self):
+ """#set + use of var"""
+ self.verify("#set $testVar = 'blarg'\n$testVar",
+ "blarg")
+
+ def test4(self):
+ """#set + use in an #include"""
+ self.verify("#set global $aSetVar = 1234\n#include source=$includeBlock2",
+ "1 2 1234")
+
+ def test5(self):
+ """#set with a dictionary"""
+ self.verify( """#set $testDict = {'one':'one1','two':'two2','three':'three3'}
+$testDict.one
+$testDict.two""",
+ "one1\ntwo2")
+
+ def test6(self):
+ """#set with string, then used in #if block"""
+
+ self.verify("""#set $test='a string'\n#if $test#blarg#end if""",
+ "blarg")
+
+ def test7(self):
+ """simple #set, gobble WS"""
+ self.verify(" #set $testVar = 'blarg' ",
+ "")
+
+ def test8(self):
+ """simple #set, don't gobble WS"""
+ self.verify(" #set $testVar = 'blarg'#---",
+ " ---")
+
+ def test9(self):
+ """simple #set with a list"""
+ self.verify(" #set $testVar = [1, 2, 3] \n$testVar",
+ "[1, 2, 3]")
+
+ def test10(self):
+ """simple #set global with a list"""
+ self.verify(" #set global $testVar = [1, 2, 3] \n$testVar",
+ "[1, 2, 3]")
+
+ def test11(self):
+ """simple #set global with a list and *cache
+
+ Caching only works with global #set vars. Local vars are not accesible
+ to the cache namespace.
+ """
+
+ self.verify(" #set global $testVar = [1, 2, 3] \n$*testVar",
+ "[1, 2, 3]")
+
+ def test12(self):
+ """simple #set global with a list and *<int>*cache"""
+ self.verify(" #set global $testVar = [1, 2, 3] \n$*5*testVar",
+ "[1, 2, 3]")
+
+ def test13(self):
+ """simple #set with a list and *<float>*cache"""
+ self.verify(" #set global $testVar = [1, 2, 3] \n$*.5*testVar",
+ "[1, 2, 3]")
+
+ def test14(self):
+ """simple #set without NameMapper on"""
+ self.verify("""#compiler useNameMapper = 0\n#set $testVar = 1 \n$testVar""",
+ "1")
+
+ def test15(self):
+ """simple #set without $"""
+ self.verify("""#set testVar = 1 \n$testVar""",
+ "1")
+
+ def test16(self):
+ """simple #set global without $"""
+ self.verify("""#set global testVar = 1 \n$testVar""",
+ "1")
+
+ def test17(self):
+ """simple #set module without $"""
+ self.verify("""#set module __foo__ = 'bar'\n$__foo__""",
+ "bar")
+
+ def test18(self):
+ """#set with i,j=list style assignment"""
+ self.verify("""#set i,j = [1,2]\n$i$j""",
+ "12")
+ self.verify("""#set $i,$j = [1,2]\n$i$j""",
+ "12")
+
+ def test19(self):
+ """#set with (i,j)=list style assignment"""
+ self.verify("""#set (i,j) = [1,2]\n$i$j""",
+ "12")
+ self.verify("""#set ($i,$j) = [1,2]\n$i$j""",
+ "12")
+
+ def test20(self):
+ """#set with i, (j,k)=list style assignment"""
+ self.verify("""#set i, (j,k) = [1,(2,3)]\n$i$j$k""",
+ "123")
+ self.verify("""#set $i, ($j,$k) = [1,(2,3)]\n$i$j$k""",
+ "123")
+
+
+class IfDirective(OutputTest):
+
+ def test1(self):
+ """simple #if block"""
+ self.verify("#if 1\n$aStr\n#end if\n",
+ "blarg\n")
+
+ self.verify("#if 1:\n$aStr\n#end if\n",
+ "blarg\n")
+
+ self.verify("#if 1: \n$aStr\n#end if\n",
+ "blarg\n")
+
+ self.verify("#if 1: ##comment \n$aStr\n#end if\n",
+ "blarg\n")
+
+ self.verify("#if 1 ##comment \n$aStr\n#end if\n",
+ "blarg\n")
+
+ self.verify("#if 1##for i in range(10)#$i#end for##end if",
+ '0123456789')
+
+ self.verify("#if 1: #for i in range(10)#$i#end for",
+ '0123456789')
+
+ self.verify("#if 1: #for i in range(10):$i",
+ '0123456789')
+
+ def test2(self):
+ """simple #if block, with WS"""
+ self.verify(" #if 1\n$aStr\n #end if \n",
+ "blarg\n")
+ def test3(self):
+ """simple #if block, with WS and explicit closures"""
+ self.verify(" #if 1#\n$aStr\n #end if #--\n",
+ " \nblarg\n --\n")
+
+ def test4(self):
+ """#if block using $numOne"""
+ self.verify("#if $numOne\n$aStr\n#end if\n",
+ "blarg\n")
+
+ def test5(self):
+ """#if block using $zero"""
+ self.verify("#if $zero\n$aStr\n#end if\n",
+ "")
+ def test6(self):
+ """#if block using $emptyString"""
+ self.verify("#if $emptyString\n$aStr\n#end if\n",
+ "")
+ def test7(self):
+ """#if ... #else ... block using a $emptyString"""
+ self.verify("#if $emptyString\n$anInt\n#else\n$anInt - $anInt\n#end if",
+ "1 - 1\n")
+
+ def test8(self):
+ """#if ... #elif ... #else ... block using a $emptyString"""
+ self.verify("#if $emptyString\n$c\n#elif $numOne\n$numOne\n#else\n$c - $c\n#end if",
+ "1\n")
+
+ def test9(self):
+ """#if 'not' test, with #slurp"""
+ self.verify("#if not $emptyString\n$aStr#slurp\n#end if\n",
+ "blarg")
+
+ def test10(self):
+ """#if block using $*emptyString
+
+ This should barf
+ """
+ try:
+ self.verify("#if $*emptyString\n$aStr\n#end if\n",
+ "")
+ except ParseError:
+ pass
+ else:
+ self.fail('This should barf')
+
+ def test11(self):
+ """#if block using invalid top-level $(placeholder) syntax - should barf"""
+
+ for badSyntax in ("#if $*5*emptyString\n$aStr\n#end if\n",
+ "#if ${emptyString}\n$aStr\n#end if\n",
+ "#if $(emptyString)\n$aStr\n#end if\n",
+ "#if $[emptyString]\n$aStr\n#end if\n",
+ "#if $!emptyString\n$aStr\n#end if\n",
+ ):
+ try:
+ self.verify(badSyntax, "")
+ except ParseError:
+ pass
+ else:
+ self.fail('This should barf')
+
+ def test12(self):
+ """#if ... #else if ... #else ... block using a $emptyString
+ Same as test 8 but using else if instead of elif"""
+ self.verify("#if $emptyString\n$c\n#else if $numOne\n$numOne\n#else\n$c - $c\n#end if",
+ "1\n")
+
+
+ def test13(self):
+ """#if# ... #else # ... block using a $emptyString with """
+ self.verify("#if $emptyString# $anInt#else#$anInt - $anInt#end if",
+ "1 - 1")
+
+ def test14(self):
+ """single-line #if: simple"""
+ self.verify("#if $emptyString then 'true' else 'false'",
+ "false")
+
+ def test15(self):
+ """single-line #if: more complex"""
+ self.verify("#if $anInt then 'true' else 'false'",
+ "true")
+
+ def test16(self):
+ """single-line #if: with the words 'else' and 'then' in the output """
+ self.verify("#if ($anInt and not $emptyString==''' else ''') then $str('then') else 'else'",
+ "then")
+
+ def test17(self):
+ """single-line #if: """
+ self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo",
+ "foo\nfoo")
+
+
+ self.verify("#if 1: foo\n#if 0: bar\n#if 1: foo",
+ "foo\nfoo")
+
+ def test18(self):
+ """single-line #if: \n#else: """
+ self.verify("#if 1: foo\n#elif 0: bar",
+ "foo\n")
+
+ self.verify("#if 1: foo\n#elif 0: bar\n#else: blarg\n",
+ "foo\n")
+
+ self.verify("#if 0: foo\n#elif 0: bar\n#else: blarg\n",
+ "blarg\n")
+
+class UnlessDirective(OutputTest):
+
+ def test1(self):
+ """#unless 1"""
+ self.verify("#unless 1\n 1234 \n#end unless",
+ "")
+
+ self.verify("#unless 1:\n 1234 \n#end unless",
+ "")
+
+ self.verify("#unless 1: ##comment\n 1234 \n#end unless",
+ "")
+
+ self.verify("#unless 1 ##comment\n 1234 \n#end unless",
+ "")
+
+
+ def test2(self):
+ """#unless 0"""
+ self.verify("#unless 0\n 1234 \n#end unless",
+ " 1234 \n")
+
+ def test3(self):
+ """#unless $none"""
+ self.verify("#unless $none\n 1234 \n#end unless",
+ " 1234 \n")
+
+ def test4(self):
+ """#unless $numTwo"""
+ self.verify("#unless $numTwo\n 1234 \n#end unless",
+ "")
+
+ def test5(self):
+ """#unless $numTwo with WS"""
+ self.verify(" #unless $numTwo \n 1234 \n #end unless ",
+ "")
+
+ def test6(self):
+ """single-line #unless"""
+ self.verify("#unless 1: 1234", "")
+ self.verify("#unless 0: 1234", "1234")
+ self.verify("#unless 0: 1234\n"*2, "1234\n"*2)
+
+class PSP(OutputTest):
+
+ def test1(self):
+ """simple <%= [int] %>"""
+ self.verify("<%= 1234 %>", "1234")
+
+ def test2(self):
+ """simple <%= [string] %>"""
+ self.verify("<%= 'blarg' %>", "blarg")
+
+ def test3(self):
+ """simple <%= None %>"""
+ self.verify("<%= None %>", "")
+ def test4(self):
+ """simple <%= [string] %> + $anInt"""
+ self.verify("<%= 'blarg' %>$anInt", "blarg1")
+
+ def test5(self):
+ """simple <%= [EXPR] %> + $anInt"""
+ self.verify("<%= ('blarg'*2).upper() %>$anInt", "BLARGBLARG1")
+
+ def test6(self):
+ """for loop in <%%>"""
+ self.verify("<% for i in range(5):%>1<%end%>", "11111")
+
+ def test7(self):
+ """for loop in <%%> and using <%=i%>"""
+ self.verify("<% for i in range(5):%><%=i%><%end%>", "01234")
+
+ def test8(self):
+ """for loop in <% $%> and using <%=i%>"""
+ self.verify("""<% for i in range(5):
+ i=i*2$%><%=i%><%end%>""", "02468")
+
+ def test9(self):
+ """for loop in <% $%> and using <%=i%> plus extra text"""
+ self.verify("""<% for i in range(5):
+ i=i*2$%><%=i%>-<%end%>""", "0-2-4-6-8-")
+
+
+class WhileDirective(OutputTest):
+ def test1(self):
+ """simple #while with a counter"""
+ self.verify("#set $i = 0\n#while $i < 5\n$i#slurp\n#set $i += 1\n#end while",
+ "01234")
+
+class ContinueDirective(OutputTest):
+ def test1(self):
+ """#continue with a #while"""
+ self.verify("""#set $i = 0
+#while $i < 5
+#if $i == 3
+ #set $i += 1
+ #continue
+#end if
+$i#slurp
+#set $i += 1
+#end while""",
+ "0124")
+
+ def test2(self):
+ """#continue with a #for"""
+ self.verify("""#for $i in range(5)
+#if $i == 3
+ #continue
+#end if
+$i#slurp
+#end for""",
+ "0124")
+
+class BreakDirective(OutputTest):
+ def test1(self):
+ """#break with a #while"""
+ self.verify("""#set $i = 0
+#while $i < 5
+#if $i == 3
+ #break
+#end if
+$i#slurp
+#set $i += 1
+#end while""",
+ "012")
+
+ def test2(self):
+ """#break with a #for"""
+ self.verify("""#for $i in range(5)
+#if $i == 3
+ #break
+#end if
+$i#slurp
+#end for""",
+ "012")
+
+
+class TryDirective(OutputTest):
+
+ def test1(self):
+ """simple #try
+ """
+ self.verify("#try\n1234\n#except\nblarg\n#end try",
+ "1234\n")
+
+ def test2(self):
+ """#try / #except with #raise
+ """
+ self.verify("#try\n#raise ValueError\n#except\nblarg\n#end try",
+ "blarg\n")
+
+ def test3(self):
+ """#try / #except with #raise + WS
+
+ Should gobble
+ """
+ self.verify(" #try \n #raise ValueError \n #except \nblarg\n #end try",
+ "blarg\n")
+
+
+ def test4(self):
+ """#try / #except with #raise + WS and leading text
+
+ Shouldn't gobble
+ """
+ self.verify("--#try \n #raise ValueError \n #except \nblarg\n #end try#--",
+ "--\nblarg\n --")
+
+ def test5(self):
+ """nested #try / #except with #raise
+ """
+ self.verify(
+"""#try
+ #raise ValueError
+#except
+ #try
+ #raise ValueError
+ #except
+blarg
+ #end try
+#end try""",
+ "blarg\n")
+
+class PassDirective(OutputTest):
+ def test1(self):
+ """#pass in a #try / #except block
+ """
+ self.verify("#try\n#raise ValueError\n#except\n#pass\n#end try",
+ "")
+
+ def test2(self):
+ """#pass in a #try / #except block + WS
+ """
+ self.verify(" #try \n #raise ValueError \n #except \n #pass \n #end try",
+ "")
+
+
+class AssertDirective(OutputTest):
+ def test1(self):
+ """simple #assert
+ """
+ self.verify("#set $x = 1234\n#assert $x == 1234",
+ "")
+
+ def test2(self):
+ """simple #assert that fails
+ """
+ def test(self=self):
+ self.verify("#set $x = 1234\n#assert $x == 999",
+ ""),
+ self.failUnlessRaises(AssertionError, test)
+
+ def test3(self):
+ """simple #assert with WS
+ """
+ self.verify("#set $x = 1234\n #assert $x == 1234 ",
+ "")
+
+
+class RaiseDirective(OutputTest):
+ def test1(self):
+ """simple #raise ValueError
+
+ Should raise ValueError
+ """
+ def test(self=self):
+ self.verify("#raise ValueError",
+ ""),
+ self.failUnlessRaises(ValueError, test)
+
+ def test2(self):
+ """#raise ValueError in #if block
+
+ Should raise ValueError
+ """
+ def test(self=self):
+ self.verify("#if 1\n#raise ValueError\n#end if\n",
+ "")
+ self.failUnlessRaises(ValueError, test)
+
+
+ def test3(self):
+ """#raise ValueError in #if block
+
+ Shouldn't raise ValueError
+ """
+ self.verify("#if 0\n#raise ValueError\n#else\nblarg#end if\n",
+ "blarg\n")
+
+
+
+class ImportDirective(OutputTest):
+ def test1(self):
+ """#import math
+ """
+ self.verify("#import math",
+ "")
+
+ def test2(self):
+ """#import math + WS
+
+ Should gobble
+ """
+ self.verify(" #import math ",
+ "")
+
+ def test3(self):
+ """#import math + WS + leading text
+
+ Shouldn't gobble
+ """
+ self.verify(" -- #import math ",
+ " -- ")
+
+ def test4(self):
+ """#from math import syn
+ """
+ self.verify("#from math import cos",
+ "")
+
+ def test5(self):
+ """#from math import cos + WS
+ Should gobble
+ """
+ self.verify(" #from math import cos ",
+ "")
+
+ def test6(self):
+ """#from math import cos + WS + leading text
+ Shouldn't gobble
+ """
+ self.verify(" -- #from math import cos ",
+ " -- ")
+
+ def test7(self):
+ """#from math import cos -- use it
+ """
+ self.verify("#from math import cos\n$cos(0)",
+ "1.0")
+
+ def test8(self):
+ """#from math import cos,tan,sin -- and use them
+ """
+ self.verify("#from math import cos, tan, sin\n$cos(0)-$tan(0)-$sin(0)",
+ "1.0-0.0-0.0")
+
+ def test9(self):
+ """#import os.path -- use it
+ """
+
+ self.verify("#import os.path\n$os.path.exists('.')",
+ repr(True))
+
+ def test10(self):
+ """#import os.path -- use it with NameMapper turned off
+ """
+ self.verify("""##
+#compiler-settings
+useNameMapper=False
+#end compiler-settings
+#import os.path
+$os.path.exists('.')""",
+ repr(True))
+
+ def test11(self):
+ """#from math import *
+ """
+
+ self.verify("#from math import *\n$pow(1,2) $log10(10)",
+ "1.0 1.0")
+
+class CompilerDirective(OutputTest):
+ def test1(self):
+ """overriding the commentStartToken
+ """
+ self.verify("""$anInt##comment
+#compiler commentStartToken = '//'
+$anInt//comment
+""",
+ "1\n1\n")
+
+ def test2(self):
+ """overriding and resetting the commentStartToken
+ """
+ self.verify("""$anInt##comment
+#compiler commentStartToken = '//'
+$anInt//comment
+#compiler reset
+$anInt//comment
+""",
+ "1\n1\n1//comment\n")
+
+
+class CompilerSettingsDirective(OutputTest):
+
+ def test1(self):
+ """overriding the cheetahVarStartToken
+ """
+ self.verify("""$anInt
+#compiler-settings
+cheetahVarStartToken = @
+#end compiler-settings
+ at anInt
+#compiler-settings reset
+$anInt
+""",
+ "1\n1\n1\n")
+
+ def test2(self):
+ """overriding the directiveStartToken
+ """
+ self.verify("""#set $x = 1234
+$x
+#compiler-settings
+directiveStartToken = @
+#end compiler-settings
+ at set $x = 1234
+$x
+""",
+ "1234\n1234\n")
+
+ def test3(self):
+ """overriding the commentStartToken
+ """
+ self.verify("""$anInt##comment
+#compiler-settings
+commentStartToken = //
+#end compiler-settings
+$anInt//comment
+""",
+ "1\n1\n")
+
+if sys.platform.startswith('java'):
+ del CompilerDirective
+ del CompilerSettingsDirective
+
+class ExtendsDirective(OutputTest):
+
+ def test1(self):
+ """#extends Cheetah.Templates._SkeletonPage"""
+ self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage
+#extends _SkeletonPage
+#implements respond
+$spacer()
+""",
+ '<img src="spacer.gif" width="1" height="1" alt="" />\n')
+
+
+ self.verify("""#from Cheetah.Templates._SkeletonPage import _SkeletonPage
+#extends _SkeletonPage
+#implements respond(foo=1234)
+$spacer()$foo
+""",
+ '<img src="spacer.gif" width="1" height="1" alt="" />1234\n')
+
+ def test2(self):
+ """#extends Cheetah.Templates.SkeletonPage without #import"""
+ self.verify("""#extends Cheetah.Templates.SkeletonPage
+#implements respond
+$spacer()
+""",
+ '<img src="spacer.gif" width="1" height="1" alt="" />\n')
+
+ def test3(self):
+ """#extends Cheetah.Templates.SkeletonPage.SkeletonPage without #import"""
+ self.verify("""#extends Cheetah.Templates.SkeletonPage.SkeletonPage
+#implements respond
+$spacer()
+""",
+ '<img src="spacer.gif" width="1" height="1" alt="" />\n')
+
+ def test4(self):
+ """#extends with globals and searchList test"""
+ self.verify("""#extends Cheetah.Templates.SkeletonPage
+#set global g="Hello"
+#implements respond
+$g $numOne
+""",
+ 'Hello 1\n')
+
+
+class SuperDirective(OutputTest):
+ def test1(self):
+ tmpl1 = Template.compile('''$foo $bar(99)
+ #def foo: this is base foo
+ #def bar(arg): super-$arg''')
+
+ tmpl2 = tmpl1.subclass('''
+ #implements dummy
+ #def foo
+ #super
+ This is child foo
+ #super(trans=trans)
+ $bar(1234)
+ #end def
+ #def bar(arg): #super($arg)
+ ''')
+ expected = ('this is base foo '
+ 'This is child foo\nthis is base foo '
+ 'super-1234\n super-99')
+ assert str(tmpl2()).strip()==expected
+
+
+class ImportantExampleCases(OutputTest):
+ def test1(self):
+ """how to make a comma-delimited list"""
+ self.verify("""#set $sep = ''
+#for $letter in $letterList
+$sep$letter#slurp
+#set $sep = ', '
+#end for
+""",
+ "a, b, c")
+
+class FilterDirective(OutputTest):
+ convertEOLs=False
+
+ def _getCompilerSettings(self):
+ return {'useFilterArgsInPlaceholders':True}
+
+ def test1(self):
+ """#filter Filter
+ """
+ self.verify("#filter Filter\n$none#end filter",
+ "")
+
+ self.verify("#filter Filter: $none",
+ "")
+
+ def test2(self):
+ """#filter ReplaceNone with WS
+ """
+ self.verify("#filter Filter \n$none#end filter",
+ "")
+
+ def test3(self):
+ """#filter MaxLen -- maxlen of 5"""
+
+ self.verify("#filter MaxLen \n${tenDigits, $maxlen=5}#end filter",
+ "12345")
+
+ def test4(self):
+ """#filter MaxLen -- no maxlen
+ """
+ self.verify("#filter MaxLen \n${tenDigits}#end filter",
+ "1234567890")
+
+ def test5(self):
+ """#filter WebSafe -- basic usage
+ """
+ self.verify("#filter WebSafe \n$webSafeTest#end filter",
+ "abc <=> &")
+
+ def test6(self):
+ """#filter WebSafe -- also space
+ """
+ self.verify("#filter WebSafe \n${webSafeTest, $also=' '}#end filter",
+ "abc <=> &")
+
+ def test7(self):
+ """#filter WebSafe -- also space, without $ on the args
+ """
+ self.verify("#filter WebSafe \n${webSafeTest, also=' '}#end filter",
+ "abc <=> &")
+
+ def test8(self):
+ """#filter Strip -- trailing newline
+ """
+ self.verify("#filter Strip\n$strip1#end filter",
+ "strippable whitespace\n")
+
+ def test9(self):
+ """#filter Strip -- no trailing newine
+ """
+ self.verify("#filter Strip\n$strip2#end filter",
+ "strippable whitespace")
+
+ def test10(self):
+ """#filter Strip -- multi-line
+ """
+ self.verify("#filter Strip\n$strip3#end filter",
+ "strippable whitespace\n1 2 3\n")
+
+ def test11(self):
+ """#filter StripSqueeze -- canonicalize all whitespace to ' '
+ """
+ self.verify("#filter StripSqueeze\n$strip3#end filter",
+ "strippable whitespace 1 2 3")
+
+
+class EchoDirective(OutputTest):
+ def test1(self):
+ """#echo 1234
+ """
+ self.verify("#echo 1234",
+ "1234")
+
+class SilentDirective(OutputTest):
+ def test1(self):
+ """#silent 1234
+ """
+ self.verify("#silent 1234",
+ "")
+
+class ErrorCatcherDirective(OutputTest):
+ pass
+
+
+class VarExists(OutputTest): # Template.varExists()
+
+ def test1(self):
+ """$varExists('$anInt')
+ """
+ self.verify("$varExists('$anInt')",
+ repr(True))
+
+ def test2(self):
+ """$varExists('anInt')
+ """
+ self.verify("$varExists('anInt')",
+ repr(True))
+
+ def test3(self):
+ """$varExists('$anInt')
+ """
+ self.verify("$varExists('$bogus')",
+ repr(False))
+
+ def test4(self):
+ """$varExists('$anInt') combined with #if false
+ """
+ self.verify("#if $varExists('$bogus')\n1234\n#else\n999\n#end if",
+ "999\n")
+
+ def test5(self):
+ """$varExists('$anInt') combined with #if true
+ """
+ self.verify("#if $varExists('$anInt')\n1234\n#else\n999#end if",
+ "1234\n")
+
+class GetVar(OutputTest): # Template.getVar()
+ def test1(self):
+ """$getVar('$anInt')
+ """
+ self.verify("$getVar('$anInt')",
+ "1")
+
+ def test2(self):
+ """$getVar('anInt')
+ """
+ self.verify("$getVar('anInt')",
+ "1")
+
+ def test3(self):
+ """$self.getVar('anInt')
+ """
+ self.verify("$self.getVar('anInt')",
+ "1")
+
+ def test4(self):
+ """$getVar('bogus', 1234)
+ """
+ self.verify("$getVar('bogus', 1234)",
+ "1234")
+
+ def test5(self):
+ """$getVar('$bogus', 1234)
+ """
+ self.verify("$getVar('$bogus', 1234)",
+ "1234")
+
+
+class MiscComplexSyntax(OutputTest):
+ def test1(self):
+ """Complex use of {},[] and () in a #set expression
+ ----
+ #set $c = {'A':0}[{}.get('a', {'a' : 'A'}['a'])]
+ $c
+ """
+ self.verify("#set $c = {'A':0}[{}.get('a', {'a' : 'A'}['a'])]\n$c",
+ "0")
+
+
+class CGI(OutputTest):
+ """CGI scripts with(out) the CGI environment and with(out) GET variables.
+ """
+ convertEOLs=False
+
+ def _beginCGI(self):
+ os.environ['REQUEST_METHOD'] = "GET"
+ def _endCGI(self):
+ try:
+ del os.environ['REQUEST_METHOD']
+ except KeyError:
+ pass
+ _guaranteeNoCGI = _endCGI
+
+
+ def test1(self):
+ """A regular template."""
+ self._guaranteeNoCGI()
+ source = "#extends Cheetah.Tools.CGITemplate\n" + \
+ "#implements respond\n" + \
+ "$cgiHeaders#slurp\n" + \
+ "Hello, world!"
+ self.verify(source, "Hello, world!")
+
+
+ def test2(self):
+ """A CGI script."""
+ self._beginCGI()
+ source = "#extends Cheetah.Tools.CGITemplate\n" + \
+ "#implements respond\n" + \
+ "$cgiHeaders#slurp\n" + \
+ "Hello, world!"
+ self.verify(source, "Content-type: text/html\n\nHello, world!")
+ self._endCGI()
+
+
+ def test3(self):
+ """A (pseudo) Webware servlet.
+
+ This uses the Python syntax escape to set
+ self._CHEETAH__isControlledByWebKit.
+ We could instead do '#silent self._CHEETAH__isControlledByWebKit = True',
+ taking advantage of the fact that it will compile unchanged as long
+ as there's no '$' in the statement. (It won't compile with an '$'
+ because that would convert to a function call, and you can't assign
+ to a function call.) Because this isn't really being called from
+ Webware, we'd better not use any Webware services! Likewise, we'd
+ better not call $cgiImport() because it would be misled.
+ """
+ self._beginCGI()
+ source = "#extends Cheetah.Tools.CGITemplate\n" + \
+ "#implements respond\n" + \
+ "<% self._CHEETAH__isControlledByWebKit = True %>#slurp\n" + \
+ "$cgiHeaders#slurp\n" + \
+ "Hello, world!"
+ self.verify(source, "Hello, world!")
+ self._endCGI()
+
+
+ def test4(self):
+ """A CGI script with a GET variable."""
+ self._beginCGI()
+ os.environ['QUERY_STRING'] = "cgiWhat=world"
+ source = "#extends Cheetah.Tools.CGITemplate\n" + \
+ "#implements respond\n" + \
+ "$cgiHeaders#slurp\n" + \
+ "#silent $webInput(['cgiWhat'])##slurp\n" + \
+ "Hello, $cgiWhat!"
+ self.verify(source,
+ "Content-type: text/html\n\nHello, world!")
+ del os.environ['QUERY_STRING']
+ self._endCGI()
+
+
+
+class WhitespaceAfterDirectiveTokens(OutputTest):
+ def _getCompilerSettings(self):
+ return {'allowWhitespaceAfterDirectiveStartToken':True}
+
+ def test1(self):
+ self.verify("# for i in range(10): $i",
+ "0123456789")
+ self.verify("# for i in range(10)\n$i# end for",
+ "0123456789")
+ self.verify("# for i in range(10)#$i#end for",
+ "0123456789")
+
+
+
+class DefmacroDirective(OutputTest):
+ def _getCompilerSettings(self):
+ def aMacro(src):
+ return '$aStr'
+
+ return {'macroDirectives':{'aMacro':aMacro
+ }}
+
+ def test1(self):
+ self.verify("""\
+#defmacro inc: #set @src +=1
+#set i = 1
+#inc: $i
+$i""",
+ "2")
+
+
+
+ self.verify("""\
+#defmacro test
+#for i in range(10): @src
+#end defmacro
+#test: $i-foo#slurp
+#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo012")
+
+ self.verify("""\
+#defmacro test
+#for i in range(10): @src
+#end defmacro
+#test: $i-foo
+#for i in range(3): $i""",
+ "0-foo\n1-foo\n2-foo\n3-foo\n4-foo\n5-foo\n6-foo\n7-foo\n8-foo\n9-foo\n012")
+
+
+ self.verify("""\
+#defmacro test: #for i in range(10): @src
+#test: $i-foo#slurp
+-#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
+
+ self.verify("""\
+#defmacro test##for i in range(10): @src#end defmacro##slurp
+#test: $i-foo#slurp
+-#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
+
+ self.verify("""\
+#defmacro testFoo: nothing
+#defmacro test(foo=1234): #for i in range(10): @src
+#test foo=234: $i-foo#slurp
+-#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
+
+ self.verify("""\
+#defmacro testFoo: nothing
+#defmacro test(foo=1234): #for i in range(10): @src at foo
+#test foo='-foo'#$i#end test#-#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
+
+ self.verify("""\
+#defmacro testFoo: nothing
+#defmacro test(foo=1234): #for i in range(10): @src.strip()@foo
+#test foo='-foo': $i
+-#for i in range(3): $i""",
+ "0-foo1-foo2-foo3-foo4-foo5-foo6-foo7-foo8-foo9-foo-012")
+
+ def test2(self):
+ self.verify("#aMacro: foo",
+ "blarg")
+ self.verify("#defmacro nested: @macros.aMacro(@src)\n#nested: foo",
+ "blarg")
+
+
+class Indenter(OutputTest):
+ convertEOLs=False
+
+ source = """
+public class X
+{
+ #for $method in $methods
+ $getMethod($method)
+
+ #end for
+}
+//end of class
+
+#def getMethod($method)
+ #indent ++
+ public $getType($method) ${method.Name}($getParams($method.Params));
+ #indent --
+#end def
+
+#def getParams($params)
+ #indent off
+
+ #for $counter in $range($len($params))
+ #if $counter == len($params) - 1
+ $params[$counter]#slurp
+ #else:
+ $params[$counter],
+ #end if
+ #end for
+ #indent on
+#end def
+
+#def getType($method)
+ #indent push
+ #indent=0
+ #if $method.Type == "VT_VOID"
+ void#slurp
+ #elif $method.Type == "VT_INT"
+ int#slurp
+ #elif $method.Type == "VT_VARIANT"
+ Object#slurp
+ #end if
+ #indent pop
+#end def
+"""
+
+ control = """
+public class X
+{
+ public void Foo(
+ _input,
+ _output);
+
+
+ public int Bar(
+ _str1,
+ str2,
+ _str3);
+
+
+ public Object Add(
+ value1,
+ value);
+
+
+}
+//end of class
+
+
+
+"""
+ def _getCompilerSettings(self):
+ return {'useFilterArgsInPlaceholders':True}
+
+ def searchList(self): # Inside Indenter class.
+ class Method:
+ def __init__(self, _name, _type, *_params):
+ self.Name = _name
+ self.Type = _type
+ self.Params = _params
+ methods = [Method("Foo", "VT_VOID", "_input", "_output"),
+ Method("Bar", "VT_INT", "_str1", "str2", "_str3"),
+ Method("Add", "VT_VARIANT", "value1", "value")]
+ return [{"methods": methods}]
+
+ def test1(self): # Inside Indenter class.
+ self.verify(self.source, self.control)
+
+
+##################################################
+## CREATE CONVERTED EOL VERSIONS OF THE TEST CASES
+
+if OutputTest._useNewStyleCompilation and versionTuple >= (2,3):
+ extraCompileKwArgsForDiffBaseclass = {'baseclass':dict}
+else:
+ extraCompileKwArgsForDiffBaseclass = {'baseclass':object}
+
+
+for klass in [var for var in globals().values()
+ if type(var) == types.ClassType and issubclass(var, unittest.TestCase)]:
+ name = klass.__name__
+ if hasattr(klass,'convertEOLs') and klass.convertEOLs:
+ win32Src = r"class %(name)s_Win32EOL(%(name)s): _EOLreplacement = '\r\n'"%locals()
+ macSrc = r"class %(name)s_MacEOL(%(name)s): _EOLreplacement = '\r'"%locals()
+ #print win32Src
+ #print macSrc
+ exec win32Src+'\n'
+ exec macSrc+'\n'
+
+ if versionTuple >= (2,3):
+ src = r"class %(name)s_DiffBaseClass(%(name)s): "%locals()
+ src += " _extraCompileKwArgs = extraCompileKwArgsForDiffBaseclass"
+ exec src+'\n'
+
+ del name
+ del klass
+
+##################################################
+## if run from the command line ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Template.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Template.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Template.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,336 @@
+#!/usr/bin/env python
+
+import pdb
+import sys
+import types
+import os
+import os.path
+import tempfile
+import shutil
+import unittest_local_copy as unittest
+from Cheetah.Template import Template
+
+majorVer, minorVer = sys.version_info[0], sys.version_info[1]
+versionTuple = (majorVer, minorVer)
+
+class TemplateTest(unittest.TestCase):
+ pass
+
+class ClassMethods_compile(TemplateTest):
+ """I am using the same Cheetah source for each test to root out clashes
+ caused by the compile caching in Template.compile().
+ """
+
+ def test_basicUsage(self):
+ klass = Template.compile(source='$foo')
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+
+ def test_baseclassArg(self):
+ klass = Template.compile(source='$foo', baseclass=dict)
+ t = klass({'foo':1234})
+ assert str(t)=='1234'
+
+ klass2 = Template.compile(source='$foo', baseclass=klass)
+ t = klass2({'foo':1234})
+ assert str(t)=='1234'
+
+ klass3 = Template.compile(source='#implements dummy\n$bar', baseclass=klass2)
+ t = klass3({'foo':1234})
+ assert str(t)=='1234'
+
+ klass4 = Template.compile(source='$foo', baseclass='dict')
+ t = klass4({'foo':1234})
+ assert str(t)=='1234'
+
+ def test_moduleFileCaching(self):
+ if versionTuple < (2,3):
+ return
+ tmpDir = tempfile.mkdtemp()
+ try:
+ #print tmpDir
+ assert os.path.exists(tmpDir)
+ klass = Template.compile(source='$foo',
+ cacheModuleFilesForTracebacks=True,
+ cacheDirForModuleFiles=tmpDir)
+ mod = sys.modules[klass.__module__]
+ #print mod.__file__
+ assert os.path.exists(mod.__file__)
+ assert os.path.dirname(mod.__file__)==tmpDir
+ finally:
+ shutil.rmtree(tmpDir, True)
+
+ def test_classNameArg(self):
+ klass = Template.compile(source='$foo', className='foo123')
+ assert klass.__name__=='foo123'
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+
+ def test_moduleNameArg(self):
+ klass = Template.compile(source='$foo', moduleName='foo99')
+ mod = sys.modules['foo99']
+ assert klass.__name__=='foo99'
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+
+
+ klass = Template.compile(source='$foo',
+ moduleName='foo1',
+ className='foo2')
+ mod = sys.modules['foo1']
+ assert klass.__name__=='foo2'
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+
+
+ def test_mainMethodNameArg(self):
+ klass = Template.compile(source='$foo',
+ className='foo123',
+ mainMethodName='testMeth')
+ assert klass.__name__=='foo123'
+ t = klass(namespaces={'foo':1234})
+ #print t.generatedClassCode()
+ assert str(t)=='1234'
+ assert t.testMeth()=='1234'
+
+ klass = Template.compile(source='$foo',
+ moduleName='fooXXX',
+ className='foo123',
+ mainMethodName='testMeth',
+ baseclass=dict)
+ assert klass.__name__=='foo123'
+ t = klass({'foo':1234})
+ #print t.generatedClassCode()
+ assert str(t)=='1234'
+ assert t.testMeth()=='1234'
+
+
+
+ def test_moduleGlobalsArg(self):
+ klass = Template.compile(source='$foo',
+ moduleGlobals={'foo':1234})
+ t = klass()
+ assert str(t)=='1234'
+
+ klass2 = Template.compile(source='$foo', baseclass='Test1',
+ moduleGlobals={'Test1':dict})
+ t = klass2({'foo':1234})
+ assert str(t)=='1234'
+
+ klass3 = Template.compile(source='$foo', baseclass='Test1',
+ moduleGlobals={'Test1':dict, 'foo':1234})
+ t = klass3()
+ assert str(t)=='1234'
+
+
+ def test_keepRefToGeneratedCodeArg(self):
+ klass = Template.compile(source='$foo',
+ className='unique58',
+ cacheCompilationResults=False,
+ keepRefToGeneratedCode=False)
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ assert not t.generatedModuleCode()
+
+
+ klass2 = Template.compile(source='$foo',
+ className='unique58',
+ keepRefToGeneratedCode=True)
+ t = klass2(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ assert t.generatedModuleCode()
+
+ klass3 = Template.compile(source='$foo',
+ className='unique58',
+ keepRefToGeneratedCode=False)
+ t = klass3(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ # still there as this class came from the cache
+ assert t.generatedModuleCode()
+
+
+ def test_compilationCache(self):
+ klass = Template.compile(source='$foo',
+ className='unique111',
+ cacheCompilationResults=False)
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ assert not klass._CHEETAH_isInCompilationCache
+
+
+ # this time it will place it in the cache
+ klass = Template.compile(source='$foo',
+ className='unique111',
+ cacheCompilationResults=True)
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ assert klass._CHEETAH_isInCompilationCache
+
+ # by default it will be in the cache
+ klass = Template.compile(source='$foo',
+ className='unique999099')
+ t = klass(namespaces={'foo':1234})
+ assert str(t)=='1234'
+ assert klass._CHEETAH_isInCompilationCache
+
+
+class ClassMethods_subclass(TemplateTest):
+
+ def test_basicUsage(self):
+ klass = Template.compile(source='$foo', baseclass=dict)
+ t = klass({'foo':1234})
+ assert str(t)=='1234'
+
+ klass2 = klass.subclass(source='$foo')
+ t = klass2({'foo':1234})
+ assert str(t)=='1234'
+
+ klass3 = klass2.subclass(source='#implements dummy\n$bar')
+ t = klass3({'foo':1234})
+ assert str(t)=='1234'
+
+
+class Preprocessors(TemplateTest):
+
+ def test_basicUsage1(self):
+ src='''\
+ %set foo = @a
+ $(@foo*10)
+ @a'''
+ src = '\n'.join([ln.strip() for ln in src.splitlines()])
+ preprocessors = {'tokens':'@ %',
+ 'namespaces':{'a':99}
+ }
+ klass = Template.compile(src, preprocessors=preprocessors)
+ assert str(klass())=='990\n99'
+
+ def test_normalizePreprocessorArgVariants(self):
+ src='%set foo = 12\n%%comment\n$(@foo*10)'
+
+ class Settings1: tokens = '@ %'
+ Settings1 = Settings1()
+
+ from Cheetah.Template import TemplatePreprocessor
+ settings = Template._normalizePreprocessorSettings(Settings1)
+ preprocObj = TemplatePreprocessor(settings)
+
+ def preprocFunc(source, file):
+ return '$(12*10)', None
+
+ class TemplateSubclass(Template):
+ pass
+
+ compilerSettings = {'cheetahVarStartToken':'@',
+ 'directiveStartToken':'%',
+ 'commentStartToken':'%%',
+ }
+
+ for arg in ['@ %',
+ {'tokens':'@ %'},
+ {'compilerSettings':compilerSettings},
+ {'compilerSettings':compilerSettings,
+ 'templateInitArgs':{}},
+ {'tokens':'@ %',
+ 'templateAPIClass':TemplateSubclass},
+ Settings1,
+ preprocObj,
+ preprocFunc,
+ ]:
+
+ klass = Template.compile(src, preprocessors=arg)
+ assert str(klass())=='120'
+
+
+ def test_complexUsage(self):
+ src='''\
+ %set foo = @a
+ %def func1: #def func(arg): $arg("***")
+ %% comment
+ $(@foo*10)
+ @func1
+ $func(lambda x:c"--$x-- at a")'''
+ src = '\n'.join([ln.strip() for ln in src.splitlines()])
+
+
+ for arg in [{'tokens':'@ %', 'namespaces':{'a':99} },
+ {'tokens':'@ %', 'namespaces':{'a':99} },
+ ]:
+ klass = Template.compile(src, preprocessors=arg)
+ t = klass()
+ assert str(t)=='990\n--***--99'
+
+
+
+ def test_i18n(self):
+ src='''\
+ %i18n: This is a $string that needs translation
+ %i18n id="foo", domain="root": This is a $string that needs translation
+ '''
+ src = '\n'.join([ln.strip() for ln in src.splitlines()])
+ klass = Template.compile(src, preprocessors='@ %', baseclass=dict)
+ t = klass({'string':'bit of text'})
+ #print str(t), repr(str(t))
+ assert str(t)==('This is a bit of text that needs translation\n'*2)[:-1]
+
+
+class TryExceptImportTest(TemplateTest):
+ def test_FailCase(self):
+ ''' Test situation where an inline #import statement will get relocated '''
+ source = '''
+ #def myFunction()
+ Ahoy!
+ #try
+ #import sys
+ #except ImportError
+ $print "This will never happen!"
+ #end try
+ #end def
+ '''
+ # This should raise an IndentationError (if the bug exists)
+ klass = Template.compile(source=source, compilerSettings={'useLegacyImportMode' : False})
+ t = klass(namespaces={'foo' : 1234})
+
+class ClassMethodSupport(TemplateTest):
+ def test_BasicDecorator(self):
+ if sys.version_info[0] == 2 and sys.version_info[1] == 3:
+ print 'This version of Python doesn\'t support decorators, skipping tests'
+ return
+ template = '''
+ #@classmethod
+ #def myClassMethod()
+ #return '$foo = %s' % $foo
+ #end def
+ '''
+ template = Template.compile(source=template)
+ try:
+ rc = template.myClassMethod(foo='bar')
+ assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected')
+ except AttributeError, ex:
+ self.fail(ex)
+
+class StaticMethodSupport(TemplateTest):
+ def test_BasicDecorator(self):
+ if sys.version_info[0] == 2 and sys.version_info[1] == 3:
+ print 'This version of Python doesn\'t support decorators, skipping tests'
+ return
+ template = '''
+ #@staticmethod
+ #def myStaticMethod()
+ #return '$foo = %s' % $foo
+ #end def
+ '''
+ template = Template.compile(source=template)
+ try:
+ rc = template.myStaticMethod(foo='bar')
+ assert rc == '$foo = bar', (rc, 'Template class method didn\'t return what I expected')
+ except AttributeError, ex:
+ self.fail(ex)
+
+
+
+
+##################################################
+## if run from the command line ##
+
+if __name__ == '__main__':
+ unittest.main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Test.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Test.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Test.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+'''
+Core module of Cheetah's Unit-testing framework
+
+TODO
+================================================================================
+# combo tests
+# negative test cases for expected exceptions
+# black-box vs clear-box testing
+# do some tests that run the Template for long enough to check that the refresh code works
+'''
+
+import sys
+import unittest_local_copy as unittest
+
+
+
+import SyntaxAndOutput
+import NameMapper
+import Template
+import CheetahWrapper
+import Regressions
+import Unicode
+
+suites = [
+ unittest.findTestCases(SyntaxAndOutput),
+ unittest.findTestCases(NameMapper),
+ unittest.findTestCases(Template),
+ unittest.findTestCases(Regressions),
+ unittest.findTestCases(Unicode),
+]
+
+if not sys.platform.startswith('java'):
+ suites.append(unittest.findTestCases(CheetahWrapper))
+
+if __name__ == '__main__':
+ runner = unittest.TextTestRunner()
+ if 'xml' in sys.argv:
+ import xmlrunner
+ runner = xmlrunner.XMLTestRunner(filename='Cheetah-Tests.xml')
+
+ results = runner.run(unittest.TestSuite(suites))
+
+
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Unicode.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Unicode.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/Unicode.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# -*- encoding: utf8 -*-
+
+from Cheetah.Template import Template
+from Cheetah import CheetahWrapper
+from Cheetah import DummyTransaction
+import imp
+import os
+import pdb
+import random
+import sys
+import tempfile
+import unittest_local_copy as unittest # This is stupid
+
+class CommandLineTest(unittest.TestCase):
+ def createAndCompile(self, source):
+ sourcefile = '-'
+ while sourcefile.find('-') != -1:
+ sourcefile = tempfile.mktemp()
+
+ fd = open('%s.tmpl' % sourcefile, 'w')
+ fd.write(source)
+ fd.close()
+
+ wrap = CheetahWrapper.CheetahWrapper()
+ wrap.main(['cheetah', 'compile', '--nobackup', sourcefile])
+ module_name = os.path.basename(sourcefile)
+ module = loadModule(module_name, ['/tmp'])
+ template = getattr(module, module_name)
+ return template
+
+class JBQ_UTF8_Test1(unittest.TestCase):
+ def runTest(self):
+ t = Template.compile(source="""Main file with |$v|
+
+ $other""")
+
+ otherT = Template.compile(source="Other template with |$v|")
+ other = otherT()
+ t.other = other
+
+ t.v = u'Unicode String'
+ t.other.v = u'Unicode String'
+
+ assert unicode(t())
+
+class JBQ_UTF8_Test2(unittest.TestCase):
+ def runTest(self):
+ t = Template.compile(source="""Main file with |$v|
+
+ $other""")
+
+ otherT = Template.compile(source="Other template with |$v|")
+ other = otherT()
+ t.other = other
+
+ t.v = u'Unicode String with eacute é'
+ t.other.v = u'Unicode String'
+
+ assert unicode(t())
+
+
+class JBQ_UTF8_Test3(unittest.TestCase):
+ def runTest(self):
+ t = Template.compile(source="""Main file with |$v|
+
+ $other""")
+
+ otherT = Template.compile(source="Other template with |$v|")
+ other = otherT()
+ t.other = other
+
+ t.v = u'Unicode String with eacute é'
+ t.other.v = u'Unicode String and an eacute é'
+
+ assert unicode(t())
+
+class JBQ_UTF8_Test4(unittest.TestCase):
+ def runTest(self):
+ t = Template.compile(source="""#encoding utf-8
+ Main file with |$v| and eacute in the template é""")
+
+ t.v = 'Unicode String'
+
+ assert unicode(t())
+
+class JBQ_UTF8_Test5(unittest.TestCase):
+ def runTest(self):
+ t = Template.compile(source="""#encoding utf-8
+ Main file with |$v| and eacute in the template é""")
+
+ t.v = u'Unicode String'
+
+ assert unicode(t())
+
+def loadModule(moduleName, path=None):
+ if path:
+ assert isinstance(path, list)
+ try:
+ mod = sys.modules[moduleName]
+ except KeyError:
+ fp = None
+
+ try:
+ fp, pathname, description = imp.find_module(moduleName, path)
+ mod = imp.load_module(moduleName, fp, pathname, description)
+ finally:
+ if fp:
+ fp.close()
+ return mod
+
+class JBQ_UTF8_Test6(unittest.TestCase):
+ def runTest(self):
+ source = """#encoding utf-8
+ #set $someUnicodeString = u"Bébé"
+ Main file with |$v| and eacute in the template é"""
+ t = Template.compile(source=source)
+
+ t.v = u'Unicode String'
+
+ assert unicode(t())
+
+class JBQ_UTF8_Test7(CommandLineTest):
+ def runTest(self):
+ source = """#encoding utf-8
+ #set $someUnicodeString = u"Bébé"
+ Main file with |$v| and eacute in the template é"""
+
+ template = self.createAndCompile(source)
+ template.v = u'Unicode String'
+
+ assert unicode(template())
+
+class Unicode_in_SearchList_Test(CommandLineTest):
+ def test_BasicASCII(self):
+ source = '''This is $adjective'''
+
+ template = self.createAndCompile(source)
+ assert template and issubclass(template, Template)
+ template = template(searchList=[{'adjective' : u'neat'}])
+ assert template.respond()
+
+ def test_Thai(self):
+ # The string is something in Thai
+ source = '''This is $foo $adjective'''
+ template = self.createAndCompile(source)
+ assert template and issubclass(template, Template)
+ template = template(searchList=[{'foo' : 'bar',
+ 'adjective' : u'\u0e22\u0e34\u0e19\u0e14\u0e35\u0e15\u0e49\u0e2d\u0e19\u0e23\u0e31\u0e1a'}])
+ assert template.respond()
+
+ def test_ErrorReporting(self):
+ utf8 = '\xe0\xb8\xa2\xe0\xb8\xb4\xe0\xb8\x99\xe0\xb8\x94\xe0\xb8\xb5\xe0\xb8\x95\xe0\xb9\x89\xe0\xb8\xad\xe0\xb8\x99\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x9a'
+
+ source = '''This is $adjective'''
+ template = self.createAndCompile(source)
+ assert template and issubclass(template, Template)
+ template = template(searchList=[{'adjective' : utf8}])
+ self.failUnlessRaises(DummyTransaction.DummyResponseFailure, template.respond)
+
+
+
+if __name__ == '__main__':
+ unittest.main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/unittest_local_copy.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/unittest_local_copy.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/unittest_local_copy.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,978 @@
+#!/usr/bin/env python
+""" This is a hacked version of PyUnit that extends its reporting capabilities
+with optional meta data on the test cases. It also makes it possible to
+separate the standard and error output streams in TextTestRunner.
+
+It's a hack rather than a set of subclasses because a) Steve had used double
+underscore private attributes for some things I needed access to, and b) the
+changes affected so many classes that it was easier just to hack it.
+
+The changes are in the following places:
+TestCase:
+ - minor refactoring of __init__ and __call__ internals
+ - added some attributes and methods for storing and retrieving meta data
+
+_TextTestResult
+ - refactored the stream handling
+ - incorporated all the output code from TextTestRunner
+ - made the output of FAIL and ERROR information more flexible and
+ incorporated the new meta data from TestCase
+ - added a flag called 'explain' to __init__ that controls whether the new '
+ explanation' meta data from TestCase is printed along with tracebacks
+
+TextTestRunner
+ - delegated all output to _TextTestResult
+ - added 'err' and 'explain' to the __init__ signature to match the changes
+ in _TextTestResult
+
+TestProgram
+ - added -e and --explain as flags on the command line
+
+-- Tavis Rudd <tavis at redonions.net> (Sept 28th, 2001)
+
+- _TestTextResult.printErrorList(): print blank line after each traceback
+
+-- Mike Orr <mso at oz.net> (Nov 11, 2002)
+
+TestCase methods copied from unittest in Python 2.3:
+ - .assertAlmostEqual(first, second, places=7, msg=None): to N decimal places.
+ - .failIfAlmostEqual(first, second, places=7, msg=None)
+
+-- Mike Orr (Jan 5, 2004)
+
+
+Below is the original docstring for unittest.
+---------------------------------------------------------------------------
+Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
+Smalltalk testing framework.
+
+This module contains the core framework classes that form the basis of
+specific test cases and suites (TestCase, TestSuite etc.), and also a
+text-based utility class for running the tests and reporting the results
+(TextTestRunner).
+
+Simple usage:
+
+ import unittest
+
+ class IntegerArithmenticTestCase(unittest.TestCase):
+ def testAdd(self): ## test method names begin 'test*'
+ self.assertEquals((1 + 2), 3)
+ self.assertEquals(0 + 1, 1)
+ def testMultiply(self);
+ self.assertEquals((0 * 10), 0)
+ self.assertEquals((5 * 8), 40)
+
+ if __name__ == '__main__':
+ unittest.main()
+
+Further information is available in the bundled documentation, and from
+
+ http://pyunit.sourceforge.net/
+
+Copyright (c) 1999, 2000, 2001 Steve Purcell
+This module is free software, and you may redistribute it and/or modify
+it under the same terms as Python itself, so long as this copyright message
+and disclaimer are retained in their original form.
+
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+"""
+
+__author__ = "Steve Purcell"
+__email__ = "stephen_purcell at yahoo dot com"
+__revision__ = "$Revision: 1.11 $"[11:-2]
+
+
+##################################################
+## DEPENDENCIES ##
+
+import os
+import re
+import string
+import sys
+import time
+import traceback
+import types
+import pprint
+
+##################################################
+## CONSTANTS & GLOBALS
+
+try:
+ True,False
+except NameError:
+ True, False = (1==1),(1==0)
+
+##############################################################################
+# Test framework core
+##############################################################################
+
+
+class TestResult:
+ """Holder for test result information.
+
+ Test results are automatically managed by the TestCase and TestSuite
+ classes, and do not need to be explicitly manipulated by writers of tests.
+
+ Each instance holds the total number of tests run, and collections of
+ failures and errors that occurred among those test runs. The collections
+ contain tuples of (testcase, exceptioninfo), where exceptioninfo is a
+ tuple of values as returned by sys.exc_info().
+ """
+ def __init__(self):
+ self.failures = []
+ self.errors = []
+ self.testsRun = 0
+ self.shouldStop = 0
+
+ def startTest(self, test):
+ "Called when the given test is about to be run"
+ self.testsRun = self.testsRun + 1
+
+ def stopTest(self, test):
+ "Called when the given test has been run"
+ pass
+
+ def addError(self, test, err):
+ "Called when an error has occurred"
+ self.errors.append((test, err))
+
+ def addFailure(self, test, err):
+ "Called when a failure has occurred"
+ self.failures.append((test, err))
+
+ def addSuccess(self, test):
+ "Called when a test has completed successfully"
+ pass
+
+ def wasSuccessful(self):
+ "Tells whether or not this result was a success"
+ return len(self.failures) == len(self.errors) == 0
+
+ def stop(self):
+ "Indicates that the tests should be aborted"
+ self.shouldStop = 1
+
+ def __repr__(self):
+ return "<%s run=%i errors=%i failures=%i>" % \
+ (self.__class__, self.testsRun, len(self.errors),
+ len(self.failures))
+
+class TestCase:
+ """A class whose instances are single test cases.
+
+ By default, the test code itself should be placed in a method named
+ 'runTest'.
+
+ If the fixture may be used for many test cases, create as
+ many test methods as are needed. When instantiating such a TestCase
+ subclass, specify in the constructor arguments the name of the test method
+ that the instance is to execute.
+
+ Test authors should subclass TestCase for their own tests. Construction
+ and deconstruction of the test's environment ('fixture') can be
+ implemented by overriding the 'setUp' and 'tearDown' methods respectively.
+
+ If it is necessary to override the __init__ method, the base class
+ __init__ method must always be called. It is important that subclasses
+ should not change the signature of their __init__ method, since instances
+ of the classes are instantiated automatically by parts of the framework
+ in order to be run.
+ """
+
+ # This attribute determines which exception will be raised when
+ # the instance's assertion methods fail; test methods raising this
+ # exception will be deemed to have 'failed' rather than 'errored'
+
+ failureException = AssertionError
+
+ # the name of the fixture. Used for displaying meta data about the test
+ name = None
+
+ def __init__(self, methodName='runTest'):
+ """Create an instance of the class that will use the named test
+ method when executed. Raises a ValueError if the instance does
+ not have a method with the specified name.
+ """
+ self._testMethodName = methodName
+ self._setupTestMethod()
+ self._setupMetaData()
+
+ def _setupTestMethod(self):
+ try:
+ self._testMethod = getattr(self, self._testMethodName)
+ except AttributeError:
+ raise ValueError, "no such test method in %s: %s" % \
+ (self.__class__, self._testMethodName)
+
+ ## meta data methods
+
+ def _setupMetaData(self):
+ """Setup the default meta data for the test case:
+
+ - id: self.__class__.__name__ + testMethodName OR self.name + testMethodName
+ - description: 1st line of Class docstring + 1st line of method docstring
+ - explanation: rest of Class docstring + rest of method docstring
+
+ """
+
+
+ testDoc = self._testMethod.__doc__ or '\n'
+ testDocLines = testDoc.splitlines()
+
+ testDescription = testDocLines[0].strip()
+ if len(testDocLines) > 1:
+ testExplanation = '\n'.join(
+ [ln.strip() for ln in testDocLines[1:]]
+ ).strip()
+ else:
+ testExplanation = ''
+
+ fixtureDoc = self.__doc__ or '\n'
+ fixtureDocLines = fixtureDoc.splitlines()
+ fixtureDescription = fixtureDocLines[0].strip()
+ if len(fixtureDocLines) > 1:
+ fixtureExplanation = '\n'.join(
+ [ln.strip() for ln in fixtureDocLines[1:]]
+ ).strip()
+ else:
+ fixtureExplanation = ''
+
+ if not self.name:
+ self.name = self.__class__
+ self._id = "%s.%s" % (self.name, self._testMethodName)
+
+ if not fixtureDescription:
+ self._description = testDescription
+ else:
+ self._description = fixtureDescription + ', ' + testDescription
+
+ if not fixtureExplanation:
+ self._explanation = testExplanation
+ else:
+ self._explanation = ['Fixture Explanation:',
+ '--------------------',
+ fixtureExplanation,
+ '',
+ 'Test Explanation:',
+ '-----------------',
+ testExplanation
+ ]
+ self._explanation = '\n'.join(self._explanation)
+
+ def id(self):
+ return self._id
+
+ def setId(self, id):
+ self._id = id
+
+ def describe(self):
+ """Returns a one-line description of the test, or None if no
+ description has been provided.
+
+ The default implementation of this method returns the first line of
+ the specified test method's docstring.
+ """
+ return self._description
+
+ shortDescription = describe
+
+ def setDescription(self, descr):
+ self._description = descr
+
+ def explain(self):
+ return self._explanation
+
+ def setExplanation(self, expln):
+ self._explanation = expln
+
+ ## core methods
+
+ def setUp(self):
+ "Hook method for setting up the test fixture before exercising it."
+ pass
+
+ def run(self, result=None):
+ return self(result)
+
+ def tearDown(self):
+ "Hook method for deconstructing the test fixture after testing it."
+ pass
+
+ def debug(self):
+ """Run the test without collecting errors in a TestResult"""
+ self.setUp()
+ self._testMethod()
+ self.tearDown()
+
+ ## internal methods
+
+ def defaultTestResult(self):
+ return TestResult()
+
+ def __call__(self, result=None):
+ if result is None:
+ result = self.defaultTestResult()
+
+ result.startTest(self)
+ try:
+ try:
+ self.setUp()
+ except:
+ result.addError(self, self.__exc_info())
+ return
+
+ ok = 0
+ try:
+ self._testMethod()
+ ok = 1
+ except self.failureException, e:
+ result.addFailure(self, self.__exc_info())
+ except:
+ result.addError(self, self.__exc_info())
+ try:
+ self.tearDown()
+ except:
+ result.addError(self, self.__exc_info())
+ ok = 0
+ if ok:
+ result.addSuccess(self)
+ finally:
+ result.stopTest(self)
+
+ return result
+
+ def countTestCases(self):
+ return 1
+
+ def __str__(self):
+ return "%s (%s)" % (self._testMethodName, self.__class__)
+
+ def __repr__(self):
+ return "<%s testMethod=%s>" % \
+ (self.__class__, self._testMethodName)
+
+ def __exc_info(self):
+ """Return a version of sys.exc_info() with the traceback frame
+ minimised; usually the top level of the traceback frame is not
+ needed.
+ """
+ exctype, excvalue, tb = sys.exc_info()
+ if sys.platform[:4] == 'java': ## tracebacks look different in Jython
+ return (exctype, excvalue, tb)
+ newtb = tb.tb_next
+ if newtb is None:
+ return (exctype, excvalue, tb)
+ return (exctype, excvalue, newtb)
+
+ ## methods for use by the test cases
+
+ def fail(self, msg=None):
+ """Fail immediately, with the given message."""
+ raise self.failureException, msg
+
+ def failIf(self, expr, msg=None):
+ "Fail the test if the expression is true."
+ if expr: raise self.failureException, msg
+
+ def failUnless(self, expr, msg=None):
+ """Fail the test unless the expression is true."""
+ if not expr: raise self.failureException, msg
+
+ def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
+ """Fail unless an exception of class excClass is thrown
+ by callableObj when invoked with arguments args and keyword
+ arguments kwargs. If a different type of exception is
+ thrown, it will not be caught, and the test case will be
+ deemed to have suffered an error, exactly as for an
+ unexpected exception.
+ """
+ try:
+ apply(callableObj, args, kwargs)
+ except excClass:
+ return
+ else:
+ if hasattr(excClass,'__name__'): excName = excClass.__name__
+ else: excName = str(excClass)
+ raise self.failureException, excName
+
+ def failUnlessEqual(self, first, second, msg=None):
+ """Fail if the two objects are unequal as determined by the '!='
+ operator.
+ """
+ if first != second:
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+
+ def failIfEqual(self, first, second, msg=None):
+ """Fail if the two objects are equal as determined by the '=='
+ operator.
+ """
+ if first == second:
+ raise self.failureException, (msg or '%s == %s' % (first, second))
+
+ def failUnlessAlmostEqual(self, first, second, places=7, msg=None):
+ """Fail if the two objects are unequal as determined by their
+ difference rounded to the given number of decimal places
+ (default 7) and comparing to zero.
+
+ Note that decimal places (from zero) is usually not the same
+ as significant digits (measured from the most signficant digit).
+ """
+ if round(second-first, places) != 0:
+ raise self.failureException, \
+ (msg or '%s != %s within %s places' % (`first`, `second`, `places` ))
+
+ def failIfAlmostEqual(self, first, second, places=7, msg=None):
+ """Fail if the two objects are equal as determined by their
+ difference rounded to the given number of decimal places
+ (default 7) and comparing to zero.
+
+ Note that decimal places (from zero) is usually not the same
+ as significant digits (measured from the most signficant digit).
+ """
+ if round(second-first, places) == 0:
+ raise self.failureException, \
+ (msg or '%s == %s within %s places' % (`first`, `second`, `places`))
+
+ ## aliases
+
+ assertEqual = assertEquals = failUnlessEqual
+
+ assertNotEqual = assertNotEquals = failIfEqual
+
+ assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual
+
+ assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual
+
+ assertRaises = failUnlessRaises
+
+ assert_ = failUnless
+
+
+class FunctionTestCase(TestCase):
+ """A test case that wraps a test function.
+
+ This is useful for slipping pre-existing test functions into the
+ PyUnit framework. Optionally, set-up and tidy-up functions can be
+ supplied. As with TestCase, the tidy-up ('tearDown') function will
+ always be called if the set-up ('setUp') function ran successfully.
+ """
+
+ def __init__(self, testFunc, setUp=None, tearDown=None,
+ description=None):
+ TestCase.__init__(self)
+ self.__setUpFunc = setUp
+ self.__tearDownFunc = tearDown
+ self.__testFunc = testFunc
+ self.__description = description
+
+ def setUp(self):
+ if self.__setUpFunc is not None:
+ self.__setUpFunc()
+
+ def tearDown(self):
+ if self.__tearDownFunc is not None:
+ self.__tearDownFunc()
+
+ def runTest(self):
+ self.__testFunc()
+
+ def id(self):
+ return self.__testFunc.__name__
+
+ def __str__(self):
+ return "%s (%s)" % (self.__class__, self.__testFunc.__name__)
+
+ def __repr__(self):
+ return "<%s testFunc=%s>" % (self.__class__, self.__testFunc)
+
+
+ def describe(self):
+ if self.__description is not None: return self.__description
+ doc = self.__testFunc.__doc__
+ return doc and string.strip(string.split(doc, "\n")[0]) or None
+
+ ## aliases
+ shortDescription = describe
+
+class TestSuite:
+ """A test suite is a composite test consisting of a number of TestCases.
+
+ For use, create an instance of TestSuite, then add test case instances.
+ When all tests have been added, the suite can be passed to a test
+ runner, such as TextTestRunner. It will run the individual test cases
+ in the order in which they were added, aggregating the results. When
+ subclassing, do not forget to call the base class constructor.
+ """
+ def __init__(self, tests=(), suiteName=None):
+ self._tests = []
+ self._testMap = {}
+ self.suiteName = suiteName
+ self.addTests(tests)
+
+ def __repr__(self):
+ return "<%s tests=%s>" % (self.__class__, pprint.pformat(self._tests))
+
+ __str__ = __repr__
+
+ def countTestCases(self):
+ cases = 0
+ for test in self._tests:
+ cases = cases + test.countTestCases()
+ return cases
+
+ def addTest(self, test):
+ self._tests.append(test)
+ if isinstance(test, TestSuite) and test.suiteName:
+ name = test.suiteName
+ elif isinstance(test, TestCase):
+ #print test, test._testMethodName
+ name = test._testMethodName
+ else:
+ name = test.__class__.__name__
+ self._testMap[name] = test
+
+ def addTests(self, tests):
+ for test in tests:
+ self.addTest(test)
+
+ def getTestForName(self, name):
+ return self._testMap[name]
+
+ def run(self, result):
+ return self(result)
+
+ def __call__(self, result):
+ for test in self._tests:
+ if result.shouldStop:
+ break
+ test(result)
+ return result
+
+ def debug(self):
+ """Run the tests without collecting errors in a TestResult"""
+ for test in self._tests: test.debug()
+
+
+##############################################################################
+# Text UI
+##############################################################################
+
+class StreamWrapper:
+ def __init__(self, out=sys.stdout, err=sys.stderr):
+ self._streamOut = out
+ self._streamErr = err
+
+ def write(self, txt):
+ self._streamOut.write(txt)
+ self._streamOut.flush()
+
+ def writeln(self, *lines):
+ for line in lines:
+ self.write(line + '\n')
+ if not lines:
+ self.write('\n')
+
+ def writeErr(self, txt):
+ self._streamErr.write(txt)
+
+ def writelnErr(self, *lines):
+ for line in lines:
+ self.writeErr(line + '\n')
+ if not lines:
+ self.writeErr('\n')
+
+
+class _TextTestResult(TestResult, StreamWrapper):
+ _separatorWidth = 70
+ _sep1 = '='
+ _sep2 = '-'
+ _errorSep1 = '*'
+ _errorSep2 = '-'
+ _errorSep3 = ''
+
+ def __init__(self,
+ stream=sys.stdout,
+ errStream=sys.stderr,
+ verbosity=1,
+ explain=False):
+
+ TestResult.__init__(self)
+ StreamWrapper.__init__(self, out=stream, err=errStream)
+
+ self._verbosity = verbosity
+ self._showAll = verbosity > 1
+ self._dots = (verbosity == 1)
+ self._explain = explain
+
+ ## startup and shutdown methods
+
+ def beginTests(self):
+ self._startTime = time.time()
+
+ def endTests(self):
+ self._stopTime = time.time()
+ self._timeTaken = float(self._stopTime - self._startTime)
+
+ def stop(self):
+ self.shouldStop = 1
+
+ ## methods called for each test
+
+ def startTest(self, test):
+ TestResult.startTest(self, test)
+ if self._showAll:
+ self.write("%s (%s)" %( test.id(), test.describe() ) )
+ self.write(" ... ")
+
+ def addSuccess(self, test):
+ TestResult.addSuccess(self, test)
+ if self._showAll:
+ self.writeln("ok")
+ elif self._dots:
+ self.write('.')
+
+ def addError(self, test, err):
+ TestResult.addError(self, test, err)
+ if self._showAll:
+ self.writeln("ERROR")
+ elif self._dots:
+ self.write('E')
+ if err[0] is KeyboardInterrupt:
+ self.stop()
+
+ def addFailure(self, test, err):
+ TestResult.addFailure(self, test, err)
+ if self._showAll:
+ self.writeln("FAIL")
+ elif self._dots:
+ self.write('F')
+
+ ## display methods
+
+ def summarize(self):
+ self.printErrors()
+ self.writeSep2()
+ run = self.testsRun
+ self.writeln("Ran %d test%s in %.3fs" %
+ (run, run == 1 and "" or "s", self._timeTaken))
+ self.writeln()
+ if not self.wasSuccessful():
+ self.writeErr("FAILED (")
+ failed, errored = map(len, (self.failures, self.errors))
+ if failed:
+ self.writeErr("failures=%d" % failed)
+ if errored:
+ if failed: self.writeErr(", ")
+ self.writeErr("errors=%d" % errored)
+ self.writelnErr(")")
+ else:
+ self.writelnErr("OK")
+
+ def writeSep1(self):
+ self.writeln(self._sep1 * self._separatorWidth)
+
+ def writeSep2(self):
+ self.writeln(self._sep2 * self._separatorWidth)
+
+ def writeErrSep1(self):
+ self.writeln(self._errorSep1 * self._separatorWidth)
+
+ def writeErrSep2(self):
+ self.writeln(self._errorSep2 * self._separatorWidth)
+
+ def printErrors(self):
+ if self._dots or self._showAll:
+ self.writeln()
+ self.printErrorList('ERROR', self.errors)
+ self.printErrorList('FAIL', self.failures)
+
+ def printErrorList(self, flavour, errors):
+ for test, err in errors:
+ self.writeErrSep1()
+ self.writelnErr("%s %s (%s)" % (flavour, test.id(), test.describe() ))
+ if self._explain:
+ expln = test.explain()
+ if expln:
+ self.writeErrSep2()
+ self.writeErr( expln )
+ self.writelnErr()
+
+ self.writeErrSep2()
+ for line in apply(traceback.format_exception, err):
+ for l in line.split("\n")[:-1]:
+ self.writelnErr(l)
+ self.writelnErr("")
+
+class TextTestRunner:
+ def __init__(self,
+ stream=sys.stdout,
+ errStream=sys.stderr,
+ verbosity=1,
+ explain=False):
+
+ self._out = stream
+ self._err = errStream
+ self._verbosity = verbosity
+ self._explain = explain
+
+ ## main methods
+
+ def run(self, test):
+ result = self._makeResult()
+ result.beginTests()
+ test( result )
+ result.endTests()
+ result.summarize()
+
+ return result
+
+ ## internal methods
+
+ def _makeResult(self):
+ return _TextTestResult(stream=self._out,
+ errStream=self._err,
+ verbosity=self._verbosity,
+ explain=self._explain,
+ )
+
+##############################################################################
+# Locating and loading tests
+##############################################################################
+
+class TestLoader:
+ """This class is responsible for loading tests according to various
+ criteria and returning them wrapped in a Test
+ """
+ testMethodPrefix = 'test'
+ sortTestMethodsUsing = cmp
+ suiteClass = TestSuite
+
+ def loadTestsFromTestCase(self, testCaseClass):
+ """Return a suite of all tests cases contained in testCaseClass"""
+ return self.suiteClass(tests=map(testCaseClass,
+ self.getTestCaseNames(testCaseClass)),
+ suiteName=testCaseClass.__name__)
+
+ def loadTestsFromModule(self, module):
+ """Return a suite of all tests cases contained in the given module"""
+ tests = []
+ for name in dir(module):
+ obj = getattr(module, name)
+ if type(obj) == types.ClassType and issubclass(obj, TestCase):
+ tests.append(self.loadTestsFromTestCase(obj))
+ return self.suiteClass(tests)
+
+ def loadTestsFromName(self, name, module=None):
+ """Return a suite of all tests cases given a string specifier.
+
+ The name may resolve either to a module, a test case class, a
+ test method within a test case class, or a callable object which
+ returns a TestCase or TestSuite instance.
+
+ The method optionally resolves the names relative to a given module.
+ """
+ parts = string.split(name, '.')
+ if module is None:
+ if not parts:
+ raise ValueError, "incomplete test name: %s" % name
+ else:
+ parts_copy = parts[:]
+ while parts_copy:
+ try:
+ module = __import__(string.join(parts_copy,'.'))
+ break
+ except ImportError:
+ del parts_copy[-1]
+ if not parts_copy: raise
+ parts = parts[1:]
+ obj = module
+ for part in parts:
+ if isinstance(obj, TestSuite):
+ obj = obj.getTestForName(part)
+ else:
+ obj = getattr(obj, part)
+
+ if type(obj) == types.ModuleType:
+ return self.loadTestsFromModule(obj)
+ elif type(obj) == types.ClassType and issubclass(obj, TestCase):
+ return self.loadTestsFromTestCase(obj)
+ elif type(obj) == types.UnboundMethodType:
+ return obj.im_class(obj.__name__)
+ elif isinstance(obj, TestSuite):
+ return obj
+ elif isinstance(obj, TestCase):
+ return obj
+ elif callable(obj):
+ test = obj()
+ if not isinstance(test, TestCase) and \
+ not isinstance(test, TestSuite):
+ raise ValueError, \
+ "calling %s returned %s, not a test" %(obj,test)
+ return test
+ else:
+ raise ValueError, "don't know how to make test from: %s" % obj
+
+ def loadTestsFromNames(self, names, module=None):
+ """Return a suite of all tests cases found using the given sequence
+ of string specifiers. See 'loadTestsFromName()'.
+ """
+ suites = []
+ for name in names:
+ suites.append(self.loadTestsFromName(name, module))
+ return self.suiteClass(suites)
+
+ def getTestCaseNames(self, testCaseClass):
+ """Return a sorted sequence of method names found within testCaseClass.
+ """
+ testFnNames = [fn for fn in dir(testCaseClass) if fn.startswith(self.testMethodPrefix)]
+ if hasattr(testCaseClass, 'runTest'):
+ testFnNames.append('runTest')
+ for baseclass in testCaseClass.__bases__:
+ for testFnName in self.getTestCaseNames(baseclass):
+ if testFnName not in testFnNames: # handle overridden methods
+ testFnNames.append(testFnName)
+ if self.sortTestMethodsUsing:
+ testFnNames.sort(self.sortTestMethodsUsing)
+ return testFnNames
+
+
+
+defaultTestLoader = TestLoader()
+
+
+##############################################################################
+# Patches for old functions: these functions should be considered obsolete
+##############################################################################
+
+def _makeLoader(prefix, sortUsing, suiteClass=None):
+ loader = TestLoader()
+ loader.sortTestMethodsUsing = sortUsing
+ loader.testMethodPrefix = prefix
+ if suiteClass: loader.suiteClass = suiteClass
+ return loader
+
+def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
+ return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
+
+def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
+
+def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
+ return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
+
+##############################################################################
+# Facilities for running tests from the command line
+##############################################################################
+
+class TestProgram:
+ """A command-line program that runs a set of tests; this is primarily
+ for making test modules conveniently executable.
+ """
+ USAGE = """\
+Usage: %(progName)s [options] [test] [...]
+
+Options:
+ -h, --help Show this message
+ -v, --verbose Verbose output
+ -q, --quiet Minimal output
+ -e, --expain Output extra test details if there is a failure or error
+
+Examples:
+ %(progName)s - run default set of tests
+ %(progName)s MyTestSuite - run suite 'MyTestSuite'
+ %(progName)s MyTestSuite.MyTestCase - run suite 'MyTestSuite'
+ %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
+ %(progName)s MyTestCase - run all 'test*' test methods
+ in MyTestCase
+"""
+ def __init__(self, module='__main__', defaultTest=None,
+ argv=None, testRunner=None, testLoader=defaultTestLoader,
+ testSuite=None):
+ if type(module) == type(''):
+ self.module = __import__(module)
+ for part in string.split(module,'.')[1:]:
+ self.module = getattr(self.module, part)
+ else:
+ self.module = module
+ if argv is None:
+ argv = sys.argv
+ self.test = testSuite
+ self.verbosity = 1
+ self.explain = 0
+ self.defaultTest = defaultTest
+ self.testRunner = testRunner
+ self.testLoader = testLoader
+ self.progName = os.path.basename(argv[0])
+ self.parseArgs(argv)
+ self.runTests()
+
+ def usageExit(self, msg=None):
+ if msg: print msg
+ print self.USAGE % self.__dict__
+ sys.exit(2)
+
+ def parseArgs(self, argv):
+ import getopt
+ try:
+ options, args = getopt.getopt(argv[1:], 'hHvqer',
+ ['help','verbose','quiet','explain', 'raise'])
+ for opt, value in options:
+ if opt in ('-h','-H','--help'):
+ self.usageExit()
+ if opt in ('-q','--quiet'):
+ self.verbosity = 0
+ if opt in ('-v','--verbose'):
+ self.verbosity = 2
+ if opt in ('-e','--explain'):
+ self.explain = True
+ if len(args) == 0 and self.defaultTest is None and self.test is None:
+ self.test = self.testLoader.loadTestsFromModule(self.module)
+ return
+ if len(args) > 0:
+ self.testNames = args
+ else:
+ self.testNames = (self.defaultTest,)
+ self.createTests()
+ except getopt.error, msg:
+ self.usageExit(msg)
+
+ def createTests(self):
+ if self.test == None:
+ self.test = self.testLoader.loadTestsFromNames(self.testNames,
+ self.module)
+
+ def runTests(self):
+ if self.testRunner is None:
+ self.testRunner = TextTestRunner(verbosity=self.verbosity,
+ explain=self.explain)
+ result = self.testRunner.run(self.test)
+ self._cleanupAfterRunningTests()
+ sys.exit(not result.wasSuccessful())
+
+ def _cleanupAfterRunningTests(self):
+ """A hook method that is called immediately prior to calling
+ sys.exit(not result.wasSuccessful()) in self.runTests().
+ """
+ pass
+
+main = TestProgram
+
+
+##############################################################################
+# Executing this module from the command line
+##############################################################################
+
+if __name__ == "__main__":
+ main(module=None)
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/xmlrunner.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/xmlrunner.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tests/xmlrunner.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,381 @@
+"""
+XML Test Runner for PyUnit
+"""
+
+# Written by Sebastian Rittau <srittau at jroger.in-berlin.de> and placed in
+# the Public Domain. With contributions by Paolo Borelli.
+
+__revision__ = "$Id: /private/python/stdlib/xmlrunner.py 16654 2007-11-12T12:46:35.368945Z srittau $"
+
+import os.path
+import re
+import sys
+import time
+import traceback
+import unittest
+from StringIO import StringIO
+from xml.sax.saxutils import escape
+
+from StringIO import StringIO
+
+
+
+class _TestInfo(object):
+
+ """Information about a particular test.
+
+ Used by _XMLTestResult.
+
+ """
+
+ def __init__(self, test, time):
+ _pieces = test.id().split('.')
+ (self._class, self._method) = ('.'.join(_pieces[:-1]), _pieces[-1])
+ self._time = time
+ self._error = None
+ self._failure = None
+
+
+ def print_report(self, stream):
+ """Print information about this test case in XML format to the
+ supplied stream.
+
+ """
+ stream.write(' <testcase classname="%(class)s" name="%(method)s" time="%(time).4f">' % \
+ {
+ "class": self._class,
+ "method": self._method,
+ "time": self._time,
+ })
+ if self._failure != None:
+ self._print_error(stream, 'failure', self._failure)
+ if self._error != None:
+ self._print_error(stream, 'error', self._error)
+ stream.write('</testcase>\n')
+
+ def _print_error(self, stream, tagname, error):
+ """Print information from a failure or error to the supplied stream."""
+ text = escape(str(error[1]))
+ stream.write('\n')
+ stream.write(' <%s type="%s">%s\n' \
+ % (tagname, issubclass(error[0], Exception) and error[0].__name__ or str(error[0]), text))
+ tb_stream = StringIO()
+ traceback.print_tb(error[2], None, tb_stream)
+ stream.write(escape(tb_stream.getvalue()))
+ stream.write(' </%s>\n' % tagname)
+ stream.write(' ')
+
+# Module level functions since Python 2.3 doesn't grok decorators
+def create_success(test, time):
+ """Create a _TestInfo instance for a successful test."""
+ return _TestInfo(test, time)
+
+def create_failure(test, time, failure):
+ """Create a _TestInfo instance for a failed test."""
+ info = _TestInfo(test, time)
+ info._failure = failure
+ return info
+
+def create_error(test, time, error):
+ """Create a _TestInfo instance for an erroneous test."""
+ info = _TestInfo(test, time)
+ info._error = error
+ return info
+
+class _XMLTestResult(unittest.TestResult):
+
+ """A test result class that stores result as XML.
+
+ Used by XMLTestRunner.
+
+ """
+
+ def __init__(self, classname):
+ unittest.TestResult.__init__(self)
+ self._test_name = classname
+ self._start_time = None
+ self._tests = []
+ self._error = None
+ self._failure = None
+
+ def startTest(self, test):
+ unittest.TestResult.startTest(self, test)
+ self._error = None
+ self._failure = None
+ self._start_time = time.time()
+
+ def stopTest(self, test):
+ time_taken = time.time() - self._start_time
+ unittest.TestResult.stopTest(self, test)
+ if self._error:
+ info = create_error(test, time_taken, self._error)
+ elif self._failure:
+ info = create_failure(test, time_taken, self._failure)
+ else:
+ info = create_success(test, time_taken)
+ self._tests.append(info)
+
+ def addError(self, test, err):
+ unittest.TestResult.addError(self, test, err)
+ self._error = err
+
+ def addFailure(self, test, err):
+ unittest.TestResult.addFailure(self, test, err)
+ self._failure = err
+
+ def print_report(self, stream, time_taken, out, err):
+ """Prints the XML report to the supplied stream.
+
+ The time the tests took to perform as well as the captured standard
+ output and standard error streams must be passed in.a
+
+ """
+ stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' % \
+ { "e": len(self.errors), "f": len(self.failures) })
+ stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % \
+ {
+ "n": self._test_name,
+ "t": self.testsRun,
+ "time": time_taken,
+ })
+ for info in self._tests:
+ info.print_report(stream)
+ stream.write(' <system-out><![CDATA[%s]]></system-out>\n' % out)
+ stream.write(' <system-err><![CDATA[%s]]></system-err>\n' % err)
+ stream.write('</testsuite>\n')
+
+
+class XMLTestRunner(object):
+
+ """A test runner that stores results in XML format compatible with JUnit.
+
+ XMLTestRunner(stream=None) -> XML test runner
+
+ The XML file is written to the supplied stream. If stream is None, the
+ results are stored in a file called TEST-<module>.<class>.xml in the
+ current working directory (if not overridden with the path property),
+ where <module> and <class> are the module and class name of the test class.
+
+ """
+
+ def __init__(self, *args, **kwargs):
+ self._stream = kwargs.get('stream')
+ self._filename = kwargs.get('filename')
+ self._path = "."
+
+ def run(self, test):
+ """Run the given test case or test suite."""
+ class_ = test.__class__
+ classname = class_.__module__ + "." + class_.__name__
+ if self._stream == None:
+ filename = "TEST-%s.xml" % classname
+ if self._filename:
+ filename = self._filename
+ stream = file(os.path.join(self._path, filename), "w")
+ stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
+ else:
+ stream = self._stream
+
+ result = _XMLTestResult(classname)
+ start_time = time.time()
+
+ # TODO: Python 2.5: Use the with statement
+ old_stdout = sys.stdout
+ old_stderr = sys.stderr
+ sys.stdout = StringIO()
+ sys.stderr = StringIO()
+
+ try:
+ test(result)
+ try:
+ out_s = sys.stdout.getvalue()
+ except AttributeError:
+ out_s = ""
+ try:
+ err_s = sys.stderr.getvalue()
+ except AttributeError:
+ err_s = ""
+ finally:
+ sys.stdout = old_stdout
+ sys.stderr = old_stderr
+
+ time_taken = time.time() - start_time
+ result.print_report(stream, time_taken, out_s, err_s)
+ if self._stream == None:
+ stream.close()
+
+ return result
+
+ def _set_path(self, path):
+ self._path = path
+
+ path = property(lambda self: self._path, _set_path, None,
+ """The path where the XML files are stored.
+
+ This property is ignored when the XML file is written to a file
+ stream.""")
+
+
+class XMLTestRunnerTest(unittest.TestCase):
+ def setUp(self):
+ self._stream = StringIO()
+
+ def _try_test_run(self, test_class, expected):
+
+ """Run the test suite against the supplied test class and compare the
+ XML result against the expected XML string. Fail if the expected
+ string doesn't match the actual string. All time attribute in the
+ expected string should have the value "0.000". All error and failure
+ messages are reduced to "Foobar".
+
+ """
+
+ runner = XMLTestRunner(self._stream)
+ runner.run(unittest.makeSuite(test_class))
+
+ got = self._stream.getvalue()
+ # Replace all time="X.YYY" attributes by time="0.000" to enable a
+ # simple string comparison.
+ got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
+ # Likewise, replace all failure and error messages by a simple "Foobar"
+ # string.
+ got = re.sub(r'(?s)<failure (.*?)>.*?</failure>', r'<failure \1>Foobar</failure>', got)
+ got = re.sub(r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
+
+ self.assertEqual(expected, got)
+
+ def test_no_tests(self):
+ """Regression test: Check whether a test run without any tests
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ pass
+ self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
+ <system-out><![CDATA[]]></system-out>
+ <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+ def test_success(self):
+ """Regression test: Check whether a test run with a successful test
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ pass
+ self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+ <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+ <system-out><![CDATA[]]></system-out>
+ <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+ def test_failure(self):
+ """Regression test: Check whether a test run with a failing test
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ self.assert_(False)
+ self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
+ <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+ <failure type="exceptions.AssertionError">Foobar</failure>
+ </testcase>
+ <system-out><![CDATA[]]></system-out>
+ <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+ def test_error(self):
+ """Regression test: Check whether a test run with a erroneous test
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ raise IndexError()
+ self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+ <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+ <error type="exceptions.IndexError">Foobar</error>
+ </testcase>
+ <system-out><![CDATA[]]></system-out>
+ <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+ def test_stdout_capture(self):
+ """Regression test: Check whether a test run with output to stdout
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ print "Test"
+ self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+ <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+ <system-out><![CDATA[Test
+]]></system-out>
+ <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+ def test_stderr_capture(self):
+ """Regression test: Check whether a test run with output to stderr
+ matches a previous run.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ print >>sys.stderr, "Test"
+ self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+ <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+ <system-out><![CDATA[]]></system-out>
+ <system-err><![CDATA[Test
+]]></system-err>
+</testsuite>
+""")
+
+ class NullStream(object):
+ """A file-like object that discards everything written to it."""
+ def write(self, buffer):
+ pass
+
+ def test_unittests_changing_stdout(self):
+ """Check whether the XMLTestRunner recovers gracefully from unit tests
+ that change stdout, but don't change it back properly.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ sys.stdout = XMLTestRunnerTest.NullStream()
+
+ runner = XMLTestRunner(self._stream)
+ runner.run(unittest.makeSuite(TestTest))
+
+ def test_unittests_changing_stderr(self):
+ """Check whether the XMLTestRunner recovers gracefully from unit tests
+ that change stderr, but don't change it back properly.
+
+ """
+ class TestTest(unittest.TestCase):
+ def test_foo(self):
+ sys.stderr = XMLTestRunnerTest.NullStream()
+
+ runner = XMLTestRunner(self._stream)
+ runner.run(unittest.makeSuite(TestTest))
+
+
+class XMLTestProgram(unittest.TestProgram):
+ def runTests(self):
+ if self.testRunner is None:
+ self.testRunner = XMLTestRunner()
+ unittest.TestProgram.runTests(self)
+
+main = XMLTestProgram
+
+
+if __name__ == "__main__":
+ main(module=None)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/CGITemplate.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/CGITemplate.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/CGITemplate.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# $Id: CGITemplate.py,v 1.6 2006/01/29 02:09:59 tavis_rudd Exp $
+"""A subclass of Cheetah.Template for use in CGI scripts.
+
+Usage in a template:
+ #extends Cheetah.Tools.CGITemplate
+ #implements respond
+ $cgiHeaders#slurp
+
+Usage in a template inheriting a Python class:
+1. The template
+ #extends MyPythonClass
+ #implements respond
+ $cgiHeaders#slurp
+
+2. The Python class
+ from Cheetah.Tools import CGITemplate
+ class MyPythonClass(CGITemplate):
+ def cgiHeadersHook(self):
+ return "Content-Type: text/html; charset=koi8-r\n\n"
+
+To read GET/POST variables, use the .webInput method defined in
+Cheetah.Utils.WebInputMixin (available in all templates without importing
+anything), use Python's 'cgi' module, or make your own arrangements.
+
+This class inherits from Cheetah.Template to make it usable in Cheetah's
+single-inheritance model.
+
+
+Meta-Data
+================================================================================
+Author: Mike Orr <iron at mso.oz.net>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.6 $
+Start Date: 2001/10/03
+Last Revision Date: $Date: 2006/01/29 02:09:59 $
+"""
+__author__ = "Mike Orr <iron at mso.oz.net>"
+__revision__ = "$Revision: 1.6 $"[11:-2]
+
+import os
+from Cheetah.Template import Template
+
+class CGITemplate(Template):
+ """Methods useful in CGI scripts.
+
+ Any class that inherits this mixin must also inherit Cheetah.Servlet.
+ """
+
+
+ def cgiHeaders(self):
+ """Outputs the CGI headers if this is a CGI script.
+
+ Usage: $cgiHeaders#slurp
+ Override .cgiHeadersHook() if you want to customize the headers.
+ """
+ if self.isCgi():
+ return self.cgiHeadersHook()
+
+
+
+ def cgiHeadersHook(self):
+ """Override if you want to customize the CGI headers.
+ """
+ return "Content-type: text/html\n\n"
+
+
+ def isCgi(self):
+ """Is this a CGI script?
+ """
+ env = os.environ.has_key('REQUEST_METHOD')
+ wk = self._CHEETAH__isControlledByWebKit
+ return env and not wk
+
+
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReport.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReport.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReport.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,464 @@
+#!/usr/bin/env python
+"""
+@@TR: This code is pretty much unsupported.
+
+MondoReport.py -- Batching module for Python and Cheetah.
+
+Version 2001-Nov-18. Doesn't do much practical yet, but the companion
+testMondoReport.py passes all its tests.
+-Mike Orr (Iron)
+
+TODO: BatchRecord.prev/next/prev_batches/next_batches/query, prev.query,
+next.query.
+
+How about Report: .page(), .all(), .summary()? Or PageBreaker.
+"""
+import operator, types
+try:
+ from Cheetah.NameMapper import valueForKey as lookup_func
+except ImportError:
+ def lookup_func(obj, name):
+ if hasattr(obj, name):
+ return getattr(obj, name)
+ else:
+ return obj[name] # Raises KeyError.
+
+########## CONSTANTS ##############################
+
+True, False = (1==1), (1==0)
+numericTypes = types.IntType, types.LongType, types.FloatType
+
+########## PUBLIC GENERIC FUNCTIONS ##############################
+
+class NegativeError(ValueError):
+ pass
+
+def isNumeric(v):
+ return type(v) in numericTypes
+
+def isNonNegative(v):
+ ret = isNumeric(v)
+ if ret and v < 0:
+ raise NegativeError(v)
+
+def isNotNone(v):
+ return v is not None
+
+def Roman(n):
+ n = int(n) # Raises TypeError.
+ if n < 1:
+ raise ValueError("roman numeral for zero or negative undefined: " + n)
+ roman = ''
+ while n >= 1000:
+ n = n - 1000
+ roman = roman + 'M'
+ while n >= 500:
+ n = n - 500
+ roman = roman + 'D'
+ while n >= 100:
+ n = n - 100
+ roman = roman + 'C'
+ while n >= 50:
+ n = n - 50
+ roman = roman + 'L'
+ while n >= 10:
+ n = n - 10
+ roman = roman + 'X'
+ while n >= 5:
+ n = n - 5
+ roman = roman + 'V'
+ while n < 5 and n >= 1:
+ n = n - 1
+ roman = roman + 'I'
+ roman = roman.replace('DCCCC', 'CM')
+ roman = roman.replace('CCCC', 'CD')
+ roman = roman.replace('LXXXX', 'XC')
+ roman = roman.replace('XXXX', 'XL')
+ roman = roman.replace('VIIII', 'IX')
+ roman = roman.replace('IIII', 'IV')
+ return roman
+
+
+def sum(lis):
+ return reduce(operator.add, lis, 0)
+
+def mean(lis):
+ """Always returns a floating-point number.
+ """
+ lis_len = len(lis)
+ if lis_len == 0:
+ return 0.00 # Avoid ZeroDivisionError (not raised for floats anyway)
+ total = float( sum(lis) )
+ return total / lis_len
+
+def median(lis):
+ lis = lis[:]
+ lis.sort()
+ return lis[int(len(lis)/2)]
+
+
+def variance(lis):
+ raise NotImplementedError()
+
+def variance_n(lis):
+ raise NotImplementedError()
+
+def standardDeviation(lis):
+ raise NotImplementedError()
+
+def standardDeviation_n(lis):
+ raise NotImplementedError()
+
+
+
+class IndexFormats:
+ """Eight ways to display a subscript index.
+ ("Fifty ways to leave your lover....")
+ """
+ def __init__(self, index, item=None):
+ self._index = index
+ self._number = index + 1
+ self._item = item
+
+ def index(self):
+ return self._index
+
+ __call__ = index
+
+ def number(self):
+ return self._number
+
+ def even(self):
+ return self._number % 2 == 0
+
+ def odd(self):
+ return not self.even()
+
+ def even_i(self):
+ return self._index % 2 == 0
+
+ def odd_i(self):
+ return not self.even_i()
+
+ def letter(self):
+ return self.Letter().lower()
+
+ def Letter(self):
+ n = ord('A') + self._index
+ return chr(n)
+
+ def roman(self):
+ return self.Roman().lower()
+
+ def Roman(self):
+ return Roman(self._number)
+
+ def item(self):
+ return self._item
+
+
+
+########## PRIVATE CLASSES ##############################
+
+class ValuesGetterMixin:
+ def __init__(self, origList):
+ self._origList = origList
+
+ def _getValues(self, field=None, criteria=None):
+ if field:
+ ret = [lookup_func(elm, field) for elm in self._origList]
+ else:
+ ret = self._origList
+ if criteria:
+ ret = filter(criteria, ret)
+ return ret
+
+
+class RecordStats(IndexFormats, ValuesGetterMixin):
+ """The statistics that depend on the current record.
+ """
+ def __init__(self, origList, index):
+ record = origList[index] # Raises IndexError.
+ IndexFormats.__init__(self, index, record)
+ ValuesGetterMixin.__init__(self, origList)
+
+ def length(self):
+ return len(self._origList)
+
+ def first(self):
+ return self._index == 0
+
+ def last(self):
+ return self._index >= len(self._origList) - 1
+
+ def _firstOrLastValue(self, field, currentIndex, otherIndex):
+ currentValue = self._origList[currentIndex] # Raises IndexError.
+ try:
+ otherValue = self._origList[otherIndex]
+ except IndexError:
+ return True
+ if field:
+ currentValue = lookup_func(currentValue, field)
+ otherValue = lookup_func(otherValue, field)
+ return currentValue != otherValue
+
+ def firstValue(self, field=None):
+ return self._firstOrLastValue(field, self._index, self._index - 1)
+
+ def lastValue(self, field=None):
+ return self._firstOrLastValue(field, self._index, self._index + 1)
+
+ # firstPage and lastPage not implemented. Needed?
+
+ def percentOfTotal(self, field=None, suffix='%', default='N/A', decimals=2):
+ rec = self._origList[self._index]
+ if field:
+ val = lookup_func(rec, field)
+ else:
+ val = rec
+ try:
+ lis = self._getValues(field, isNumeric)
+ except NegativeError:
+ return default
+ total = sum(lis)
+ if total == 0.00: # Avoid ZeroDivisionError.
+ return default
+ val = float(val)
+ try:
+ percent = (val / total) * 100
+ except ZeroDivisionError:
+ return default
+ if decimals == 0:
+ percent = int(percent)
+ else:
+ percent = round(percent, decimals)
+ if suffix:
+ return str(percent) + suffix # String.
+ else:
+ return percent # Numeric.
+
+ def __call__(self): # Overrides IndexFormats.__call__
+ """This instance is not callable, so we override the super method.
+ """
+ raise NotImplementedError()
+
+ def prev(self):
+ if self._index == 0:
+ return None
+ else:
+ length = self.length()
+ start = self._index - length
+ return PrevNextPage(self._origList, length, start)
+
+ def next(self):
+ if self._index + self.length() == self.length():
+ return None
+ else:
+ length = self.length()
+ start = self._index + length
+ return PrevNextPage(self._origList, length, start)
+
+ def prevPages(self):
+ raise NotImplementedError()
+
+ def nextPages(self):
+ raise NotImplementedError()
+
+ prev_batches = prevPages
+ next_batches = nextPages
+
+ def summary(self):
+ raise NotImplementedError()
+
+
+
+ def _prevNextHelper(self, start,end,size,orphan,sequence):
+ """Copied from Zope's DT_InSV.py's "opt" function.
+ """
+ if size < 1:
+ if start > 0 and end > 0 and end >= start:
+ size=end+1-start
+ else: size=7
+
+ if start > 0:
+
+ try: sequence[start-1]
+ except: start=len(sequence)
+ # if start > l: start=l
+
+ if end > 0:
+ if end < start: end=start
+ else:
+ end=start+size-1
+ try: sequence[end+orphan-1]
+ except: end=len(sequence)
+ # if l - end < orphan: end=l
+ elif end > 0:
+ try: sequence[end-1]
+ except: end=len(sequence)
+ # if end > l: end=l
+ start=end+1-size
+ if start - 1 < orphan: start=1
+ else:
+ start=1
+ end=start+size-1
+ try: sequence[end+orphan-1]
+ except: end=len(sequence)
+ # if l - end < orphan: end=l
+ return start,end,size
+
+
+
+class Summary(ValuesGetterMixin):
+ """The summary statistics, that don't depend on the current record.
+ """
+ def __init__(self, origList):
+ ValuesGetterMixin.__init__(self, origList)
+
+ def sum(self, field=None):
+ lis = self._getValues(field, isNumeric)
+ return sum(lis)
+
+ total = sum
+
+ def count(self, field=None):
+ lis = self._getValues(field, isNotNone)
+ return len(lis)
+
+ def min(self, field=None):
+ lis = self._getValues(field, isNotNone)
+ return min(lis) # Python builtin function min.
+
+ def max(self, field=None):
+ lis = self._getValues(field, isNotNone)
+ return max(lis) # Python builtin function max.
+
+ def mean(self, field=None):
+ """Always returns a floating point number.
+ """
+ lis = self._getValues(field, isNumeric)
+ return mean(lis)
+
+ average = mean
+
+ def median(self, field=None):
+ lis = self._getValues(field, isNumeric)
+ return median(lis)
+
+ def variance(self, field=None):
+ raiseNotImplementedError()
+
+ def variance_n(self, field=None):
+ raiseNotImplementedError()
+
+ def standardDeviation(self, field=None):
+ raiseNotImplementedError()
+
+ def standardDeviation_n(self, field=None):
+ raiseNotImplementedError()
+
+
+class PrevNextPage:
+ def __init__(self, origList, size, start):
+ end = start + size
+ self.start = IndexFormats(start, origList[start])
+ self.end = IndexFormats(end, origList[end])
+ self.length = size
+
+
+########## MAIN PUBLIC CLASS ##############################
+class MondoReport:
+ _RecordStatsClass = RecordStats
+ _SummaryClass = Summary
+
+ def __init__(self, origlist):
+ self._origList = origlist
+
+ def page(self, size, start, overlap=0, orphan=0):
+ """Returns list of ($r, $a, $b)
+ """
+ if overlap != 0:
+ raise NotImplementedError("non-zero overlap")
+ if orphan != 0:
+ raise NotImplementedError("non-zero orphan")
+ origList = self._origList
+ origList_len = len(origList)
+ start = max(0, start)
+ end = min( start + size, len(self._origList) )
+ mySlice = origList[start:end]
+ ret = []
+ for rel in range(size):
+ abs_ = start + rel
+ r = mySlice[rel]
+ a = self._RecordStatsClass(origList, abs_)
+ b = self._RecordStatsClass(mySlice, rel)
+ tup = r, a, b
+ ret.append(tup)
+ return ret
+
+
+ batch = page
+
+ def all(self):
+ origList_len = len(self._origList)
+ return self.page(origList_len, 0, 0, 0)
+
+
+ def summary(self):
+ return self._SummaryClass(self._origList)
+
+"""
+**********************************
+ Return a pageful of records from a sequence, with statistics.
+
+ in : origlist, list or tuple. The entire set of records. This is
+ usually a list of objects or a list of dictionaries.
+ page, int >= 0. Which page to display.
+ size, int >= 1. How many records per page.
+ widow, int >=0. Not implemented.
+ orphan, int >=0. Not implemented.
+ base, int >=0. Number of first page (usually 0 or 1).
+
+ out: list of (o, b) pairs. The records for the current page. 'o' is
+ the original element from 'origlist' unchanged. 'b' is a Batch
+ object containing meta-info about 'o'.
+ exc: IndexError if 'page' or 'size' is < 1. If 'origlist' is empty or
+ 'page' is too high, it returns an empty list rather than raising
+ an error.
+
+ origlist_len = len(origlist)
+ start = (page + base) * size
+ end = min(start + size, origlist_len)
+ ret = []
+ # widow, orphan calculation: adjust 'start' and 'end' up and down,
+ # Set 'widow', 'orphan', 'first_nonwidow', 'first_nonorphan' attributes.
+ for i in range(start, end):
+ o = origlist[i]
+ b = Batch(origlist, size, i)
+ tup = o, b
+ ret.append(tup)
+ return ret
+
+ def prev(self):
+ # return a PrevNextPage or None
+
+ def next(self):
+ # return a PrevNextPage or None
+
+ def prev_batches(self):
+ # return a list of SimpleBatch for the previous batches
+
+ def next_batches(self):
+ # return a list of SimpleBatch for the next batches
+
+########## PUBLIC MIXIN CLASS FOR CHEETAH TEMPLATES ##############
+class MondoReportMixin:
+ def batch(self, origList, size=None, start=0, overlap=0, orphan=0):
+ bat = MondoReport(origList)
+ return bat.batch(size, start, overlap, orphan)
+ def batchstats(self, origList):
+ bat = MondoReport(origList)
+ return bat.stats()
+"""
+
+# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReportDoc.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReportDoc.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/MondoReportDoc.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,391 @@
+MondoReport Documentation
+Version 0.01 alpha 24-Nov-2001. iron at mso.oz.net or mso at oz.net.
+Copyright (c) 2001 Mike Orr. License: same as Python or Cheetah.
+
+* * * * *
+STATUS: previous/next batches and query string are not implemented yet.
+Sorting not designed yet. Considering "click on this column header to sort by
+this field" and multiple ascending/descending sort fields for a future version.
+
+Tested with Python 2.2b1. May work with Python 2.1 or 2.0.
+
+* * * * *
+OVERVIEW
+
+MondoReport -- provide information about a list that is useful in generating
+any kind of report. The module consists of one main public class, and some
+generic functions you may find useful in other programs. This file contains an
+overview, syntax reference and examples. The module is designed both for
+standalone use and for integration with the Cheetah template system
+(http://www.cheetahtemplate.org/), so the examples are in both Python and
+Cheetah. The main uses of MondoReport are:
+
+(A) to iterate through a list. In this sense MR is a for-loop enhancer,
+providing information that would be verbose to calculate otherwise.
+
+(B) to separate a list into equal-size "pages" (or "batches"--the two terms are
+interchangeable) and only display the current page, plus limited information
+about the previous and next pages.
+
+(C) to extract summary statistics about a certain column ("field") in the list.
+
+* * * * *
+MAIN PUBLIC CLASS
+
+To create a MondoReport instance, supply a list to operate on.
+
+ mr = MondoReport(origList)
+
+The list may be a list of anything, but if you use the 'field' argument in any
+of the methods below, the elements must be instances or dictionaries.
+
+MondoReport assumes it's operating on an unchanging list. Do not modify the
+list or any of its elements until you are completely finished with the
+ModoReport object and its sub-objects. Otherwise, you may get an exception or
+incorrect results.
+
+MondoReport instances have three methods:
+
+ .page(size, start, overlap=0, orphan=0
+ sort=None, reverse=False) => list of (r, a, b).
+
+'size' is an integer >= 1. 'start', 'overlap' and 'orphan' are integers >= 0.
+The list returned contains one triple for each record in the current page. 'r'
+is the original record. 'a' is a BatchRecord instance for the current record
+in relation to all records in the origList. 'b' is a BatchRecord instance for
+the current record in relation to all the records in that batch/page. (There
+is a .batch method that's identical to .page.)
+
+The other options aren't implemented yet, but 'overlap' duplicates this many
+records on adjacent batches. 'orphan' moves this many records or fewer, if
+they are on a page alone, onto the neighboring page. 'sort' (string) specifies
+a field to sort the records by. It may be suffixed by ":desc" to sort in
+descending order. 'reverse' (boolean) reverses the sort order. If both
+":desc" and 'reverse' are specified, they will cancel each other out. This
+sorting/reversal happens on a copy of the origList, and all objects returned
+by this method use the sorted list, except when resorting the next time.
+To do more complicated sorting, such as a hierarchy of columns, do it to the
+original list before creating the ModoReport object.
+
+ .all(sort=None, reverse=False) => list of (r, a).
+
+Same, but the current page spans the entire origList.
+
+ .summary() => Summary instance.
+
+Summary statistics for the entire origList.
+
+In Python, use .page or .all in a for loop:
+
+ from Cheetah.Tools.MondoReport import MondoReport
+ mr = MondoReport(myList)
+ for r, a, b in mr.page(20, 40):
+ # Do something with r, a and b. The current page is the third page,
+ # with twenty records corresponding to origList[40:60].
+ if not myList:
+ # Warn the user there are no records in the list.
+
+It works the same way in Cheetah, just convert to Cheetah syntax. This example
+assumes the template doubles as a Webware servlet, so we use the servlet's
+'$request' method to look up the CGI parameter 'start'. The default value is 0
+for the first page.
+
+ #from Cheetah.Tools.MondoReport import MondoReport
+ #set $mr = $MondoReport($bigList)
+ #set $start = $request.field("start", 0)
+ #for $o, $a, $b in $mr.page(20, $start)
+ ... do something with $o, $a and $b ...
+ #end for
+ #unless $bigList
+ This is displayed if the original list has no elements.
+ It's equivalent to the "else" part Zope DTML's <dtml-in>.
+ #end unless
+
+* * * * *
+USING 'r' RECORDS
+
+Use 'r' just as you would the original element. For instance:
+
+ print r.attribute # If r is an instance.
+ print r['key'] # If r is a dictionary.
+ print r # If r is numeric or a string.
+
+In Cheetah, you can take advantage of Universal Dotted Notation and autocalling:
+
+ $r.name ## 'name' may be an attribute or key of 'r'. If 'r' and/or
+ ## 'name' is a function or method, it will be called without
+ ## arguments.
+ $r.attribute
+ $r['key']
+ $r
+ $r().attribute()['key']()
+
+If origList is a list of name/value pairs (2-tuples or 2-lists), you may
+prefer to do this:
+
+ for (key, value), a, b in mr.page(20, 40):
+ print key, "=>", value
+
+ #for ($key, $value), $a, $b in $mr.page(20, $start)
+ $key => $value
+ #end for
+
+* * * * *
+STATISTICS METHODS AND FIELD VALUES
+
+Certain methods below have an optional argument 'field'. If specified,
+MondoReport will look up that field in each affected record and use its value
+in the calculation. MondoReport uses Cheetah's NameMapper if available,
+otherwise it uses a minimal NameMapper substitute that looks for an attribute
+or dictionary key called "field". You'll get an exception if any record is a
+type without attributes or keys, or if one or more records is missing that
+attribute/key.
+
+If 'field' is None, MondoReport will use the entire record in its
+calculation. This makes sense mainly if the records are a numeric type.
+
+All statistics methods filter out None values from their calculations, and
+reduce the number of records accordingly. Most filter out non-numeric fields
+(or records). Some raise NegativeError if a numeric field (or record) is
+negative.
+
+
+* * * * *
+BatchRecord METHODS
+
+The 'a' and 'b' objects of MondoReport.page() and MondoReport.all() provide
+these methods.
+
+ .index()
+
+The current subscript. For 'a', this is the true subscript into origList.
+For 'b', this is relative to the current page, so the first record will be 0.
+Hint: In Cheetah, use autocalling to skip the parentheses: '$b.index'.
+
+ .number()
+
+The record's position starting from 1. This is always '.index() + 1'.
+
+ .Letter()
+
+The letter ("A", "B", "C") corresponding to .number(). Undefined if .number()
+> 26. The current implementation just adds the offset to 'a' and returns
+whatever character it happens to be.
+
+To make a less dumb implementation (e.g., "Z, AA, BB" or "Z, A1, B1"):
+1) Subclass BatchRecord and override the .Letter method.
+2) Subclass MondoReport and set the class variable .BatchRecordClass to your
+new improved class.
+
+ .letter()
+
+Same but lower case.
+
+ .Roman()
+
+The Roman numeral corresponding to .number().
+
+ .roman()
+
+Same but lower case.
+
+ .even()
+
+True if .number() is even.
+
+ .odd()
+
+True if .number() is odd.
+
+ .even_i()
+
+True if .index() is even.
+
+ .odd_i()
+
+True if .index() is odd.
+
+ .length()
+
+For 'a', number of records in origList. For 'b', number of records on this
+page.
+
+ .item()
+
+The record itself. You don't need this in the normal case since it's the same
+as 'r', but it's useful for previous/next batches.
+
+ .size()
+
+The 'size' argument used when this BatchRecord was created.
+'a.size() == b.size()'.
+
+ .first()
+
+True if this is the first record.
+
+ .last()
+
+True if this is the last record.
+
+ .firstValue(field=None)
+
+True if there is no previous record, or if the previous field/record has a
+different value. Used for to print section headers. For instance, if you
+are printing addresses by country, this will be true at the first occurrance
+of each country. Or for indexes, you can have a non-printing field showing
+which letter of the alphablet this entry starts with, and then print a "B"
+header before printing the first record starting with "B".
+
+ .lastValue(field=None)
+
+True if this is the last record containing the current value in the
+field/record.
+
+ .percentOfTotal(field=None, suffix="%", default="N/A", decimals=2)
+
+Returns the percent that the current field/record is of all fields/records.
+If 'suffix' is None, returns a number; otherwise it returns a string with
+'suffix' suffixed. If the current value is non-numeric, returns 'default'
+instead (without 'suffix'). 'decimals' tells the number of decimal places to
+return; if 0, there will be no decimal point.
+
+ .prev()
+
+Returns a PrevNextBatch instance for the previous page. If there is no
+previous page, returns None. [Not implemented yet.]
+
+ .next()
+
+Returns a PrevNextBatch instance for the next page. If there is no next page,
+returns None. [Not implemented yet.]
+
+ .prevPages()
+
+Returns a list of PrevNextPage instances for every previous page, or [] if no
+previous pages. [Not implemented yet.]
+
+ .nextPages()
+
+Returns a list of PrevNextPage instances for every next page, or [] if no next
+pages. [Not implemented yet.]
+
+ .query(start=None, label=None, attribName="start", attribs=[])
+
+[Not implemented yet.]
+
+With no arguments, returns the HTML query string with start value removed (so
+you can append a new start value in your hyperlink). The query string is taken
+from the 'QUERY_STRING' environmental variable, or "" if missing. (This is
+Webware compatible.)
+
+With 'start' (an integer >= 0), returns the query string with an updated start
+value, normally for the next or previous batch.
+
+With 'label' (a string), returns a complete HTML hyperlink:
+'<A HREF="?new_query_string">label</A>'. You'll get a TypeError if you specify
+'label' but not 'start'.
+
+With 'attribName' (a string), uses this attribute name rather than "start".
+Useful if you have another CGI parameter "start" that's used for something
+else.
+
+With 'attribs' (a dictionary), adds these attributes to the hyperlink.
+For instance, 'attribs={"target": "_blank"}'. Ignored unless 'label' is
+specified too.
+
+This method assumes the start parameter is a GET variable, not a POST variable.
+
+ .summary()
+
+Returns a Summary instance. 'a.summary()' refers to all records in the
+origList, so it's the same as MondoReport.summary(). 'b.summary()' refers only
+to the records on the current page. [Not implemented yet.]
+
+* * * * *
+PrevNextPage INSTANCES
+
+[Not implemented yet.]
+
+PrevNextPage instances have the following methods:
+
+ .start()
+
+The index (true index of origList) that that page starts at. You may also use
+'.start().index()', '.start().number()', etc. Also
+'.start().item(field=None)'. (Oh, so *that*'s what .item is for!)
+
+ .end()
+
+The index (true index of origList) that that page ends at. You may also use
+'.end().index()', '.end().number()', etc. Also
+'.end().item(field=None)'.
+
+ .length()
+
+Number of records on that page.
+
+ .query(label=None, attribName="start", attribs={}, before="", after="")
+
+[Not implemented yet.]
+
+Similar to 'a.query()' and 'b.query()', but automatically calculates the start
+value for the appropriate page.
+
+For fancy HTML formatting, 'before' is prepended to the returned text and
+'after' is appended. (There was an argument 'else_' for if there is no such
+batch, but it was removed because you can't even get to this method at all in
+that case.)
+
+* * * * * *
+SUMMARY STATISTICS
+
+These methods are supported by the Summary instances returned by
+MondoReport.Summary():
+
+ .sum(field=None)
+
+Sum of all numeric values in a field, or sum of all records.
+
+ .total(field=None)
+
+Same.
+
+ .count(field=None)
+
+Number of fields/records with non-None values.
+
+ .min(field=None)
+
+Minimum value in that field/record. Ignores None values.
+
+ .max(field=None)
+
+Maximum value in that field/record. Ignores None values.
+
+ .mean(field=None)
+
+The mean (=average) of all numeric values in that field/record.
+
+ .average(field=None)
+
+Same.
+
+ .median(field=None)
+
+The median of all numeric values in that field/record. This is done by sorting
+the values and taking the middle value.
+
+ .variance(field=None), .variance_n(field=None)
+ .standardDeviation(field=None), .standardDeviation_n(field=None)
+
+[Not implemented yet.]
+
+
+* * * * *
+To run the regression tests (requires unittest.py, which is standard with
+Python 2.2), run MondoReportTest.py from the command line. The regression test
+double as usage examples.
+
+
+# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/RecursiveNull.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/RecursiveNull.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/RecursiveNull.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+"""
+Nothing, but in a friendly way. Good for filling in for objects you want to
+hide. If $form.f1 is a RecursiveNull object, then
+$form.f1.anything["you"].might("use") will resolve to the empty string.
+
+This module was contributed by Ian Bicking.
+"""
+
+class RecursiveNull(object):
+ def __getattr__(self, attr):
+ return self
+ def __getitem__(self, item):
+ return self
+ def __call__(self, *args, **kwargs):
+ return self
+ def __str__(self):
+ return ''
+ def __repr__(self):
+ return ''
+ def __nonzero__(self):
+ return 0
+ def __eq__(self, x):
+ if x:
+ return False
+ return True
+ def __ne__(self, x):
+ return x and True or False
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/SiteHierarchy.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/SiteHierarchy.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/SiteHierarchy.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+# $Id: SiteHierarchy.py,v 1.1 2001/10/11 03:25:54 tavis_rudd Exp $
+"""Create menus and crumbs from a site hierarchy.
+
+You define the site hierarchy as lists/tuples. Each location in the hierarchy
+is a (url, description) tuple. Each list has the base URL/text in the 0
+position, and all the children coming after it. Any child can be a list,
+representing further depth to the hierarchy. See the end of the file for an
+example hierarchy.
+
+Use Hierarchy(contents, currentURL), where contents is this hierarchy, and
+currentURL is the position you are currently in. The menubar and crumbs methods
+give you the HTML output.
+
+There are methods you can override to customize the HTML output.
+
+Meta-Data
+================================================================================
+Author: Ian Bicking <ianb at colorstudy.com>
+Version: $Revision: 1.1 $
+Start Date: 2001/07/23
+Last Revision Date: $Date: 2001/10/11 03:25:54 $
+"""
+__author__ = "Ian Bicking <ianb at colorstudy.com>"
+__version__ = "$Revision: 1.1 $"[11:-2]
+
+##################################################
+## DEPENDENCIES
+import string
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+
+##################################################
+## GLOBALS & CONSTANTS
+
+True, False = (1==1), (0==1)
+
+##################################################
+## CLASSES
+
+class Hierarchy:
+ def __init__(self, hierarchy, currentURL, prefix='', menuCSSClass=None,
+ crumbCSSClass=None):
+ """
+ hierarchy is described above, currentURL should be somewhere in
+ the hierarchy. prefix will be added before all of the URLs (to
+ help mitigate the problems with absolute URLs), and if given,
+ cssClass will be used for both links *and* nonlinks.
+ """
+
+ self._contents = hierarchy
+ self._currentURL = currentURL
+ if menuCSSClass:
+ self._menuCSSClass = ' class="%s"' % menuCSSClass
+ else:
+ self._menuCSSClass = ''
+ if crumbCSSClass:
+ self._crumbCSSClass = ' class="%s"' % crumbCSSClass
+ else:
+ self._crumbCSSClass = ''
+ self._prefix=prefix
+
+
+ ## Main output methods
+
+ def menuList(self, menuCSSClass=None):
+ """An indented menu list"""
+ if menuCSSClass:
+ self._menuCSSClass = ' class="%s"' % menuCSSClass
+
+ stream = StringIO()
+ for item in self._contents[1:]:
+ self._menubarRecurse(item, 0, stream)
+ return stream.getvalue()
+
+ def crumbs(self, crumbCSSClass=None):
+ """The home>where>you>are crumbs"""
+ if crumbCSSClass:
+ self._crumbCSSClass = ' class="%s"' % crumbCSSClass
+
+ path = []
+ pos = self._contents
+ while 1:
+ ## This is not the fastest algorithm, I'm afraid.
+ ## But it probably won't be for a huge hierarchy anyway.
+ foundAny = False
+ path.append(pos[0])
+ for item in pos[1:]:
+ if self._inContents(item):
+ if type(item) is type(()):
+ path.append(item)
+ break
+ else:
+ pos = item
+ foundAny = True
+ break
+ if not foundAny:
+ break
+ if len(path) == 1:
+ return self.emptyCrumb()
+ return string.join(map(lambda x, self=self: self.crumbLink(x[0], x[1]),
+ path), self.crumbSeperator()) + \
+ self.crumbTerminator()
+
+ ## Methods to control the Aesthetics
+ # - override these methods for your own look
+
+ def menuLink(self, url, text, indent):
+ if url == self._currentURL or self._prefix + url == self._currentURL:
+ return '%s<B%s>%s</B> <BR>\n' % (' '*2*indent,
+ self._menuCSSClass, text)
+ else:
+ return '%s<A HREF="%s%s"%s>%s</A> <BR>\n' % \
+ (' '*2*indent, self._prefix, url,
+ self._menuCSSClass, text)
+
+ def crumbLink(self, url, text):
+ if url == self._currentURL or self._prefix + url == self._currentURL:
+ return '<B%s>%s</B>' % (text, self._crumbCSSClass)
+ else:
+ return '<A HREF="%s%s"%s>%s</A>' % \
+ (self._prefix, url, self._crumbCSSClass, text)
+
+ def crumbSeperator(self):
+ return ' > '
+
+ def crumbTerminator(self):
+ return ''
+
+ def emptyCrumb(self):
+ """When you are at the homepage"""
+ return ''
+
+ ## internal methods
+
+ def _menubarRecurse(self, contents, indent, stream):
+ if type(contents) is type(()):
+ url, text = contents
+ rest = []
+ else:
+ url, text = contents[0]
+ rest = contents[1:]
+ stream.write(self.menuLink(url, text, indent))
+ if self._inContents(contents):
+ for item in rest:
+ self._menubarRecurse(item, indent+1, stream)
+
+ def _inContents(self, contents):
+ if type(contents) is type(()):
+ return self._currentURL == contents[0]
+ for item in contents:
+ if self._inContents(item):
+ return True
+ return False
+
+##################################################
+## from the command line
+
+if __name__ == '__main__':
+ hierarchy = [('/', 'home'),
+ ('/about', 'About Us'),
+ [('/services', 'Services'),
+ [('/services/products', 'Products'),
+ ('/services/products/widget', 'The Widget'),
+ ('/services/products/wedge', 'The Wedge'),
+ ('/services/products/thimble', 'The Thimble'),
+ ],
+ ('/services/prices', 'Prices'),
+ ],
+ ('/contact', 'Contact Us'),
+ ]
+
+ for url in ['/', '/services', '/services/products/widget', '/contact']:
+ print '<p>', '='*50
+ print '<br> %s: <br>\n' % url
+ n = Hierarchy(hierarchy, url, menuCSSClass='menu', crumbCSSClass='crumb',
+ prefix='/here')
+ print n.menuList()
+ print '<p>', '-'*50
+ print n.crumbs()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Tools/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+"""This package contains classes, functions, objects and packages contributed
+ by Cheetah users. They are not used by Cheetah itself. There is no
+ guarantee that this directory will be included in Cheetah releases, that
+ these objects will remain here forever, or that they will remain
+ backward-compatible.
+"""
+
+# vim: shiftwidth=5 tabstop=5 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Unspecified.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Unspecified.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Unspecified.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+try:
+ from ds.sys.Unspecified import Unspecified
+except ImportError:
+ class _Unspecified:
+ def __repr__(self):
+ return 'Unspecified'
+ def __str__(self):
+ return 'Unspecified'
+ Unspecified = _Unspecified()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Indenter.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Indenter.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Indenter.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# $Id: Indenter.py,v 1.7 2006/01/08 01:09:30 tavis_rudd Exp $
+"""Indentation maker.
+@@TR: this code is unsupported and largely undocumented ...
+
+This version is based directly on code by Robert Kuzelj
+<robert_kuzelj at yahoo.com> and uses his directive syntax. Some classes and
+attributes have been renamed. Indentation is output via
+$self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the
+searchList and another one being found. The directive syntax will
+soon be changed somewhat.
+
+Meta-Data
+================================================================================
+Author: Mike Orr <iron at mso.oz.net>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.7 $
+Start Date: 2001/11/07
+Last Revision Date: $Date: 2006/01/08 01:09:30 $
+"""
+__author__ = "Mike Orr <iron at mso.oz.net>"
+__revision__ = "$Revision: 1.7 $"[11:-2]
+
+import re
+import sys
+
+def indentize(source):
+ return IndentProcessor().process(source)
+
+class IndentProcessor:
+ """Preprocess #indent tags."""
+ LINE_SEP = '\n'
+ ARGS = "args"
+ INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P<args>.*)')
+ DIRECTIVE = re.compile(r"[ \t]*#")
+ WS = "ws"
+ WHITESPACES = re.compile(r"(?P<ws>[ \t]*)")
+
+ INC = "++"
+ DEC = "--"
+
+ SET = "="
+ CHAR = "char"
+
+ ON = "on"
+ OFF = "off"
+
+ PUSH = "push"
+ POP = "pop"
+
+ def process(self, _txt):
+ result = []
+
+ for line in _txt.splitlines():
+ match = self.INDENT_DIR.match(line)
+ if match:
+ #is indention directive
+ args = match.group(self.ARGS).strip()
+ if args == self.ON:
+ line = "#silent $self._CHEETAH__indenter.on()"
+ elif args == self.OFF:
+ line = "#silent $self._CHEETAH__indenter.off()"
+ elif args == self.INC:
+ line = "#silent $self._CHEETAH__indenter.inc()"
+ elif args == self.DEC:
+ line = "#silent $self._CHEETAH__indenter.dec()"
+ elif args.startswith(self.SET):
+ level = int(args[1:])
+ line = "#silent $self._CHEETAH__indenter.setLevel(%(level)d)" % {"level":level}
+ elif args.startswith('chars'):
+ self.indentChars = eval(args.split('=')[1])
+ line = "#silent $self._CHEETAH__indenter.setChars(%(level)d)" % {"level":level}
+ elif args.startswith(self.PUSH):
+ line = "#silent $self._CHEETAH__indenter.push()"
+ elif args.startswith(self.POP):
+ line = "#silent $self._CHEETAH__indenter.pop()"
+ else:
+ match = self.DIRECTIVE.match(line)
+ if not match:
+ #is not another directive
+ match = self.WHITESPACES.match(line)
+ if match:
+ size = len(match.group("ws").expandtabs(4))
+ line = ("${self._CHEETAH__indenter.indent(%(size)d)}" % {"size":size}) + line.lstrip()
+ else:
+ line = "${self._CHEETAH__indenter.indent(0)}" + line
+ result.append(line)
+
+ return self.LINE_SEP.join(result)
+
+class Indenter:
+ """A class that keeps track of the current indentation level.
+ .indent() returns the appropriate amount of indentation.
+ """
+ def __init__(self):
+ self.On = 1
+ self.Level = 0
+ self.Chars = " "*4
+ self.LevelStack = []
+ def on(self):
+ self.On = 1
+ def off(self):
+ self.On = 0
+ def inc(self):
+ self.Level += 1
+ def dec(self):
+ """decrement can only be applied to values greater zero
+ values below zero don't make any sense at all!"""
+ if self.Level > 0:
+ self.Level -= 1
+ def push(self):
+ self.LevelStack.append(self.Level)
+ def pop(self):
+ """the levestack can not become -1. any attempt to do so
+ sets the level to 0!"""
+ if len(self.LevelStack) > 0:
+ self.Level = self.LevelStack.pop()
+ else:
+ self.Level = 0
+ def setLevel(self, _level):
+ """the leve can't be less than zero. any attempt to do so
+ sets the level automatically to zero!"""
+ if _level < 0:
+ self.Level = 0
+ else:
+ self.Level = _level
+ def setChar(self, _chars):
+ self.Chars = _chars
+ def indent(self, _default=0):
+ if self.On:
+ return self.Chars * self.Level
+ else:
+ return " " * _default
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Misc.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Misc.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/Misc.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# $Id: Misc.py,v 1.8 2005/11/02 22:26:08 tavis_rudd Exp $
+"""Miscellaneous functions/objects used by Cheetah but also useful standalone.
+
+Meta-Data
+================================================================================
+Author: Mike Orr <iron at mso.oz.net>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.8 $
+Start Date: 2001/11/07
+Last Revision Date: $Date: 2005/11/02 22:26:08 $
+"""
+__author__ = "Mike Orr <iron at mso.oz.net>"
+__revision__ = "$Revision: 1.8 $"[11:-2]
+
+import os # Used in mkdirsWithPyInitFile.
+import types # Used in useOrRaise.
+import sys # Used in die.
+
+##################################################
+## MISCELLANEOUS FUNCTIONS
+
+def die(reason):
+ sys.stderr.write(reason + '\n')
+ sys.exit(1)
+
+def useOrRaise(thing, errmsg=''):
+ """Raise 'thing' if it's a subclass of Exception. Otherwise return it.
+
+ Called by: Cheetah.Servlet.cgiImport()
+ """
+ if type(thing) == types.ClassType and issubclass(thing, Exception):
+ raise thing(errmsg)
+ return thing
+
+
+def checkKeywords(dic, legalKeywords, what='argument'):
+ """Verify no illegal keyword arguments were passed to a function.
+
+ in : dic, dictionary (**kw in the calling routine).
+ legalKeywords, list of strings, the keywords that are allowed.
+ what, string, suffix for error message (see function source).
+ out: None.
+ exc: TypeError if 'dic' contains a key not in 'legalKeywords'.
+ called by: Cheetah.Template.__init__()
+ """
+ # XXX legalKeywords could be a set when sets get added to Python.
+ for k in dic.keys(): # Can be dic.iterkeys() if Python >= 2.2.
+ if k not in legalKeywords:
+ raise TypeError("'%s' is not a valid %s" % (k, what))
+
+
+def removeFromList(list_, *elements):
+ """Save as list_.remove(each element) but don't raise an error if
+ element is missing. Modifies 'list_' in place! Returns None.
+ """
+ for elm in elements:
+ try:
+ list_.remove(elm)
+ except ValueError:
+ pass
+
+
+def mkdirsWithPyInitFiles(path):
+ """Same as os.makedirs (mkdir 'path' and all missing parent directories)
+ but also puts a Python '__init__.py' file in every directory it
+ creates. Does nothing (without creating an '__init__.py' file) if the
+ directory already exists.
+ """
+ dir, fil = os.path.split(path)
+ if dir and not os.path.exists(dir):
+ mkdirsWithPyInitFiles(dir)
+ if not os.path.exists(path):
+ os.mkdir(path)
+ init = os.path.join(path, "__init__.py")
+ f = open(init, 'w') # Open and close to produce empty file.
+ f.close()
+
+
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/VerifyType.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/VerifyType.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/VerifyType.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# $Id: VerifyType.py,v 1.4 2005/11/02 22:26:08 tavis_rudd Exp $
+"""Functions to verify an argument's type
+
+Meta-Data
+================================================================================
+Author: Mike Orr <iron at mso.oz.net>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.4 $
+Start Date: 2001/11/07
+Last Revision Date: $Date: 2005/11/02 22:26:08 $
+"""
+__author__ = "Mike Orr <iron at mso.oz.net>"
+__revision__ = "$Revision: 1.4 $"[11:-2]
+
+##################################################
+## DEPENDENCIES
+
+import types # Used in VerifyTypeClass.
+
+##################################################
+## PRIVATE FUNCTIONS
+
+def _errmsg(argname, ltd, errmsgExtra=''):
+ """Construct an error message.
+
+ argname, string, the argument name.
+ ltd, string, description of the legal types.
+ errmsgExtra, string, text to append to error mssage.
+ Returns: string, the error message.
+ """
+ if errmsgExtra:
+ errmsgExtra = '\n' + errmsgExtra
+ return "arg '%s' must be %s%s" % (argname, ltd, errmsgExtra)
+
+
+##################################################
+## TYPE VERIFICATION FUNCTIONS
+
+def VerifyType(arg, argname, legalTypes, ltd, errmsgExtra=''):
+ """Verify the type of an argument.
+
+ arg, any, the argument.
+ argname, string, name of the argument.
+ legalTypes, list of type objects, the allowed types.
+ ltd, string, description of legal types (for error message).
+ errmsgExtra, string, text to append to error message.
+ Returns: None.
+ Exceptions: TypeError if 'arg' is the wrong type.
+ """
+ if type(arg) not in legalTypes:
+ m = _errmsg(argname, ltd, errmsgExtra)
+ raise TypeError(m)
+
+
+def VerifyTypeClass(arg, argname, legalTypes, ltd, klass, errmsgExtra=''):
+ """Same, but if it's a class, verify it's a subclass of the right class.
+
+ arg, any, the argument.
+ argname, string, name of the argument.
+ legalTypes, list of type objects, the allowed types.
+ ltd, string, description of legal types (for error message).
+ klass, class, the parent class.
+ errmsgExtra, string, text to append to the error message.
+ Returns: None.
+ Exceptions: TypeError if 'arg' is the wrong type.
+ """
+ VerifyType(arg, argname, legalTypes, ltd, errmsgExtra)
+ # If no exception, the arg is a legal type.
+ if type(arg) == types.ClassType and not issubclass(arg, klass):
+ # Must test for "is class type" to avoid TypeError from issubclass().
+ m = _errmsg(argname, ltd, errmsgExtra)
+ raise TypeError(m)
+
+# @@MO: Commented until we determine whether it's useful.
+#def VerifyClass(arg, argname, klass, ltd):
+# """Same, but allow *only* a subclass of the right class.
+# """
+# VerifyTypeClass(arg, argname, [types.ClassType], ltd, klass)
+
+# vim: shiftwidth=4 tabstop=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/WebInputMixin.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/WebInputMixin.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/WebInputMixin.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+# $Id: WebInputMixin.py,v 1.10 2006/01/06 21:56:54 tavis_rudd Exp $
+"""Provides helpers for Template.webInput(), a method for importing web
+transaction variables in bulk. See the docstring of webInput for full details.
+
+Meta-Data
+================================================================================
+Author: Mike Orr <iron at mso.oz.net>
+License: This software is released for unlimited distribution under the
+ terms of the MIT license. See the LICENSE file.
+Version: $Revision: 1.10 $
+Start Date: 2002/03/17
+Last Revision Date: $Date: 2006/01/06 21:56:54 $
+"""
+__author__ = "Mike Orr <iron at mso.oz.net>"
+__revision__ = "$Revision: 1.10 $"[11:-2]
+
+from Cheetah.Utils.Misc import useOrRaise
+
+class NonNumericInputError(ValueError): pass
+
+##################################################
+## PRIVATE FUNCTIONS AND CLASSES
+
+class _Converter:
+ """A container object for info about type converters.
+ .name, string, name of this converter (for error messages).
+ .func, function, factory function.
+ .default, value to use or raise if the real value is missing.
+ .error, value to use or raise if .func() raises an exception.
+ """
+ def __init__(self, name, func, default, error):
+ self.name = name
+ self.func = func
+ self.default = default
+ self.error = error
+
+
+def _lookup(name, func, multi, converters):
+ """Look up a Webware field/cookie/value/session value. Return
+ '(realName, value)' where 'realName' is like 'name' but with any
+ conversion suffix strips off. Applies numeric conversion and
+ single vs multi values according to the comments in the source.
+ """
+ # Step 1 -- split off the conversion suffix from 'name'; e.g. "height:int".
+ # If there's no colon, the suffix is "". 'longName' is the name with the
+ # suffix, 'shortName' is without.
+ # XXX This implementation assumes "height:" means "height".
+ colon = name.find(':')
+ if colon != -1:
+ longName = name
+ shortName, ext = name[:colon], name[colon+1:]
+ else:
+ longName = shortName = name
+ ext = ''
+
+ # Step 2 -- look up the values by calling 'func'.
+ if longName != shortName:
+ values = func(longName, None) or func(shortName, None)
+ else:
+ values = func(shortName, None)
+ # 'values' is a list of strings, a string or None.
+
+ # Step 3 -- Coerce 'values' to a list of zero, one or more strings.
+ if values is None:
+ values = []
+ elif isinstance(values, str):
+ values = [values]
+
+ # Step 4 -- Find a _Converter object or raise TypeError.
+ try:
+ converter = converters[ext]
+ except KeyError:
+ fmt = "'%s' is not a valid converter name in '%s'"
+ tup = (ext, longName)
+ raise TypeError(fmt % tup)
+
+ # Step 5 -- if there's a converter func, run it on each element.
+ # If the converter raises an exception, use or raise 'converter.error'.
+ if converter.func is not None:
+ tmp = values[:]
+ values = []
+ for elm in tmp:
+ try:
+ elm = converter.func(elm)
+ except (TypeError, ValueError):
+ tup = converter.name, elm
+ errmsg = "%s '%s' contains invalid characters" % tup
+ elm = useOrRaise(converter.error, errmsg)
+ values.append(elm)
+ # 'values' is now a list of strings, ints or floats.
+
+ # Step 6 -- If we're supposed to return a multi value, return the list
+ # as is. If we're supposed to return a single value and the list is
+ # empty, return or raise 'converter.default'. Otherwise, return the
+ # first element in the list and ignore any additional values.
+ if multi:
+ return shortName, values
+ if len(values) == 0:
+ return shortName, useOrRaise(converter.default)
+ return shortName, values[0]
+
+# vim: sw=4 ts=4 expandtab
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlDecode.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlDecode.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlDecode.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+"""This is a copy of the htmlDecode function in Webware.
+
+@@TR: It implemented more efficiently.
+
+"""
+
+from Cheetah.Utils.htmlEncode import htmlCodesReversed
+
+def htmlDecode(s, codes=htmlCodesReversed):
+ """ Returns the ASCII decoded version of the given HTML string. This does
+ NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode()."""
+ for code in codes:
+ s = s.replace(code[1], code[0])
+ return s
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlEncode.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlEncode.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/htmlEncode.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+"""This is a copy of the htmlEncode function in Webware.
+
+
+@@TR: It implemented more efficiently.
+
+"""
+htmlCodes = [
+ ['&', '&'],
+ ['<', '<'],
+ ['>', '>'],
+ ['"', '"'],
+]
+htmlCodesReversed = htmlCodes[:]
+htmlCodesReversed.reverse()
+
+def htmlEncode(s, codes=htmlCodes):
+ """ Returns the HTML encoded version of the given string. This is useful to
+ display a plain ASCII text string on a web page."""
+ for code in codes:
+ s = s.replace(code[0], code[1])
+ return s
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/memcache.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/memcache.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/memcache.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,625 @@
+#!/usr/bin/env python
+
+"""
+client module for memcached (memory cache daemon)
+
+Overview
+========
+
+See U{the MemCached homepage<http://www.danga.com/memcached>} for more about memcached.
+
+Usage summary
+=============
+
+This should give you a feel for how this module operates::
+
+ import memcache
+ mc = memcache.Client(['127.0.0.1:11211'], debug=0)
+
+ mc.set("some_key", "Some value")
+ value = mc.get("some_key")
+
+ mc.set("another_key", 3)
+ mc.delete("another_key")
+
+ mc.set("key", "1") # note that the key used for incr/decr must be a string.
+ mc.incr("key")
+ mc.decr("key")
+
+The standard way to use memcache with a database is like this::
+
+ key = derive_key(obj)
+ obj = mc.get(key)
+ if not obj:
+ obj = backend_api.get(...)
+ mc.set(key, obj)
+
+ # we now have obj, and future passes through this code
+ # will use the object from the cache.
+
+Detailed Documentation
+======================
+
+More detailed documentation is available in the L{Client} class.
+"""
+
+import sys
+import socket
+import time
+import types
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+__author__ = "Evan Martin <martine at danga.com>"
+__version__ = "1.2_tummy5"
+__copyright__ = "Copyright (C) 2003 Danga Interactive"
+__license__ = "Python"
+
+class _Error(Exception):
+ pass
+
+class Client:
+ """
+ Object representing a pool of memcache servers.
+
+ See L{memcache} for an overview.
+
+ In all cases where a key is used, the key can be either:
+ 1. A simple hashable type (string, integer, etc.).
+ 2. A tuple of C{(hashvalue, key)}. This is useful if you want to avoid
+ making this module calculate a hash value. You may prefer, for
+ example, to keep all of a given user's objects on the same memcache
+ server, so you could use the user's unique id as the hash value.
+
+ @group Setup: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog
+ @group Insertion: set, add, replace
+ @group Retrieval: get, get_multi
+ @group Integers: incr, decr
+ @group Removal: delete
+ @sort: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog,\
+ set, add, replace, get, get_multi, incr, decr, delete
+ """
+
+ _usePickle = False
+ _FLAG_PICKLE = 1<<0
+ _FLAG_INTEGER = 1<<1
+ _FLAG_LONG = 1<<2
+
+ _SERVER_RETRIES = 10 # how many times to try finding a free server.
+
+ def __init__(self, servers, debug=0):
+ """
+ Create a new Client object with the given list of servers.
+
+ @param servers: C{servers} is passed to L{set_servers}.
+ @param debug: whether to display error messages when a server can't be
+ contacted.
+ """
+ self.set_servers(servers)
+ self.debug = debug
+ self.stats = {}
+
+ def set_servers(self, servers):
+ """
+ Set the pool of servers used by this client.
+
+ @param servers: an array of servers.
+ Servers can be passed in two forms:
+ 1. Strings of the form C{"host:port"}, which implies a default weight of 1.
+ 2. Tuples of the form C{("host:port", weight)}, where C{weight} is
+ an integer weight value.
+ """
+ self.servers = [_Host(s, self.debuglog) for s in servers]
+ self._init_buckets()
+
+ def get_stats(self):
+ '''Get statistics from each of the servers.
+
+ @return: A list of tuples ( server_identifier, stats_dictionary ).
+ The dictionary contains a number of name/value pairs specifying
+ the name of the status field and the string value associated with
+ it. The values are not converted from strings.
+ '''
+ data = []
+ for s in self.servers:
+ if not s.connect(): continue
+ name = '%s:%s (%s)' % ( s.ip, s.port, s.weight )
+ s.send_cmd('stats')
+ serverData = {}
+ data.append(( name, serverData ))
+ readline = s.readline
+ while 1:
+ line = readline()
+ if not line or line.strip() == 'END': break
+ stats = line.split(' ', 2)
+ serverData[stats[1]] = stats[2]
+
+ return(data)
+
+ def flush_all(self):
+ 'Expire all data currently in the memcache servers.'
+ for s in self.servers:
+ if not s.connect(): continue
+ s.send_cmd('flush_all')
+ s.expect("OK")
+
+ def debuglog(self, str):
+ if self.debug:
+ sys.stderr.write("MemCached: %s\n" % str)
+
+ def _statlog(self, func):
+ if not self.stats.has_key(func):
+ self.stats[func] = 1
+ else:
+ self.stats[func] += 1
+
+ def forget_dead_hosts(self):
+ """
+ Reset every host in the pool to an "alive" state.
+ """
+ for s in self.servers:
+ s.dead_until = 0
+
+ def _init_buckets(self):
+ self.buckets = []
+ for server in self.servers:
+ for i in range(server.weight):
+ self.buckets.append(server)
+
+ def _get_server(self, key):
+ if type(key) == types.TupleType:
+ serverhash = key[0]
+ key = key[1]
+ else:
+ serverhash = hash(key)
+
+ for i in range(Client._SERVER_RETRIES):
+ server = self.buckets[serverhash % len(self.buckets)]
+ if server.connect():
+ #print "(using server %s)" % server,
+ return server, key
+ serverhash = hash(str(serverhash) + str(i))
+ return None, None
+
+ def disconnect_all(self):
+ for s in self.servers:
+ s.close_socket()
+
+ def delete(self, key, time=0):
+ '''Deletes a key from the memcache.
+
+ @return: Nonzero on success.
+ @rtype: int
+ '''
+ server, key = self._get_server(key)
+ if not server:
+ return 0
+ self._statlog('delete')
+ if time != None:
+ cmd = "delete %s %d" % (key, time)
+ else:
+ cmd = "delete %s" % key
+
+ try:
+ server.send_cmd(cmd)
+ server.expect("DELETED")
+ except socket.error, msg:
+ server.mark_dead(msg[1])
+ return 0
+ return 1
+
+ def incr(self, key, delta=1):
+ """
+ Sends a command to the server to atomically increment the value for C{key} by
+ C{delta}, or by 1 if C{delta} is unspecified. Returns None if C{key} doesn't
+ exist on server, otherwise it returns the new value after incrementing.
+
+ Note that the value for C{key} must already exist in the memcache, and it
+ must be the string representation of an integer.
+
+ >>> mc.set("counter", "20") # returns 1, indicating success
+ 1
+ >>> mc.incr("counter")
+ 21
+ >>> mc.incr("counter")
+ 22
+
+ Overflow on server is not checked. Be aware of values approaching
+ 2**32. See L{decr}.
+
+ @param delta: Integer amount to increment by (should be zero or greater).
+ @return: New value after incrementing.
+ @rtype: int
+ """
+ return self._incrdecr("incr", key, delta)
+
+ def decr(self, key, delta=1):
+ """
+ Like L{incr}, but decrements. Unlike L{incr}, underflow is checked and
+ new values are capped at 0. If server value is 1, a decrement of 2
+ returns 0, not -1.
+
+ @param delta: Integer amount to decrement by (should be zero or greater).
+ @return: New value after decrementing.
+ @rtype: int
+ """
+ return self._incrdecr("decr", key, delta)
+
+ def _incrdecr(self, cmd, key, delta):
+ server, key = self._get_server(key)
+ if not server:
+ return 0
+ self._statlog(cmd)
+ cmd = "%s %s %d" % (cmd, key, delta)
+ try:
+ server.send_cmd(cmd)
+ line = server.readline()
+ return int(line)
+ except socket.error, msg:
+ server.mark_dead(msg[1])
+ return None
+
+ def add(self, key, val, time=0):
+ '''
+ Add new key with value.
+
+ Like L{set}, but only stores in memcache if the key doesn\'t already exist.
+
+ @return: Nonzero on success.
+ @rtype: int
+ '''
+ return self._set("add", key, val, time)
+ def replace(self, key, val, time=0):
+ '''Replace existing key with value.
+
+ Like L{set}, but only stores in memcache if the key already exists.
+ The opposite of L{add}.
+
+ @return: Nonzero on success.
+ @rtype: int
+ '''
+ return self._set("replace", key, val, time)
+ def set(self, key, val, time=0):
+ '''Unconditionally sets a key to a given value in the memcache.
+
+ The C{key} can optionally be an tuple, with the first element being the
+ hash value, if you want to avoid making this module calculate a hash value.
+ You may prefer, for example, to keep all of a given user's objects on the
+ same memcache server, so you could use the user's unique id as the hash
+ value.
+
+ @return: Nonzero on success.
+ @rtype: int
+ '''
+ return self._set("set", key, val, time)
+
+ def _set(self, cmd, key, val, time):
+ server, key = self._get_server(key)
+ if not server:
+ return 0
+
+ self._statlog(cmd)
+
+ flags = 0
+ if isinstance(val, types.StringTypes):
+ pass
+ elif isinstance(val, int):
+ flags |= Client._FLAG_INTEGER
+ val = "%d" % val
+ elif isinstance(val, long):
+ flags |= Client._FLAG_LONG
+ val = "%d" % val
+ elif self._usePickle:
+ flags |= Client._FLAG_PICKLE
+ val = pickle.dumps(val, 2)
+ else:
+ pass
+
+ fullcmd = "%s %s %d %d %d\r\n%s" % (cmd, key, flags, time, len(val), val)
+ try:
+ server.send_cmd(fullcmd)
+ server.expect("STORED")
+ except socket.error, msg:
+ server.mark_dead(msg[1])
+ return 0
+ return 1
+
+ def get(self, key):
+ '''Retrieves a key from the memcache.
+
+ @return: The value or None.
+ '''
+ server, key = self._get_server(key)
+ if not server:
+ return None
+
+ self._statlog('get')
+
+ try:
+ server.send_cmd("get %s" % key)
+ rkey, flags, rlen, = self._expectvalue(server)
+ if not rkey:
+ return None
+ value = self._recv_value(server, flags, rlen)
+ server.expect("END")
+ except (_Error, socket.error), msg:
+ if type(msg) is types.TupleType:
+ msg = msg[1]
+ server.mark_dead(msg)
+ return None
+ return value
+
+ def get_multi(self, keys):
+ '''
+ Retrieves multiple keys from the memcache doing just one query.
+
+ >>> success = mc.set("foo", "bar")
+ >>> success = mc.set("baz", 42)
+ >>> mc.get_multi(["foo", "baz", "foobar"]) == {"foo": "bar", "baz": 42}
+ 1
+
+ This method is recommended over regular L{get} as it lowers the number of
+ total packets flying around your network, reducing total latency, since
+ your app doesn\'t have to wait for each round-trip of L{get} before sending
+ the next one.
+
+ @param keys: An array of keys.
+ @return: A dictionary of key/value pairs that were available.
+
+ '''
+
+ self._statlog('get_multi')
+
+ server_keys = {}
+
+ # build up a list for each server of all the keys we want.
+ for key in keys:
+ server, key = self._get_server(key)
+ if not server:
+ continue
+ if not server_keys.has_key(server):
+ server_keys[server] = []
+ server_keys[server].append(key)
+
+ # send out all requests on each server before reading anything
+ dead_servers = []
+ for server in server_keys.keys():
+ try:
+ server.send_cmd("get %s" % " ".join(server_keys[server]))
+ except socket.error, msg:
+ server.mark_dead(msg[1])
+ dead_servers.append(server)
+
+ # if any servers died on the way, don't expect them to respond.
+ for server in dead_servers:
+ del server_keys[server]
+
+ retvals = {}
+ for server in server_keys.keys():
+ try:
+ line = server.readline()
+ while line and line != 'END':
+ rkey, flags, rlen = self._expectvalue(server, line)
+ # Bo Yang reports that this can sometimes be None
+ if rkey is not None:
+ val = self._recv_value(server, flags, rlen)
+ retvals[rkey] = val
+ line = server.readline()
+ except (_Error, socket.error), msg:
+ server.mark_dead(msg)
+ return retvals
+
+ def _expectvalue(self, server, line=None):
+ if not line:
+ line = server.readline()
+
+ if line[:5] == 'VALUE':
+ resp, rkey, flags, len = line.split()
+ flags = int(flags)
+ rlen = int(len)
+ return (rkey, flags, rlen)
+ else:
+ return (None, None, None)
+
+ def _recv_value(self, server, flags, rlen):
+ rlen += 2 # include \r\n
+ buf = server.recv(rlen)
+ if len(buf) != rlen:
+ raise _Error("received %d bytes when expecting %d" % (len(buf), rlen))
+
+ if len(buf) == rlen:
+ buf = buf[:-2] # strip \r\n
+
+ if flags == 0:
+ val = buf
+ elif flags & Client._FLAG_INTEGER:
+ val = int(buf)
+ elif flags & Client._FLAG_LONG:
+ val = long(buf)
+ elif self._usePickle and flags & Client._FLAG_PICKLE:
+ try:
+ val = pickle.loads(buf)
+ except:
+ self.debuglog('Pickle error...\n')
+ val = None
+ else:
+ self.debuglog("unknown flags on get: %x\n" % flags)
+
+ return val
+
+class _Host:
+ _DEAD_RETRY = 30 # number of seconds before retrying a dead server.
+
+ def __init__(self, host, debugfunc=None):
+ if isinstance(host, types.TupleType):
+ host = host[0]
+ self.weight = host[1]
+ else:
+ self.weight = 1
+
+ if host.find(":") > 0:
+ self.ip, self.port = host.split(":")
+ self.port = int(self.port)
+ else:
+ self.ip, self.port = host, 11211
+
+ if not debugfunc:
+ debugfunc = lambda x: x
+ self.debuglog = debugfunc
+
+ self.deaduntil = 0
+ self.socket = None
+
+ def _check_dead(self):
+ if self.deaduntil and self.deaduntil > time.time():
+ return 1
+ self.deaduntil = 0
+ return 0
+
+ def connect(self):
+ if self._get_socket():
+ return 1
+ return 0
+
+ def mark_dead(self, reason):
+ self.debuglog("MemCache: %s: %s. Marking dead." % (self, reason))
+ self.deaduntil = time.time() + _Host._DEAD_RETRY
+ self.close_socket()
+
+ def _get_socket(self):
+ if self._check_dead():
+ return None
+ if self.socket:
+ return self.socket
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ # Python 2.3-ism: s.settimeout(1)
+ try:
+ s.connect((self.ip, self.port))
+ except socket.error, msg:
+ self.mark_dead("connect: %s" % msg[1])
+ return None
+ self.socket = s
+ return s
+
+ def close_socket(self):
+ if self.socket:
+ self.socket.close()
+ self.socket = None
+
+ def send_cmd(self, cmd):
+ if len(cmd) > 100:
+ self.socket.sendall(cmd)
+ self.socket.sendall('\r\n')
+ else:
+ self.socket.sendall(cmd + '\r\n')
+
+ def readline(self):
+ buffers = ''
+ recv = self.socket.recv
+ while 1:
+ data = recv(1)
+ if not data:
+ self.mark_dead('Connection closed while reading from %s'
+ % repr(self))
+ break
+ if data == '\n' and buffers and buffers[-1] == '\r':
+ return(buffers[:-1])
+ buffers = buffers + data
+ return(buffers)
+
+ def expect(self, text):
+ line = self.readline()
+ if line != text:
+ self.debuglog("while expecting '%s', got unexpected response '%s'" % (text, line))
+ return line
+
+ def recv(self, rlen):
+ buf = ''
+ recv = self.socket.recv
+ while len(buf) < rlen:
+ buf = buf + recv(rlen - len(buf))
+ return buf
+
+ def __str__(self):
+ d = ''
+ if self.deaduntil:
+ d = " (dead until %d)" % self.deaduntil
+ return "%s:%d%s" % (self.ip, self.port, d)
+
+def _doctest():
+ import doctest, memcache
+ servers = ["127.0.0.1:11211"]
+ mc = Client(servers, debug=1)
+ globs = {"mc": mc}
+ return doctest.testmod(memcache, globs=globs)
+
+if __name__ == "__main__":
+ print "Testing docstrings..."
+ _doctest()
+ print "Running tests:"
+ print
+ #servers = ["127.0.0.1:11211", "127.0.0.1:11212"]
+ servers = ["127.0.0.1:11211"]
+ mc = Client(servers, debug=1)
+
+ def to_s(val):
+ if not isinstance(val, types.StringTypes):
+ return "%s (%s)" % (val, type(val))
+ return "%s" % val
+ def test_setget(key, val):
+ print "Testing set/get {'%s': %s} ..." % (to_s(key), to_s(val)),
+ mc.set(key, val)
+ newval = mc.get(key)
+ if newval == val:
+ print "OK"
+ return 1
+ else:
+ print "FAIL"
+ return 0
+
+ class FooStruct:
+ def __init__(self):
+ self.bar = "baz"
+ def __str__(self):
+ return "A FooStruct"
+ def __eq__(self, other):
+ if isinstance(other, FooStruct):
+ return self.bar == other.bar
+ return 0
+
+ test_setget("a_string", "some random string")
+ test_setget("an_integer", 42)
+ if test_setget("long", long(1<<30)):
+ print "Testing delete ...",
+ if mc.delete("long"):
+ print "OK"
+ else:
+ print "FAIL"
+ print "Testing get_multi ...",
+ print mc.get_multi(["a_string", "an_integer"])
+
+ print "Testing get(unknown value) ...",
+ print to_s(mc.get("unknown_value"))
+
+ f = FooStruct()
+ test_setget("foostruct", f)
+
+ print "Testing incr ...",
+ x = mc.incr("an_integer", 1)
+ if x == 43:
+ print "OK"
+ else:
+ print "FAIL"
+
+ print "Testing decr ...",
+ x = mc.decr("an_integer", 1)
+ if x == 42:
+ print "OK"
+ else:
+ print "FAIL"
+
+
+
+# vim: ts=4 sw=4 et :
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/statprof.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/statprof.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Utils/statprof.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,304 @@
+## statprof.py
+## Copyright (C) 2004,2005 Andy Wingo <wingo at pobox dot com>
+## Copyright (C) 2001 Rob Browning <rlb at defaultvalue dot org>
+
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this program; if not, contact:
+##
+## Free Software Foundation Voice: +1-617-542-5942
+## 59 Temple Place - Suite 330 Fax: +1-617-542-2652
+## Boston, MA 02111-1307, USA gnu at gnu.org
+
+"""
+statprof is intended to be a fairly simple statistical profiler for
+python. It was ported directly from a statistical profiler for guile,
+also named statprof, available from guile-lib [0].
+
+[0] http://wingolog.org/software/guile-lib/statprof/
+
+To start profiling, call statprof.start():
+>>> start()
+
+Then run whatever it is that you want to profile, for example:
+>>> import test.pystone; test.pystone.pystones()
+
+Then stop the profiling and print out the results:
+>>> stop()
+>>> display()
+ % cumulative self
+ time seconds seconds name
+ 26.72 1.40 0.37 pystone.py:79:Proc0
+ 13.79 0.56 0.19 pystone.py:133:Proc1
+ 13.79 0.19 0.19 pystone.py:208:Proc8
+ 10.34 0.16 0.14 pystone.py:229:Func2
+ 6.90 0.10 0.10 pystone.py:45:__init__
+ 4.31 0.16 0.06 pystone.py:53:copy
+ ...
+
+All of the numerical data with the exception of the calls column is
+statistically approximate. In the following column descriptions, and
+in all of statprof, "time" refers to execution time (both user and
+system), not wall clock time.
+
+% time
+ The percent of the time spent inside the procedure itself (not
+ counting children).
+
+cumulative seconds
+ The total number of seconds spent in the procedure, including
+ children.
+
+self seconds
+ The total number of seconds spent in the procedure itself (not
+ counting children).
+
+name
+ The name of the procedure.
+
+By default statprof keeps the data collected from previous runs. If you
+want to clear the collected data, call reset():
+>>> reset()
+
+reset() can also be used to change the sampling frequency. For example,
+to tell statprof to sample 50 times a second:
+>>> reset(50)
+
+This means that statprof will sample the call stack after every 1/50 of
+a second of user + system time spent running on behalf of the python
+process. When your process is idle (for example, blocking in a read(),
+as is the case at the listener), the clock does not advance. For this
+reason statprof is not currently not suitable for profiling io-bound
+operations.
+
+The profiler uses the hash of the code object itself to identify the
+procedures, so it won't confuse different procedures with the same name.
+They will show up as two different rows in the output.
+
+Right now the profiler is quite simplistic. I cannot provide
+call-graphs or other higher level information. What you see in the
+table is pretty much all there is. Patches are welcome :-)
+
+
+Threading
+---------
+
+Because signals only get delivered to the main thread in Python,
+statprof only profiles the main thread. However because the time
+reporting function uses per-process timers, the results can be
+significantly off if other threads' work patterns are not similar to the
+main thread's work patterns.
+
+
+Implementation notes
+--------------------
+
+The profiler works by setting the unix profiling signal ITIMER_PROF to
+go off after the interval you define in the call to reset(). When the
+signal fires, a sampling routine is run which looks at the current
+procedure that's executing, and then crawls up the stack, and for each
+frame encountered, increments that frame's code object's sample count.
+Note that if a procedure is encountered multiple times on a given stack,
+it is only counted once. After the sampling is complete, the profiler
+resets profiling timer to fire again after the appropriate interval.
+
+Meanwhile, the profiler keeps track, via os.times(), how much CPU time
+(system and user -- which is also what ITIMER_PROF tracks), has elapsed
+while code has been executing within a start()/stop() block.
+
+The profiler also tries to avoid counting or timing its own code as
+much as possible.
+"""
+
+
+from __future__ import division
+
+try:
+ import itimer
+except ImportError:
+ raise ImportError('''statprof requires the itimer python extension.
+To install it, enter the following commands from a terminal:
+
+wget http://www.cute.fi/~torppa/py-itimer/py-itimer.tar.gz
+tar zxvf py-itimer.tar.gz
+cd py-itimer
+sudo python setup.py install
+''')
+
+import signal
+import os
+
+
+__all__ = ['start', 'stop', 'reset', 'display']
+
+
+###########################################################################
+## Utils
+
+def clock():
+ times = os.times()
+ return times[0] + times[1]
+
+
+###########################################################################
+## Collection data structures
+
+class ProfileState(object):
+ def __init__(self, frequency=None):
+ self.reset(frequency)
+
+ def reset(self, frequency=None):
+ # total so far
+ self.accumulated_time = 0.0
+ # start_time when timer is active
+ self.last_start_time = None
+ # total count of sampler calls
+ self.sample_count = 0
+ # a float
+ if frequency:
+ self.sample_interval = 1.0/frequency
+ elif not hasattr(self, 'sample_interval'):
+ # default to 100 Hz
+ self.sample_interval = 1.0/100.0
+ else:
+ # leave the frequency as it was
+ pass
+ self.remaining_prof_time = None
+ # for user start/stop nesting
+ self.profile_level = 0
+ # whether to catch apply-frame
+ self.count_calls = False
+ # gc time between start() and stop()
+ self.gc_time_taken = 0
+
+ def accumulate_time(self, stop_time):
+ self.accumulated_time += stop_time - self.last_start_time
+
+state = ProfileState()
+
+## call_data := { code object: CallData }
+call_data = {}
+class CallData(object):
+ def __init__(self, code):
+ self.name = code.co_name
+ self.filename = code.co_filename
+ self.lineno = code.co_firstlineno
+ self.call_count = 0
+ self.cum_sample_count = 0
+ self.self_sample_count = 0
+ call_data[code] = self
+
+def get_call_data(code):
+ return call_data.get(code, None) or CallData(code)
+
+
+###########################################################################
+## SIGPROF handler
+
+def sample_stack_procs(frame):
+ state.sample_count += 1
+ get_call_data(frame.f_code).self_sample_count += 1
+
+ code_seen = {}
+ while frame:
+ code_seen[frame.f_code] = True
+ frame = frame.f_back
+ for code in code_seen.iterkeys():
+ get_call_data(code).cum_sample_count += 1
+
+def profile_signal_handler(signum, frame):
+ if state.profile_level > 0:
+ state.accumulate_time(clock())
+ sample_stack_procs(frame)
+ itimer.setitimer(itimer.ITIMER_PROF,
+ state.sample_interval, 0.0)
+ state.last_start_time = clock()
+
+
+###########################################################################
+## Profiling API
+
+def is_active():
+ return state.profile_level > 0
+
+def start():
+ state.profile_level += 1
+ if state.profile_level == 1:
+ state.last_start_time = clock()
+ rpt = state.remaining_prof_time
+ state.remaining_prof_time = None
+ signal.signal(signal.SIGPROF, profile_signal_handler)
+ itimer.setitimer(itimer.ITIMER_PROF,
+ rpt or state.sample_interval, 0.0)
+ state.gc_time_taken = 0 # dunno
+
+def stop():
+ state.profile_level -= 1
+ if state.profile_level == 0:
+ state.accumulate_time(clock())
+ state.last_start_time = None
+ rpt = itimer.setitimer(itimer.ITIMER_PROF, 0.0, 0.0)
+ signal.signal(signal.SIGPROF, signal.SIG_IGN)
+ state.remaining_prof_time = rpt[0]
+ state.gc_time_taken = 0 # dunno
+
+def reset(frequency=None):
+ assert state.profile_level == 0, "Can't reset() while statprof is running"
+ call_data.clear()
+ state.reset(frequency)
+
+
+###########################################################################
+## Reporting API
+
+class CallStats(object):
+ def __init__(self, call_data):
+ self_samples = call_data.self_sample_count
+ cum_samples = call_data.cum_sample_count
+ nsamples = state.sample_count
+ secs_per_sample = state.accumulated_time / nsamples
+ basename = os.path.basename(call_data.filename)
+
+ self.name = '%s:%d:%s' % (basename, call_data.lineno, call_data.name)
+ self.pcnt_time_in_proc = self_samples / nsamples * 100
+ self.cum_secs_in_proc = cum_samples * secs_per_sample
+ self.self_secs_in_proc = self_samples * secs_per_sample
+ self.num_calls = None
+ self.self_secs_per_call = None
+ self.cum_secs_per_call = None
+
+ def display(self):
+ print '%6.2f %9.2f %9.2f %s' % (self.pcnt_time_in_proc,
+ self.cum_secs_in_proc,
+ self.self_secs_in_proc,
+ self.name)
+
+
+def display():
+ if state.sample_count == 0:
+ print 'No samples recorded.'
+ return
+
+ l = [CallStats(x) for x in call_data.itervalues()]
+ l = [(x.self_secs_in_proc, x.cum_secs_in_proc, x) for x in l]
+ l.sort(reverse=True)
+ l = [x[2] for x in l]
+
+ print '%5.5s %10.10s %7.7s %-8.8s' % ('% ', 'cumulative', 'self', '')
+ print '%5.5s %9.9s %8.8s %-8.8s' % ("time", "seconds", "seconds", "name")
+
+ for x in l:
+ x.display()
+
+ print '---'
+ print 'Sample count: %d' % state.sample_count
+ print 'Total time: %f seconds' % state.accumulated_time
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Version.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Version.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/Version.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,58 @@
+Version = '2.2.1'
+VersionTuple = (2, 2, 1,'final', 0)
+
+MinCompatibleVersion = '2.0rc6'
+MinCompatibleVersionTuple = (2,0,0,'candidate',6)
+
+####
+def convertVersionStringToTuple(s):
+ versionNum = [0,0,0]
+ releaseType = 'final'
+ releaseTypeSubNum = 0
+ if s.find('a')!=-1:
+ num, releaseTypeSubNum = s.split('a')
+ releaseType = 'alpha'
+ elif s.find('b')!=-1:
+ num, releaseTypeSubNum = s.split('b')
+ releaseType = 'beta'
+ elif s.find('rc')!=-1:
+ num, releaseTypeSubNum = s.split('rc')
+ releaseType = 'candidate'
+ else:
+ num = s
+ num = num.split('.')
+ for i in range(len(num)):
+ versionNum[i] = int(num[i])
+ if len(versionNum)<3:
+ versionNum += [0]
+ releaseTypeSubNum = int(releaseTypeSubNum)
+
+ return tuple(versionNum+[releaseType,releaseTypeSubNum])
+
+
+if __name__ == '__main__':
+ c = convertVersionStringToTuple
+ print c('2.0a1')
+ print c('2.0b1')
+ print c('2.0rc1')
+ print c('2.0')
+ print c('2.0.2')
+
+
+ assert c('0.9.19b1') < c('0.9.19')
+ assert c('0.9b1') < c('0.9.19')
+
+ assert c('2.0a2') > c('2.0a1')
+ assert c('2.0b1') > c('2.0a2')
+ assert c('2.0b2') > c('2.0b1')
+ assert c('2.0b2') == c('2.0b2')
+
+ assert c('2.0rc1') > c('2.0b1')
+ assert c('2.0rc2') > c('2.0rc1')
+ assert c('2.0rc2') > c('2.0b1')
+
+ assert c('2.0') > c('2.0a1')
+ assert c('2.0') > c('2.0b1')
+ assert c('2.0') > c('2.0rc1')
+ assert c('2.0.1') > c('2.0')
+ assert c('2.0rc1') > c('2.0b1')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+'''
+Cheetah is an open source template engine and code generation tool.
+
+It can be used standalone or combined with other tools and frameworks. Web
+development is its principle use, but Cheetah is very flexible and is also being
+used to generate C++ game code, Java, sql, form emails and even Python code.
+
+Homepage
+ http://www.cheetahtemplate.org/
+
+Documentation
+ http://cheetahtemplate.org/learn.html
+
+Mailing list
+cheetahtemplate-discuss at lists.sourceforge.net
+Subscribe at
+ http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss
+'''
+
+from Version import *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+def __bootstrap__():
+ global __bootstrap__, __loader__, __file__
+ import sys, pkg_resources, imp
+ __file__ = pkg_resources.resource_filename(__name__,'_namemapper.so')
+ __loader__ = None; del __bootstrap__, __loader__
+ imp.load_dynamic(__name__,__file__)
+__bootstrap__()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.so
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/_namemapper.so
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,603 @@
+"""
+Python Markdown
+===============
+
+Python Markdown converts Markdown to HTML and can be used as a library or
+called from the command line.
+
+## Basic usage as a module:
+
+ import markdown
+ md = Markdown()
+ html = md.convert(your_text_string)
+
+## Basic use from the command line:
+
+ python markdown.py source.txt > destination.html
+
+Run "python markdown.py --help" to see more options.
+
+## Extensions
+
+See <http://www.freewisdom.org/projects/python-markdown/> for more
+information and instructions on how to extend the functionality of
+Python Markdown. Read that before you try modifying this file.
+
+## Authors and License
+
+Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
+maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
+Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
+
+Contact: markdown at freewisdom.org
+
+Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
+Copyright 200? Django Software Foundation (OrderedDict implementation)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see docs/LICENSE for details).
+"""
+
+version = "2.0-rc2"
+version_info = (2,0,0, "rc2")
+
+import re
+import codecs
+import sys
+import warnings
+import logging
+from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
+
+
+"""
+CONSTANTS
+=============================================================================
+"""
+
+"""
+Constants you might want to modify
+-----------------------------------------------------------------------------
+"""
+
+# default logging level for command-line use
+COMMAND_LINE_LOGGING_LEVEL = CRITICAL
+TAB_LENGTH = 4 # expand tabs to this many spaces
+ENABLE_ATTRIBUTES = True # @id = xyz -> <... id="xyz">
+SMART_EMPHASIS = True # this_or_that does not become this<i>or</i>that
+DEFAULT_OUTPUT_FORMAT = 'xhtml1' # xhtml or html4 output
+HTML_REMOVED_TEXT = "[HTML_REMOVED]" # text used instead of HTML in safe mode
+BLOCK_LEVEL_ELEMENTS = re.compile("p|div|h[1-6]|blockquote|pre|table|dl|ol|ul"
+ "|script|noscript|form|fieldset|iframe|math"
+ "|ins|del|hr|hr/|style|li|dt|dd|thead|tbody"
+ "|tr|th|td")
+DOC_TAG = "div" # Element used to wrap document - later removed
+
+# Placeholders
+STX = u'\u0002' # Use STX ("Start of text") for start-of-placeholder
+ETX = u'\u0003' # Use ETX ("End of text") for end-of-placeholder
+INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:"
+INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX
+AMP_SUBSTITUTE = STX+"amp"+ETX
+
+
+"""
+Constants you probably do not need to change
+-----------------------------------------------------------------------------
+"""
+
+RTL_BIDI_RANGES = ( (u'\u0590', u'\u07FF'),
+ # Hebrew (0590-05FF), Arabic (0600-06FF),
+ # Syriac (0700-074F), Arabic supplement (0750-077F),
+ # Thaana (0780-07BF), Nko (07C0-07FF).
+ (u'\u2D30', u'\u2D7F'), # Tifinagh
+ )
+
+
+"""
+AUXILIARY GLOBAL FUNCTIONS
+=============================================================================
+"""
+
+
+def message(level, text):
+ """ A wrapper method for logging debug messages. """
+ logger = logging.getLogger('MARKDOWN')
+ if logger.handlers:
+ # The logger is configured
+ logger.log(level, text)
+ if level > WARN:
+ sys.exit(0)
+ elif level > WARN:
+ raise MarkdownException, text
+ else:
+ warnings.warn(text, MarkdownWarning)
+
+
+def isBlockLevel(tag):
+ """Check if the tag is a block level HTML tag."""
+ return BLOCK_LEVEL_ELEMENTS.match(tag)
+
+"""
+MISC AUXILIARY CLASSES
+=============================================================================
+"""
+
+class AtomicString(unicode):
+ """A string which should not be further processed."""
+ pass
+
+
+class MarkdownException(Exception):
+ """ A Markdown Exception. """
+ pass
+
+
+class MarkdownWarning(Warning):
+ """ A Markdown Warning. """
+ pass
+
+
+"""
+OVERALL DESIGN
+=============================================================================
+
+Markdown processing takes place in four steps:
+
+1. A bunch of "preprocessors" munge the input text.
+2. BlockParser() parses the high-level structural elements of the
+ pre-processed text into an ElementTree.
+3. A bunch of "treeprocessors" are run against the ElementTree. One such
+ treeprocessor runs InlinePatterns against the ElementTree, detecting inline
+ markup.
+4. Some post-processors are run against the text after the ElementTree has
+ been serialized into text.
+5. The output is written to a string.
+
+Those steps are put together by the Markdown() class.
+
+"""
+
+import preprocessors
+import blockprocessors
+import treeprocessors
+import inlinepatterns
+import postprocessors
+import blockparser
+import etree_loader
+import odict
+
+# Extensions should use "markdown.etree" instead of "etree" (or do `from
+# markdown import etree`). Do not import it by yourself.
+
+etree = etree_loader.importETree()
+
+# Adds the ability to output html4
+import html4
+
+
+class Markdown:
+ """Convert Markdown to HTML."""
+
+ def __init__(self,
+ extensions=[],
+ extension_configs={},
+ safe_mode = False,
+ output_format=DEFAULT_OUTPUT_FORMAT):
+ """
+ Creates a new Markdown instance.
+
+ Keyword arguments:
+
+ * extensions: A list of extensions.
+ If they are of type string, the module mdx_name.py will be loaded.
+ If they are a subclass of markdown.Extension, they will be used
+ as-is.
+ * extension-configs: Configuration setting for extensions.
+ * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
+ * output_format: Format of output. Supported formats are:
+ * "xhtml1": Outputs XHTML 1.x. Default.
+ * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
+ * "html4": Outputs HTML 4
+ * "html": Outputs latest supported version of HTML (currently HTML 4).
+ Note that it is suggested that the more specific formats ("xhtml1"
+ and "html4") be used as "xhtml" or "html" may change in the future
+ if it makes sense at that time.
+
+ """
+
+ self.safeMode = safe_mode
+ self.registeredExtensions = []
+ self.docType = ""
+ self.stripTopLevelTags = True
+
+ # Preprocessors
+ self.preprocessors = odict.OrderedDict()
+ self.preprocessors["html_block"] = \
+ preprocessors.HtmlBlockPreprocessor(self)
+ self.preprocessors["reference"] = \
+ preprocessors.ReferencePreprocessor(self)
+ # footnote preprocessor will be inserted with "<reference"
+
+ # Block processors - ran by the parser
+ self.parser = blockparser.BlockParser()
+ self.parser.blockprocessors['empty'] = \
+ blockprocessors.EmptyBlockProcessor(self.parser)
+ self.parser.blockprocessors['indent'] = \
+ blockprocessors.ListIndentProcessor(self.parser)
+ self.parser.blockprocessors['code'] = \
+ blockprocessors.CodeBlockProcessor(self.parser)
+ self.parser.blockprocessors['hashheader'] = \
+ blockprocessors.HashHeaderProcessor(self.parser)
+ self.parser.blockprocessors['setextheader'] = \
+ blockprocessors.SetextHeaderProcessor(self.parser)
+ self.parser.blockprocessors['hr'] = \
+ blockprocessors.HRProcessor(self.parser)
+ self.parser.blockprocessors['olist'] = \
+ blockprocessors.OListProcessor(self.parser)
+ self.parser.blockprocessors['ulist'] = \
+ blockprocessors.UListProcessor(self.parser)
+ self.parser.blockprocessors['quote'] = \
+ blockprocessors.BlockQuoteProcessor(self.parser)
+ self.parser.blockprocessors['paragraph'] = \
+ blockprocessors.ParagraphProcessor(self.parser)
+
+
+ #self.prePatterns = []
+
+ # Inline patterns - Run on the tree
+ self.inlinePatterns = odict.OrderedDict()
+ self.inlinePatterns["backtick"] = \
+ inlinepatterns.BacktickPattern(inlinepatterns.BACKTICK_RE)
+ self.inlinePatterns["escape"] = \
+ inlinepatterns.SimpleTextPattern(inlinepatterns.ESCAPE_RE)
+ self.inlinePatterns["reference"] = \
+ inlinepatterns.ReferencePattern(inlinepatterns.REFERENCE_RE, self)
+ self.inlinePatterns["link"] = \
+ inlinepatterns.LinkPattern(inlinepatterns.LINK_RE, self)
+ self.inlinePatterns["image_link"] = \
+ inlinepatterns.ImagePattern(inlinepatterns.IMAGE_LINK_RE, self)
+ self.inlinePatterns["image_reference"] = \
+ inlinepatterns.ImageReferencePattern(inlinepatterns.IMAGE_REFERENCE_RE, self)
+ self.inlinePatterns["autolink"] = \
+ inlinepatterns.AutolinkPattern(inlinepatterns.AUTOLINK_RE, self)
+ self.inlinePatterns["automail"] = \
+ inlinepatterns.AutomailPattern(inlinepatterns.AUTOMAIL_RE, self)
+ self.inlinePatterns["linebreak2"] = \
+ inlinepatterns.SubstituteTagPattern(inlinepatterns.LINE_BREAK_2_RE, 'br')
+ self.inlinePatterns["linebreak"] = \
+ inlinepatterns.SubstituteTagPattern(inlinepatterns.LINE_BREAK_RE, 'br')
+ self.inlinePatterns["html"] = \
+ inlinepatterns.HtmlPattern(inlinepatterns.HTML_RE, self)
+ self.inlinePatterns["entity"] = \
+ inlinepatterns.HtmlPattern(inlinepatterns.ENTITY_RE, self)
+ self.inlinePatterns["not_strong"] = \
+ inlinepatterns.SimpleTextPattern(inlinepatterns.NOT_STRONG_RE)
+ self.inlinePatterns["strong_em"] = \
+ inlinepatterns.DoubleTagPattern(inlinepatterns.STRONG_EM_RE, 'strong,em')
+ self.inlinePatterns["strong"] = \
+ inlinepatterns.SimpleTagPattern(inlinepatterns.STRONG_RE, 'strong')
+ self.inlinePatterns["emphasis"] = \
+ inlinepatterns.SimpleTagPattern(inlinepatterns.EMPHASIS_RE, 'em')
+ self.inlinePatterns["emphasis2"] = \
+ inlinepatterns.SimpleTagPattern(inlinepatterns.EMPHASIS_2_RE, 'em')
+ # The order of the handlers matters!!!
+
+
+ # Tree processors - run once we have a basic parse.
+ self.treeprocessors = odict.OrderedDict()
+ self.treeprocessors["inline"] = treeprocessors.InlineProcessor(self)
+ self.treeprocessors["prettify"] = \
+ treeprocessors.PrettifyTreeprocessor(self)
+
+ # Postprocessors - finishing touches.
+ self.postprocessors = odict.OrderedDict()
+ self.postprocessors["raw_html"] = \
+ postprocessors.RawHtmlPostprocessor(self)
+ self.postprocessors["amp_substitute"] = \
+ postprocessors.AndSubstitutePostprocessor()
+ # footnote postprocessor will be inserted with ">amp_substitute"
+
+ # Map format keys to serializers
+ self.output_formats = {
+ 'html' : html4.to_html_string,
+ 'html4' : html4.to_html_string,
+ 'xhtml' : etree.tostring,
+ 'xhtml1': etree.tostring,
+ }
+
+ self.references = {}
+ self.htmlStash = preprocessors.HtmlStash()
+ self.registerExtensions(extensions = extensions,
+ configs = extension_configs)
+ self.set_output_format(output_format)
+ self.reset()
+
+ def registerExtensions(self, extensions, configs):
+ """
+ Register extensions with this instance of Markdown.
+
+ Keyword aurguments:
+
+ * extensions: A list of extensions, which can either
+ be strings or objects. See the docstring on Markdown.
+ * configs: A dictionary mapping module names to config options.
+
+ """
+ for ext in extensions:
+ if isinstance(ext, basestring):
+ ext = load_extension(ext, configs.get(ext, []))
+ try:
+ ext.extendMarkdown(self, globals())
+ except AttributeError:
+ message(ERROR, "Incorrect type! Extension '%s' is "
+ "neither a string or an Extension." %(repr(ext)))
+
+
+ def registerExtension(self, extension):
+ """ This gets called by the extension """
+ self.registeredExtensions.append(extension)
+
+ def reset(self):
+ """
+ Resets all state variables so that we can start with a new text.
+ """
+ self.htmlStash.reset()
+ self.references.clear()
+
+ for extension in self.registeredExtensions:
+ extension.reset()
+
+ def set_output_format(self, format):
+ """ Set the output format for the class instance. """
+ try:
+ self.serializer = self.output_formats[format.lower()]
+ except KeyError:
+ message(CRITICAL, 'Invalid Output Format: "%s". Use one of %s.' \
+ % (format, self.output_formats.keys()))
+
+ def convert(self, source):
+ """
+ Convert markdown to serialized XHTML or HTML.
+
+ Keyword arguments:
+
+ * source: Source text as a Unicode string.
+
+ """
+
+ # Fixup the source text
+ if not source.strip():
+ return u"" # a blank unicode string
+ try:
+ source = unicode(source)
+ except UnicodeDecodeError:
+ message(CRITICAL, 'UnicodeDecodeError: Markdown only accepts unicode or ascii input.')
+ return u""
+
+ source = source.replace(STX, "").replace(ETX, "")
+ source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n"
+ source = re.sub(r'\n\s+\n', '\n\n', source)
+ source = source.expandtabs(TAB_LENGTH)
+
+ # Split into lines and run the line preprocessors.
+ self.lines = source.split("\n")
+ for prep in self.preprocessors.values():
+ self.lines = prep.run(self.lines)
+
+ # Parse the high-level elements.
+ root = self.parser.parseDocument(self.lines).getroot()
+
+ # Run the tree-processors
+ for treeprocessor in self.treeprocessors.values():
+ newRoot = treeprocessor.run(root)
+ if newRoot:
+ root = newRoot
+
+ # Serialize _properly_. Strip top-level tags.
+ output, length = codecs.utf_8_decode(self.serializer(root, encoding="utf8"))
+ if self.stripTopLevelTags:
+ start = output.index('<%s>'%DOC_TAG)+len(DOC_TAG)+2
+ end = output.rindex('</%s>'%DOC_TAG)
+ output = output[start:end].strip()
+
+ # Run the text post-processors
+ for pp in self.postprocessors.values():
+ output = pp.run(output)
+
+ return output.strip()
+
+ def convertFile(self, input=None, output=None, encoding=None):
+ """Converts a markdown file and returns the HTML as a unicode string.
+
+ Decodes the file using the provided encoding (defaults to utf-8),
+ passes the file content to markdown, and outputs the html to either
+ the provided stream or the file with provided name, using the same
+ encoding as the source file.
+
+ **Note:** This is the only place that decoding and encoding of unicode
+ takes place in Python-Markdown. (All other code is unicode-in /
+ unicode-out.)
+
+ Keyword arguments:
+
+ * input: Name of source text file.
+ * output: Name of output file. Writes to stdout if `None`.
+ * encoding: Encoding of input and output files. Defaults to utf-8.
+
+ """
+
+ encoding = encoding or "utf-8"
+
+ # Read the source
+ input_file = codecs.open(input, mode="r", encoding=encoding)
+ text = input_file.read()
+ input_file.close()
+ text = text.lstrip(u'\ufeff') # remove the byte-order mark
+
+ # Convert
+ html = self.convert(text)
+
+ # Write to file or stdout
+ if isinstance(output, (str, unicode)):
+ output_file = codecs.open(output, "w", encoding=encoding)
+ output_file.write(html)
+ output_file.close()
+ else:
+ output.write(html.encode(encoding))
+
+
+"""
+Extensions
+-----------------------------------------------------------------------------
+"""
+
+class Extension:
+ """ Base class for extensions to subclass. """
+ def __init__(self, configs = {}):
+ """Create an instance of an Extention.
+
+ Keyword arguments:
+
+ * configs: A dict of configuration setting used by an Extension.
+ """
+ self.config = configs
+
+ def getConfig(self, key):
+ """ Return a setting for the given key or an empty string. """
+ if key in self.config:
+ return self.config[key][0]
+ else:
+ return ""
+
+ def getConfigInfo(self):
+ """ Return all config settings as a list of tuples. """
+ return [(key, self.config[key][1]) for key in self.config.keys()]
+
+ def setConfig(self, key, value):
+ """ Set a config setting for `key` with the given `value`. """
+ self.config[key][0] = value
+
+ def extendMarkdown(self, md, md_globals):
+ """
+ Add the various proccesors and patterns to the Markdown Instance.
+
+ This method must be overriden by every extension.
+
+ Keyword arguments:
+
+ * md: The Markdown instance.
+
+ * md_globals: Global variables in the markdown module namespace.
+
+ """
+ pass
+
+
+def load_extension(ext_name, configs = []):
+ """Load extension by name, then return the module.
+
+ The extension name may contain arguments as part of the string in the
+ following format: "extname(key1=value1,key2=value2)"
+
+ """
+
+ # Parse extensions config params (ignore the order)
+ configs = dict(configs)
+ pos = ext_name.find("(") # find the first "("
+ if pos > 0:
+ ext_args = ext_name[pos+1:-1]
+ ext_name = ext_name[:pos]
+ pairs = [x.split("=") for x in ext_args.split(",")]
+ configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
+
+ # Setup the module names
+ ext_module = 'markdown.extensions'
+ module_name_new_style = '.'.join([ext_module, ext_name])
+ module_name_old_style = '_'.join(['mdx', ext_name])
+
+ # Try loading the extention first from one place, then another
+ try: # New style (markdown.extensons.<extension>)
+ module = __import__(module_name_new_style, {}, {}, [ext_module])
+ except ImportError:
+ try: # Old style (mdx.<extension>)
+ module = __import__(module_name_old_style)
+ except ImportError:
+ message(WARN, "Failed loading extension '%s' from '%s' or '%s'"
+ % (ext_name, module_name_new_style, module_name_old_style))
+ # Return None so we don't try to initiate none-existant extension
+ return None
+
+ # If the module is loaded successfully, we expect it to define a
+ # function called makeExtension()
+ try:
+ return module.makeExtension(configs.items())
+ except AttributeError:
+ message(CRITICAL, "Failed to initiate extension '%s'" % ext_name)
+
+
+def load_extensions(ext_names):
+ """Loads multiple extensions"""
+ extensions = []
+ for ext_name in ext_names:
+ extension = load_extension(ext_name)
+ if extension:
+ extensions.append(extension)
+ return extensions
+
+
+"""
+EXPORTED FUNCTIONS
+=============================================================================
+
+Those are the two functions we really mean to export: markdown() and
+markdownFromFile().
+"""
+
+def markdown(text,
+ extensions = [],
+ safe_mode = False,
+ output_format = DEFAULT_OUTPUT_FORMAT):
+ """Convert a markdown string to HTML and return HTML as a unicode string.
+
+ This is a shortcut function for `Markdown` class to cover the most
+ basic use case. It initializes an instance of Markdown, loads the
+ necessary extensions and runs the parser on the given text.
+
+ Keyword arguments:
+
+ * text: Markdown formatted text as Unicode or ASCII string.
+ * extensions: A list of extensions or extension names (may contain config args).
+ * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
+ * output_format: Format of output. Supported formats are:
+ * "xhtml1": Outputs XHTML 1.x. Default.
+ * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
+ * "html4": Outputs HTML 4
+ * "html": Outputs latest supported version of HTML (currently HTML 4).
+ Note that it is suggested that the more specific formats ("xhtml1"
+ and "html4") be used as "xhtml" or "html" may change in the future
+ if it makes sense at that time.
+
+ Returns: An HTML document as a string.
+
+ """
+ md = Markdown(extensions=load_extensions(extensions),
+ safe_mode=safe_mode,
+ output_format=output_format)
+ return md.convert(text)
+
+
+def markdownFromFile(input = None,
+ output = None,
+ extensions = [],
+ encoding = None,
+ safe_mode = False,
+ output_format = DEFAULT_OUTPUT_FORMAT):
+ """Read markdown code from a file and write it to a file or a stream."""
+ md = Markdown(extensions=load_extensions(extensions),
+ safe_mode=safe_mode,
+ output_format=output_format)
+ md.convertFile(input, output, encoding)
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockparser.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockparser.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockparser.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,95 @@
+
+import markdown
+
+class State(list):
+ """ Track the current and nested state of the parser.
+
+ This utility class is used to track the state of the BlockParser and
+ support multiple levels if nesting. It's just a simple API wrapped around
+ a list. Each time a state is set, that state is appended to the end of the
+ list. Each time a state is reset, that state is removed from the end of
+ the list.
+
+ Therefore, each time a state is set for a nested block, that state must be
+ reset when we back out of that level of nesting or the state could be
+ corrupted.
+
+ While all the methods of a list object are available, only the three
+ defined below need be used.
+
+ """
+
+ def set(self, state):
+ """ Set a new state. """
+ self.append(state)
+
+ def reset(self):
+ """ Step back one step in nested state. """
+ self.pop()
+
+ def isstate(self, state):
+ """ Test that top (current) level is of given state. """
+ if len(self):
+ return self[-1] == state
+ else:
+ return False
+
+class BlockParser:
+ """ Parse Markdown blocks into an ElementTree object.
+
+ A wrapper class that stitches the various BlockProcessors together,
+ looping through them and creating an ElementTree object.
+ """
+
+ def __init__(self):
+ self.blockprocessors = markdown.odict.OrderedDict()
+ self.state = State()
+
+ def parseDocument(self, lines):
+ """ Parse a markdown document into an ElementTree.
+
+ Given a list of lines, an ElementTree object (not just a parent Element)
+ is created and the root element is passed to the parser as the parent.
+ The ElementTree object is returned.
+
+ This should only be called on an entire document, not pieces.
+
+ """
+ # Create a ElementTree from the lines
+ self.root = markdown.etree.Element(markdown.DOC_TAG)
+ self.parseChunk(self.root, '\n'.join(lines))
+ return markdown.etree.ElementTree(self.root)
+
+ def parseChunk(self, parent, text):
+ """ Parse a chunk of markdown text and attach to given etree node.
+
+ While the ``text`` argument is generally assumed to contain multiple
+ blocks which will be split on blank lines, it could contain only one
+ block. Generally, this method would be called by extensions when
+ block parsing is required.
+
+ The ``parent`` etree Element passed in is altered in place.
+ Nothing is returned.
+
+ """
+ self.parseBlocks(parent, text.split('\n\n'))
+
+ def parseBlocks(self, parent, blocks):
+ """ Process blocks of markdown text and attach to given etree node.
+
+ Given a list of ``blocks``, each blockprocessor is stepped through
+ until there are no blocks left. While an extension could potentially
+ call this method directly, it's generally expected to be used internally.
+
+ This is a public method as an extension may need to add/alter additional
+ BlockProcessors which call this method to recursively parse a nested
+ block.
+
+ """
+ while blocks:
+ for processor in self.blockprocessors.values():
+ if processor.test(parent, blocks[0]):
+ processor.run(parent, blocks)
+ break
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockprocessors.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockprocessors.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/blockprocessors.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,460 @@
+"""
+CORE MARKDOWN BLOCKPARSER
+=============================================================================
+
+This parser handles basic parsing of Markdown blocks. It doesn't concern itself
+with inline elements such as **bold** or *italics*, but rather just catches
+blocks, lists, quotes, etc.
+
+The BlockParser is made up of a bunch of BlockProssors, each handling a
+different type of block. Extensions may add/replace/remove BlockProcessors
+as they need to alter how markdown blocks are parsed.
+
+"""
+
+import re
+import markdown
+
+class BlockProcessor:
+ """ Base class for block processors.
+
+ Each subclass will provide the methods below to work with the source and
+ tree. Each processor will need to define it's own ``test`` and ``run``
+ methods. The ``test`` method should return True or False, to indicate
+ whether the current block should be processed by this processor. If the
+ test passes, the parser will call the processors ``run`` method.
+
+ """
+
+ def __init__(self, parser=None):
+ self.parser = parser
+
+ def lastChild(self, parent):
+ """ Return the last child of an etree element. """
+ if len(parent):
+ return parent[-1]
+ else:
+ return None
+
+ def detab(self, text):
+ """ Remove a tab from the front of each line of the given text. """
+ newtext = []
+ lines = text.split('\n')
+ for line in lines:
+ if line.startswith(' '*markdown.TAB_LENGTH):
+ newtext.append(line[markdown.TAB_LENGTH:])
+ elif not line.strip():
+ newtext.append('')
+ else:
+ break
+ return '\n'.join(newtext), '\n'.join(lines[len(newtext):])
+
+ def looseDetab(self, text, level=1):
+ """ Remove a tab from front of lines but allowing dedented lines. """
+ lines = text.split('\n')
+ for i in range(len(lines)):
+ if lines[i].startswith(' '*markdown.TAB_LENGTH*level):
+ lines[i] = lines[i][markdown.TAB_LENGTH*level:]
+ return '\n'.join(lines)
+
+ def test(self, parent, block):
+ """ Test for block type. Must be overridden by subclasses.
+
+ As the parser loops through processors, it will call the ``test`` method
+ on each to determine if the given block of text is of that type. This
+ method must return a boolean ``True`` or ``False``. The actual method of
+ testing is left to the needs of that particular block type. It could
+ be as simple as ``block.startswith(some_string)`` or a complex regular
+ expression. As the block type may be different depending on the parent
+ of the block (i.e. inside a list), the parent etree element is also
+ provided and may be used as part of the test.
+
+ Keywords:
+
+ * ``parent``: A etree element which will be the parent of the block.
+ * ``block``: A block of text from the source which has been split at
+ blank lines.
+ """
+ pass
+
+ def run(self, parent, blocks):
+ """ Run processor. Must be overridden by subclasses.
+
+ When the parser determines the appropriate type of a block, the parser
+ will call the corresponding processor's ``run`` method. This method
+ should parse the individual lines of the block and append them to
+ the etree.
+
+ Note that both the ``parent`` and ``etree`` keywords are pointers
+ to instances of the objects which should be edited in place. Each
+ processor must make changes to the existing objects as there is no
+ mechanism to return new/different objects to replace them.
+
+ This means that this method should be adding SubElements or adding text
+ to the parent, and should remove (``pop``) or add (``insert``) items to
+ the list of blocks.
+
+ Keywords:
+
+ * ``parent``: A etree element which is the parent of the current block.
+ * ``blocks``: A list of all remaining blocks of the document.
+ """
+ pass
+
+
+class ListIndentProcessor(BlockProcessor):
+ """ Process children of list items.
+
+ Example:
+ * a list item
+ process this part
+
+ or this part
+
+ """
+
+ INDENT_RE = re.compile(r'^(([ ]{%s})+)'% markdown.TAB_LENGTH)
+ ITEM_TYPES = ['li']
+ LIST_TYPES = ['ul', 'ol']
+
+ def test(self, parent, block):
+ return block.startswith(' '*markdown.TAB_LENGTH) and \
+ not self.parser.state.isstate('detabbed') and \
+ (parent.tag in self.ITEM_TYPES or \
+ (len(parent) and parent[-1] and \
+ (parent[-1].tag in self.LIST_TYPES)
+ )
+ )
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ level, sibling = self.get_level(parent, block)
+ block = self.looseDetab(block, level)
+
+ self.parser.state.set('detabbed')
+ if parent.tag in self.ITEM_TYPES:
+ # The parent is already a li. Just parse the child block.
+ self.parser.parseBlocks(parent, [block])
+ elif sibling.tag in self.ITEM_TYPES:
+ # The sibling is a li. Use it as parent.
+ self.parser.parseBlocks(sibling, [block])
+ elif len(sibling) and sibling[-1].tag in self.ITEM_TYPES:
+ # The parent is a list (``ol`` or ``ul``) which has children.
+ # Assume the last child li is the parent of this block.
+ if sibling[-1].text:
+ # If the parent li has text, that text needs to be moved to a p
+ block = '%s\n\n%s' % (sibling[-1].text, block)
+ sibling[-1].text = ''
+ self.parser.parseChunk(sibling[-1], block)
+ else:
+ self.create_item(sibling, block)
+ self.parser.state.reset()
+
+ def create_item(self, parent, block):
+ """ Create a new li and parse the block with it as the parent. """
+ li = markdown.etree.SubElement(parent, 'li')
+ self.parser.parseBlocks(li, [block])
+
+ def get_level(self, parent, block):
+ """ Get level of indent based on list level. """
+ # Get indent level
+ m = self.INDENT_RE.match(block)
+ if m:
+ indent_level = len(m.group(1))/markdown.TAB_LENGTH
+ else:
+ indent_level = 0
+ if self.parser.state.isstate('list'):
+ # We're in a tightlist - so we already are at correct parent.
+ level = 1
+ else:
+ # We're in a looselist - so we need to find parent.
+ level = 0
+ # Step through children of tree to find matching indent level.
+ while indent_level > level:
+ child = self.lastChild(parent)
+ if child and (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES):
+ if child.tag in self.LIST_TYPES:
+ level += 1
+ parent = child
+ else:
+ # No more child levels. If we're short of indent_level,
+ # we have a code block. So we stop here.
+ break
+ return level, parent
+
+
+class CodeBlockProcessor(BlockProcessor):
+ """ Process code blocks. """
+
+ def test(self, parent, block):
+ return block.startswith(' '*markdown.TAB_LENGTH)
+
+ def run(self, parent, blocks):
+ sibling = self.lastChild(parent)
+ block = blocks.pop(0)
+ theRest = ''
+ if sibling and sibling.tag == "pre" and len(sibling) \
+ and sibling[0].tag == "code":
+ # The previous block was a code block. As blank lines do not start
+ # new code blocks, append this block to the previous, adding back
+ # linebreaks removed from the split into a list.
+ code = sibling[0]
+ block, theRest = self.detab(block)
+ code.text = markdown.AtomicString('%s\n%s\n' % (code.text, block.rstrip()))
+ else:
+ # This is a new codeblock. Create the elements and insert text.
+ pre = markdown.etree.SubElement(parent, 'pre')
+ code = markdown.etree.SubElement(pre, 'code')
+ block, theRest = self.detab(block)
+ code.text = markdown.AtomicString('%s\n' % block.rstrip())
+ if theRest:
+ # This block contained unindented line(s) after the first indented
+ # line. Insert these lines as the first block of the master blocks
+ # list for future processing.
+ blocks.insert(0, theRest)
+
+
+class BlockQuoteProcessor(BlockProcessor):
+
+ RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
+
+ def test(self, parent, block):
+ return bool(self.RE.search(block))
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ before = block[:m.start()] # Lines before blockquote
+ # Pass lines before blockquote in recursively for parsing forst.
+ self.parser.parseBlocks(parent, [before])
+ # Remove ``> `` from begining of each line.
+ block = '\n'.join([self.clean(line) for line in
+ block[m.start():].split('\n')])
+ sibling = self.lastChild(parent)
+ if sibling and sibling.tag == "blockquote":
+ # Previous block was a blockquote so set that as this blocks parent
+ quote = sibling
+ else:
+ # This is a new blockquote. Create a new parent element.
+ quote = markdown.etree.SubElement(parent, 'blockquote')
+ # Recursively parse block with blockquote as parent.
+ self.parser.parseChunk(quote, block)
+
+ def clean(self, line):
+ """ Remove ``>`` from beginning of a line. """
+ m = self.RE.match(line)
+ if line.strip() == ">":
+ return ""
+ elif m:
+ return m.group(2)
+ else:
+ return line
+
+class OListProcessor(BlockProcessor):
+ """ Process ordered list blocks. """
+
+ TAG = 'ol'
+ # Detect an item (``1. item``). ``group(1)`` contains contents of item.
+ RE = re.compile(r'^[ ]{0,3}\d+\.[ ](.*)')
+ # Detect items on secondary lines. they can be of either list type.
+ CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.)|[*+-])[ ](.*)')
+ # Detect indented (nested) items of either type
+ INDENT_RE = re.compile(r'^[ ]{4,7}((\d+\.)|[*+-])[ ].*')
+
+ def test(self, parent, block):
+ return bool(self.RE.match(block))
+
+ def run(self, parent, blocks):
+ # Check fr multiple items in one block.
+ items = self.get_items(blocks.pop(0))
+ sibling = self.lastChild(parent)
+ if sibling and sibling.tag in ['ol', 'ul']:
+ # Previous block was a list item, so set that as parent
+ lst = sibling
+ # make sure previous item is in a p.
+ if len(lst) and lst[-1].text and not len(lst[-1]):
+ p = markdown.etree.SubElement(lst[-1], 'p')
+ p.text = lst[-1].text
+ lst[-1].text = ''
+ # parse first block differently as it gets wrapped in a p.
+ li = markdown.etree.SubElement(lst, 'li')
+ self.parser.state.set('looselist')
+ firstitem = items.pop(0)
+ self.parser.parseBlocks(li, [firstitem])
+ self.parser.state.reset()
+ else:
+ # This is a new list so create parent with appropriate tag.
+ lst = markdown.etree.SubElement(parent, self.TAG)
+ self.parser.state.set('list')
+ # Loop through items in block, recursively parsing each with the
+ # appropriate parent.
+ for item in items:
+ if item.startswith(' '*markdown.TAB_LENGTH):
+ # Item is indented. Parse with last item as parent
+ self.parser.parseBlocks(lst[-1], [item])
+ else:
+ # New item. Create li and parse with it as parent
+ li = markdown.etree.SubElement(lst, 'li')
+ self.parser.parseBlocks(li, [item])
+ self.parser.state.reset()
+
+ def get_items(self, block):
+ """ Break a block into list items. """
+ items = []
+ for line in block.split('\n'):
+ m = self.CHILD_RE.match(line)
+ if m:
+ # This is a new item. Append
+ items.append(m.group(3))
+ elif self.INDENT_RE.match(line):
+ # This is an indented (possibly nested) item.
+ if items[-1].startswith(' '*markdown.TAB_LENGTH):
+ # Previous item was indented. Append to that item.
+ items[-1] = '%s\n%s' % (items[-1], line)
+ else:
+ items.append(line)
+ else:
+ # This is another line of previous item. Append to that item.
+ items[-1] = '%s\n%s' % (items[-1], line)
+ return items
+
+
+class UListProcessor(OListProcessor):
+ """ Process unordered list blocks. """
+
+ TAG = 'ul'
+ RE = re.compile(r'^[ ]{0,3}[*+-][ ](.*)')
+
+
+class HashHeaderProcessor(BlockProcessor):
+ """ Process Hash Headers. """
+
+ # Detect a header at start of any line in block
+ RE = re.compile(r'(^|\n)(?P<level>#{1,6})(?P<header>.*?)#*(\n|$)')
+
+ def test(self, parent, block):
+ return bool(self.RE.search(block))
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ before = block[:m.start()] # All lines before header
+ after = block[m.end():] # All lines after header
+ if before:
+ # As the header was not the first line of the block and the
+ # lines before the header must be parsed first,
+ # recursively parse this lines as a block.
+ self.parser.parseBlocks(parent, [before])
+ # Create header using named groups from RE
+ h = markdown.etree.SubElement(parent, 'h%d' % len(m.group('level')))
+ h.text = m.group('header').strip()
+ if after:
+ # Insert remaining lines as first block for future parsing.
+ blocks.insert(0, after)
+ else:
+ # This should never happen, but just in case...
+ message(CRITICAL, "We've got a problem header!")
+
+
+class SetextHeaderProcessor(BlockProcessor):
+ """ Process Setext-style Headers. """
+
+ # Detect Setext-style header. Must be first 2 lines of block.
+ RE = re.compile(r'^.*?\n[=-]{3,}', re.MULTILINE)
+
+ def test(self, parent, block):
+ return bool(self.RE.match(block))
+
+ def run(self, parent, blocks):
+ lines = blocks.pop(0).split('\n')
+ # Determine level. ``=`` is 1 and ``-`` is 2.
+ if lines[1].startswith('='):
+ level = 1
+ else:
+ level = 2
+ h = markdown.etree.SubElement(parent, 'h%d' % level)
+ h.text = lines[0].strip()
+ if len(lines) > 2:
+ # Block contains additional lines. Add to master blocks for later.
+ blocks.insert(0, '\n'.join(lines[2:]))
+
+
+class HRProcessor(BlockProcessor):
+ """ Process Horizontal Rules. """
+
+ RE = r'[ ]{0,3}(?P<ch>[*_-])[ ]?((?P=ch)[ ]?){2,}[ ]*'
+ # Detect hr on any line of a block.
+ SEARCH_RE = re.compile(r'(^|\n)%s(\n|$)' % RE)
+ # Match a hr on a single line of text.
+ MATCH_RE = re.compile(r'^%s$' % RE)
+
+ def test(self, parent, block):
+ return bool(self.SEARCH_RE.search(block))
+
+ def run(self, parent, blocks):
+ lines = blocks.pop(0).split('\n')
+ prelines = []
+ # Check for lines in block before hr.
+ for line in lines:
+ m = self.MATCH_RE.match(line)
+ if m:
+ break
+ else:
+ prelines.append(line)
+ if len(prelines):
+ # Recursively parse lines before hr so they get parsed first.
+ self.parser.parseBlocks(parent, ['\n'.join(prelines)])
+ # create hr
+ hr = markdown.etree.SubElement(parent, 'hr')
+ # check for lines in block after hr.
+ lines = lines[len(prelines)+1:]
+ if len(lines):
+ # Add lines after hr to master blocks for later parsing.
+ blocks.insert(0, '\n'.join(lines))
+
+
+class EmptyBlockProcessor(BlockProcessor):
+ """ Process blocks and start with an empty line. """
+
+ # Detect a block that only contains whitespace
+ # or only whitespace on the first line.
+ RE = re.compile(r'^\s*\n')
+
+ def test(self, parent, block):
+ return bool(self.RE.match(block))
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.match(block)
+ if m:
+ # Add remaining line to master blocks for later.
+ blocks.insert(0, block[m.end():])
+ sibling = self.lastChild(parent)
+ if sibling and sibling.tag == 'pre' and sibling[0] and \
+ sibling[0].tag == 'code':
+ # Last block is a codeblock. Append to preserve whitespace.
+ sibling[0].text = markdown.AtomicString('%s/n/n/n' % sibling[0].text )
+
+
+class ParagraphProcessor(BlockProcessor):
+ """ Process Paragraph blocks. """
+
+ def test(self, parent, block):
+ return True
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ if block.strip():
+ # Not a blank block. Add to parent, otherwise throw it away.
+ if self.parser.state.isstate('list'):
+ # The parent is a tight-list. Append to parent.text
+ if parent.text:
+ parent.text = '%s\n%s' % (parent.text, block)
+ else:
+ parent.text = block.lstrip()
+ else:
+ # Create a regular paragraph
+ p = markdown.etree.SubElement(parent, 'p')
+ p.text = block.lstrip()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/commandline.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/commandline.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/commandline.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,96 @@
+"""
+COMMAND-LINE SPECIFIC STUFF
+=============================================================================
+
+The rest of the code is specifically for handling the case where Python
+Markdown is called from the command line.
+"""
+
+import markdown
+import sys
+import logging
+from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
+
+EXECUTABLE_NAME_FOR_USAGE = "python markdown.py"
+""" The name used in the usage statement displayed for python versions < 2.3.
+(With python 2.3 and higher the usage statement is generated by optparse
+and uses the actual name of the executable called.) """
+
+OPTPARSE_WARNING = """
+Python 2.3 or higher required for advanced command line options.
+For lower versions of Python use:
+
+ %s INPUT_FILE > OUTPUT_FILE
+
+""" % EXECUTABLE_NAME_FOR_USAGE
+
+def parse_options():
+ """
+ Define and parse `optparse` options for command-line usage.
+ """
+
+ try:
+ optparse = __import__("optparse")
+ except:
+ if len(sys.argv) == 2:
+ return {'input': sys.argv[1],
+ 'output': None,
+ 'safe': False,
+ 'extensions': [],
+ 'encoding': None }, CRITICAL
+ else:
+ print OPTPARSE_WARNING
+ return None, None
+
+ parser = optparse.OptionParser(usage="%prog INPUTFILE [options]")
+ parser.add_option("-f", "--file", dest="filename", default=sys.stdout,
+ help="write output to OUTPUT_FILE",
+ metavar="OUTPUT_FILE")
+ parser.add_option("-e", "--encoding", dest="encoding",
+ help="encoding for input and output files",)
+ parser.add_option("-q", "--quiet", default = CRITICAL,
+ action="store_const", const=CRITICAL+10, dest="verbose",
+ help="suppress all messages")
+ parser.add_option("-v", "--verbose",
+ action="store_const", const=INFO, dest="verbose",
+ help="print info messages")
+ parser.add_option("-s", "--safe", dest="safe", default=False,
+ metavar="SAFE_MODE",
+ help="safe mode ('replace', 'remove' or 'escape' user's HTML tag)")
+ parser.add_option("-o", "--output_format", dest="output_format",
+ default='xhtml1', metavar="OUTPUT_FORMAT",
+ help="Format of output. One of 'xhtml1' (default) or 'html4'.")
+ parser.add_option("--noisy",
+ action="store_const", const=DEBUG, dest="verbose",
+ help="print debug messages")
+ parser.add_option("-x", "--extension", action="append", dest="extensions",
+ help = "load extension EXTENSION", metavar="EXTENSION")
+
+ (options, args) = parser.parse_args()
+
+ if not len(args) == 1:
+ parser.print_help()
+ return None, None
+ else:
+ input_file = args[0]
+
+ if not options.extensions:
+ options.extensions = []
+
+ return {'input': input_file,
+ 'output': options.filename,
+ 'safe_mode': options.safe,
+ 'extensions': options.extensions,
+ 'encoding': options.encoding,
+ 'output_format': options.output_format}, options.verbose
+
+def run():
+ """Run Markdown from the command line."""
+
+ # Parse options and adjust logging level if necessary
+ options, logging_level = parse_options()
+ if not options: sys.exit(0)
+ if logging_level: logging.getLogger('MARKDOWN').setLevel(logging_level)
+
+ # Run
+ markdown.markdownFromFile(**options)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/etree_loader.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/etree_loader.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/etree_loader.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+
+from markdown import message, CRITICAL
+import sys
+
+## Import
+def importETree():
+ """Import the best implementation of ElementTree, return a module object."""
+ etree_in_c = None
+ try: # Is it Python 2.5+ with C implemenation of ElementTree installed?
+ import xml.etree.cElementTree as etree_in_c
+ except ImportError:
+ try: # Is it Python 2.5+ with Python implementation of ElementTree?
+ import xml.etree.ElementTree as etree
+ except ImportError:
+ try: # An earlier version of Python with cElementTree installed?
+ import cElementTree as etree_in_c
+ except ImportError:
+ try: # An earlier version of Python with Python ElementTree?
+ import elementtree.ElementTree as etree
+ except ImportError:
+ message(CRITICAL, "Failed to import ElementTree")
+ sys.exit(1)
+ if etree_in_c and etree_in_c.VERSION < "1.0":
+ message(CRITICAL, "For cElementTree version 1.0 or higher is required.")
+ sys.exit(1)
+ elif etree_in_c :
+ return etree_in_c
+ elif etree.VERSION < "1.1":
+ message(CRITICAL, "For ElementTree version 1.1 or higher is required")
+ sys.exit(1)
+ else :
+ return etree
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/html4.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/html4.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/html4.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,274 @@
+# markdown/html4.py
+#
+# Add html4 serialization to older versions of Elementree
+# Taken from ElementTree 1.3 preview with slight modifications
+#
+# Copyright (c) 1999-2007 by Fredrik Lundh. All rights reserved.
+#
+# fredrik at pythonware.com
+# http://www.pythonware.com
+#
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2007 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+
+import markdown
+ElementTree = markdown.etree.ElementTree
+QName = markdown.etree.QName
+Comment = markdown.etree.Comment
+PI = markdown.etree.PI
+ProcessingInstruction = markdown.etree.ProcessingInstruction
+
+HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
+ "img", "input", "isindex", "link", "meta" "param")
+
+try:
+ HTML_EMPTY = set(HTML_EMPTY)
+except NameError:
+ pass
+
+_namespace_map = {
+ # "well-known" namespace prefixes
+ "http://www.w3.org/XML/1998/namespace": "xml",
+ "http://www.w3.org/1999/xhtml": "html",
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
+ "http://schemas.xmlsoap.org/wsdl/": "wsdl",
+ # xml schema
+ "http://www.w3.org/2001/XMLSchema": "xs",
+ "http://www.w3.org/2001/XMLSchema-instance": "xsi",
+ # dublic core
+ "http://purl.org/dc/elements/1.1/": "dc",
+}
+
+
+def _raise_serialization_error(text):
+ raise TypeError(
+ "cannot serialize %r (type %s)" % (text, type(text).__name__)
+ )
+
+def _encode(text, encoding):
+ try:
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+def _escape_cdata(text, encoding):
+ # escape character data
+ try:
+ # it's worth avoiding do-nothing calls for strings that are
+ # shorter than 500 character, or so. assume that's, by far,
+ # the most common case in most applications.
+ if "&" in text:
+ text = text.replace("&", "&")
+ if "<" in text:
+ text = text.replace("<", "<")
+ if ">" in text:
+ text = text.replace(">", ">")
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+
+def _escape_attrib(text, encoding):
+ # escape attribute value
+ try:
+ if "&" in text:
+ text = text.replace("&", "&")
+ if "<" in text:
+ text = text.replace("<", "<")
+ if ">" in text:
+ text = text.replace(">", ">")
+ if "\"" in text:
+ text = text.replace("\"", """)
+ if "\n" in text:
+ text = text.replace("\n", " ")
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+def _escape_attrib_html(text, encoding):
+ # escape attribute value
+ try:
+ if "&" in text:
+ text = text.replace("&", "&")
+ if ">" in text:
+ text = text.replace(">", ">")
+ if "\"" in text:
+ text = text.replace("\"", """)
+ return text.encode(encoding, "xmlcharrefreplace")
+ except (TypeError, AttributeError):
+ _raise_serialization_error(text)
+
+
+def _serialize_html(write, elem, encoding, qnames, namespaces):
+ tag = elem.tag
+ text = elem.text
+ if tag is Comment:
+ write("<!--%s-->" % _escape_cdata(text, encoding))
+ elif tag is ProcessingInstruction:
+ write("<?%s?>" % _escape_cdata(text, encoding))
+ else:
+ tag = qnames[tag]
+ if tag is None:
+ if text:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_html(write, e, encoding, qnames, None)
+ else:
+ write("<" + tag)
+ items = elem.items()
+ if items or namespaces:
+ items.sort() # lexical order
+ for k, v in items:
+ if isinstance(k, QName):
+ k = k.text
+ if isinstance(v, QName):
+ v = qnames[v.text]
+ else:
+ v = _escape_attrib_html(v, encoding)
+ # FIXME: handle boolean attributes
+ write(" %s=\"%s\"" % (qnames[k], v))
+ if namespaces:
+ items = namespaces.items()
+ items.sort(key=lambda x: x[1]) # sort on prefix
+ for v, k in items:
+ if k:
+ k = ":" + k
+ write(" xmlns%s=\"%s\"" % (
+ k.encode(encoding),
+ _escape_attrib(v, encoding)
+ ))
+ write(">")
+ tag = tag.lower()
+ if text:
+ if tag == "script" or tag == "style":
+ write(_encode(text, encoding))
+ else:
+ write(_escape_cdata(text, encoding))
+ for e in elem:
+ _serialize_html(write, e, encoding, qnames, None)
+ if tag not in HTML_EMPTY:
+ write("</" + tag + ">")
+ if elem.tail:
+ write(_escape_cdata(elem.tail, encoding))
+
+def write_html(root, f,
+ # keyword arguments
+ encoding="us-ascii",
+ default_namespace=None):
+ assert root is not None
+ if not hasattr(f, "write"):
+ f = open(f, "wb")
+ write = f.write
+ if not encoding:
+ encoding = "us-ascii"
+ qnames, namespaces = _namespaces(
+ root, encoding, default_namespace
+ )
+ _serialize_html(
+ write, root, encoding, qnames, namespaces
+ )
+
+# --------------------------------------------------------------------
+# serialization support
+
+def _namespaces(elem, encoding, default_namespace=None):
+ # identify namespaces used in this tree
+
+ # maps qnames to *encoded* prefix:local names
+ qnames = {None: None}
+
+ # maps uri:s to prefixes
+ namespaces = {}
+ if default_namespace:
+ namespaces[default_namespace] = ""
+
+ def encode(text):
+ return text.encode(encoding)
+
+ def add_qname(qname):
+ # calculate serialized qname representation
+ try:
+ if qname[:1] == "{":
+ uri, tag = qname[1:].split("}", 1)
+ prefix = namespaces.get(uri)
+ if prefix is None:
+ prefix = _namespace_map.get(uri)
+ if prefix is None:
+ prefix = "ns%d" % len(namespaces)
+ if prefix != "xml":
+ namespaces[uri] = prefix
+ if prefix:
+ qnames[qname] = encode("%s:%s" % (prefix, tag))
+ else:
+ qnames[qname] = encode(tag) # default element
+ else:
+ if default_namespace:
+ # FIXME: can this be handled in XML 1.0?
+ raise ValueError(
+ "cannot use non-qualified names with "
+ "default_namespace option"
+ )
+ qnames[qname] = encode(qname)
+ except TypeError:
+ _raise_serialization_error(qname)
+
+ # populate qname and namespaces table
+ try:
+ iterate = elem.iter
+ except AttributeError:
+ iterate = elem.getiterator # cET compatibility
+ for elem in iterate():
+ tag = elem.tag
+ if isinstance(tag, QName) and tag.text not in qnames:
+ add_qname(tag.text)
+ elif isinstance(tag, basestring):
+ if tag not in qnames:
+ add_qname(tag)
+ elif tag is not None and tag is not Comment and tag is not PI:
+ _raise_serialization_error(tag)
+ for key, value in elem.items():
+ if isinstance(key, QName):
+ key = key.text
+ if key not in qnames:
+ add_qname(key)
+ if isinstance(value, QName) and value.text not in qnames:
+ add_qname(value.text)
+ text = elem.text
+ if isinstance(text, QName) and text.text not in qnames:
+ add_qname(text.text)
+ return qnames, namespaces
+
+def to_html_string(element, encoding=None):
+ class dummy:
+ pass
+ data = []
+ file = dummy()
+ file.write = data.append
+ write_html(ElementTree(element).getroot(),file,encoding)
+ return "".join(data)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/inlinepatterns.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/inlinepatterns.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/inlinepatterns.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,371 @@
+"""
+INLINE PATTERNS
+=============================================================================
+
+Inline patterns such as *emphasis* are handled by means of auxiliary
+objects, one per pattern. Pattern objects must be instances of classes
+that extend markdown.Pattern. Each pattern object uses a single regular
+expression and needs support the following methods:
+
+ pattern.getCompiledRegExp() # returns a regular expression
+
+ pattern.handleMatch(m) # takes a match object and returns
+ # an ElementTree element or just plain text
+
+All of python markdown's built-in patterns subclass from Pattern,
+but you can add additional patterns that don't.
+
+Also note that all the regular expressions used by inline must
+capture the whole block. For this reason, they all start with
+'^(.*)' and end with '(.*)!'. In case with built-in expression
+Pattern takes care of adding the "^(.*)" and "(.*)!".
+
+Finally, the order in which regular expressions are applied is very
+important - e.g. if we first replace http://.../ links with <a> tags
+and _then_ try to replace inline html, we would end up with a mess.
+So, we apply the expressions in the following order:
+
+* escape and backticks have to go before everything else, so
+ that we can preempt any markdown patterns by escaping them.
+
+* then we handle auto-links (must be done before inline html)
+
+* then we handle inline HTML. At this point we will simply
+ replace all inline HTML strings with a placeholder and add
+ the actual HTML to a hash.
+
+* then inline images (must be done before links)
+
+* then bracketed links, first regular then reference-style
+
+* finally we apply strong and emphasis
+"""
+
+import markdown
+import re
+from urlparse import urlparse, urlunparse
+import sys
+if sys.version >= "3.0":
+ from html import entities as htmlentitydefs
+else:
+ import htmlentitydefs
+
+"""
+The actual regular expressions for patterns
+-----------------------------------------------------------------------------
+"""
+
+NOBRACKET = r'[^\]\[]*'
+BRK = ( r'\[('
+ + (NOBRACKET + r'(\[')*6
+ + (NOBRACKET+ r'\])*')*6
+ + NOBRACKET + r')\]' )
+NOIMG = r'(?<!\!)'
+
+BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' # `e=f()` or ``e=f("`")``
+ESCAPE_RE = r'\\(.)' # \<
+EMPHASIS_RE = r'(\*)([^\*]*)\2' # *emphasis*
+STRONG_RE = r'(\*{2}|_{2})(.*?)\2' # **strong**
+STRONG_EM_RE = r'(\*{3}|_{3})(.*?)\2' # ***strong***
+
+if markdown.SMART_EMPHASIS:
+ EMPHASIS_2_RE = r'(?<!\S)(_)(\S.*?)\2' # _emphasis_
+else:
+ EMPHASIS_2_RE = r'(_)(.*?)\2' # _emphasis_
+
+LINK_RE = NOIMG + BRK + \
+r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*?)\s*((['"])(.*)\12)?\)'''
+# [text](url) or [text](<url>)
+
+IMAGE_LINK_RE = r'\!' + BRK + r'\s*\((<.*?>|([^\)]*))\)'
+# ![alttxt](http://x.com/) or ![alttxt](<http://x.com/>)
+REFERENCE_RE = NOIMG + BRK+ r'\s*\[([^\]]*)\]' # [Google][3]
+IMAGE_REFERENCE_RE = r'\!' + BRK + '\s*\[([^\]]*)\]' # ![alt text][2]
+NOT_STRONG_RE = r'( \* )' # stand-alone * or _
+AUTOLINK_RE = r'<((?:f|ht)tps?://[^>]*)>' # <http://www.123.com>
+AUTOMAIL_RE = r'<([^> \!]*@[^> ]*)>' # <me at example.com>
+
+HTML_RE = r'(\<([a-zA-Z/][^\>]*?|\!--.*?--)\>)' # <...>
+ENTITY_RE = r'(&[\#a-zA-Z0-9]*;)' # &
+LINE_BREAK_RE = r' \n' # two spaces at end of line
+LINE_BREAK_2_RE = r' $' # two spaces at end of text
+
+
+def dequote(string):
+ """Remove quotes from around a string."""
+ if ( ( string.startswith('"') and string.endswith('"'))
+ or (string.startswith("'") and string.endswith("'")) ):
+ return string[1:-1]
+ else:
+ return string
+
+ATTR_RE = re.compile("\{@([^\}]*)=([^\}]*)}") # {@id=123}
+
+def handleAttributes(text, parent):
+ """Set values of an element based on attribute definitions ({@id=123})."""
+ def attributeCallback(match):
+ parent.set(match.group(1), match.group(2).replace('\n', ' '))
+ return ATTR_RE.sub(attributeCallback, text)
+
+
+"""
+The pattern classes
+-----------------------------------------------------------------------------
+"""
+
+class Pattern:
+ """Base class that inline patterns subclass. """
+
+ def __init__ (self, pattern, markdown_instance=None):
+ """
+ Create an instant of an inline pattern.
+
+ Keyword arguments:
+
+ * pattern: A regular expression that matches a pattern
+
+ """
+ self.pattern = pattern
+ self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern, re.DOTALL)
+
+ # Api for Markdown to pass safe_mode into instance
+ self.safe_mode = False
+ if markdown_instance:
+ self.markdown = markdown_instance
+
+ def getCompiledRegExp (self):
+ """ Return a compiled regular expression. """
+ return self.compiled_re
+
+ def handleMatch(self, m):
+ """Return a ElementTree element from the given match.
+
+ Subclasses should override this method.
+
+ Keyword arguments:
+
+ * m: A re match object containing a match of the pattern.
+
+ """
+ pass
+
+ def type(self):
+ """ Return class name, to define pattern type """
+ return self.__class__.__name__
+
+BasePattern = Pattern # for backward compatibility
+
+class SimpleTextPattern (Pattern):
+ """ Return a simple text of group(2) of a Pattern. """
+ def handleMatch(self, m):
+ text = m.group(2)
+ if text == markdown.INLINE_PLACEHOLDER_PREFIX:
+ return None
+ return text
+
+class SimpleTagPattern (Pattern):
+ """
+ Return element of type `tag` with a text attribute of group(3)
+ of a Pattern.
+
+ """
+ def __init__ (self, pattern, tag):
+ Pattern.__init__(self, pattern)
+ self.tag = tag
+
+ def handleMatch(self, m):
+ el = markdown.etree.Element(self.tag)
+ el.text = m.group(3)
+ return el
+
+
+class SubstituteTagPattern (SimpleTagPattern):
+ """ Return a eLement of type `tag` with no children. """
+ def handleMatch (self, m):
+ return markdown.etree.Element(self.tag)
+
+
+class BacktickPattern (Pattern):
+ """ Return a `<code>` element containing the matching text. """
+ def __init__ (self, pattern):
+ Pattern.__init__(self, pattern)
+ self.tag = "code"
+
+ def handleMatch(self, m):
+ el = markdown.etree.Element(self.tag)
+ el.text = markdown.AtomicString(m.group(3).strip())
+ return el
+
+
+class DoubleTagPattern (SimpleTagPattern):
+ """Return a ElementTree element nested in tag2 nested in tag1.
+
+ Useful for strong emphasis etc.
+
+ """
+ def handleMatch(self, m):
+ tag1, tag2 = self.tag.split(",")
+ el1 = markdown.etree.Element(tag1)
+ el2 = markdown.etree.SubElement(el1, tag2)
+ el2.text = m.group(3)
+ return el1
+
+
+class HtmlPattern (Pattern):
+ """ Store raw inline html and return a placeholder. """
+ def handleMatch (self, m):
+ rawhtml = m.group(2)
+ inline = True
+ place_holder = self.markdown.htmlStash.store(rawhtml)
+ return place_holder
+
+
+class LinkPattern (Pattern):
+ """ Return a link element from the given match. """
+ def handleMatch(self, m):
+ el = markdown.etree.Element("a")
+ el.text = m.group(2)
+ title = m.group(11)
+ href = m.group(9)
+
+ if href:
+ if href[0] == "<":
+ href = href[1:-1]
+ el.set("href", self.sanitize_url(href.strip()))
+ else:
+ el.set("href", "")
+
+ if title:
+ title = dequote(title) #.replace('"', """)
+ el.set("title", title)
+ return el
+
+ def sanitize_url(self, url):
+ """
+ Sanitize a url against xss attacks in "safe_mode".
+
+ Rather than specifically blacklisting `javascript:alert("XSS")` and all
+ its aliases (see <http://ha.ckers.org/xss.html>), we whitelist known
+ safe url formats. Most urls contain a network location, however some
+ are known not to (i.e.: mailto links). Script urls do not contain a
+ location. Additionally, for `javascript:...`, the scheme would be
+ "javascript" but some aliases will appear to `urlparse()` to have no
+ scheme. On top of that relative links (i.e.: "foo/bar.html") have no
+ scheme. Therefore we must check "path", "parameters", "query" and
+ "fragment" for any literal colons. We don't check "scheme" for colons
+ because it *should* never have any and "netloc" must allow the form:
+ `username:password at host:port`.
+
+ """
+ locless_schemes = ['', 'mailto', 'news']
+ scheme, netloc, path, params, query, fragment = url = urlparse(url)
+ safe_url = False
+ if netloc != '' or scheme in locless_schemes:
+ safe_url = True
+
+ for part in url[2:]:
+ if ":" in part:
+ safe_url = False
+
+ if self.markdown.safeMode and not safe_url:
+ return ''
+ else:
+ return urlunparse(url)
+
+class ImagePattern(LinkPattern):
+ """ Return a img element from the given match. """
+ def handleMatch(self, m):
+ el = markdown.etree.Element("img")
+ src_parts = m.group(9).split()
+ if src_parts:
+ src = src_parts[0]
+ if src[0] == "<" and src[-1] == ">":
+ src = src[1:-1]
+ el.set('src', self.sanitize_url(src))
+ else:
+ el.set('src', "")
+ if len(src_parts) > 1:
+ el.set('title', dequote(" ".join(src_parts[1:])))
+
+ if markdown.ENABLE_ATTRIBUTES:
+ truealt = handleAttributes(m.group(2), el)
+ else:
+ truealt = m.group(2)
+
+ el.set('alt', truealt)
+ return el
+
+class ReferencePattern(LinkPattern):
+ """ Match to a stored reference and return link element. """
+ def handleMatch(self, m):
+ if m.group(9):
+ id = m.group(9).lower()
+ else:
+ # if we got something like "[Google][]"
+ # we'll use "google" as the id
+ id = m.group(2).lower()
+
+ if not id in self.markdown.references: # ignore undefined refs
+ return None
+ href, title = self.markdown.references[id]
+
+ text = m.group(2)
+ return self.makeTag(href, title, text)
+
+ def makeTag(self, href, title, text):
+ el = markdown.etree.Element('a')
+
+ el.set('href', self.sanitize_url(href))
+ if title:
+ el.set('title', title)
+
+ el.text = text
+ return el
+
+
+class ImageReferencePattern (ReferencePattern):
+ """ Match to a stored reference and return img element. """
+ def makeTag(self, href, title, text):
+ el = markdown.etree.Element("img")
+ el.set("src", self.sanitize_url(href))
+ if title:
+ el.set("title", title)
+ el.set("alt", text)
+ return el
+
+
+class AutolinkPattern (Pattern):
+ """ Return a link Element given an autolink (`<http://example/com>`). """
+ def handleMatch(self, m):
+ el = markdown.etree.Element("a")
+ el.set('href', m.group(2))
+ el.text = markdown.AtomicString(m.group(2))
+ return el
+
+class AutomailPattern (Pattern):
+ """
+ Return a mailto link Element given an automail link (`<foo at example.com>`).
+ """
+ def handleMatch(self, m):
+ el = markdown.etree.Element('a')
+ email = m.group(2)
+ if email.startswith("mailto:"):
+ email = email[len("mailto:"):]
+
+ def codepoint2name(code):
+ """Return entity definition by code, or the code if not defined."""
+ entity = htmlentitydefs.codepoint2name.get(code)
+ if entity:
+ return "%s%s;" % (markdown.AMP_SUBSTITUTE, entity)
+ else:
+ return "%s#%d;" % (markdown.AMP_SUBSTITUTE, code)
+
+ letters = [codepoint2name(ord(letter)) for letter in email]
+ el.text = markdown.AtomicString(''.join(letters))
+
+ mailto = "mailto:" + email
+ mailto = "".join([markdown.AMP_SUBSTITUTE + '#%d;' %
+ ord(letter) for letter in mailto])
+ el.set('href', mailto)
+ return el
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/odict.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/odict.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/odict.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,162 @@
+class OrderedDict(dict):
+ """
+ A dictionary that keeps its keys in the order in which they're inserted.
+
+ Copied from Django's SortedDict with some modifications.
+
+ """
+ def __new__(cls, *args, **kwargs):
+ instance = super(OrderedDict, cls).__new__(cls, *args, **kwargs)
+ instance.keyOrder = []
+ return instance
+
+ def __init__(self, data=None):
+ if data is None:
+ data = {}
+ super(OrderedDict, self).__init__(data)
+ if isinstance(data, dict):
+ self.keyOrder = data.keys()
+ else:
+ self.keyOrder = []
+ for key, value in data:
+ if key not in self.keyOrder:
+ self.keyOrder.append(key)
+
+ def __deepcopy__(self, memo):
+ from copy import deepcopy
+ return self.__class__([(key, deepcopy(value, memo))
+ for key, value in self.iteritems()])
+
+ def __setitem__(self, key, value):
+ super(OrderedDict, self).__setitem__(key, value)
+ if key not in self.keyOrder:
+ self.keyOrder.append(key)
+
+ def __delitem__(self, key):
+ super(OrderedDict, self).__delitem__(key)
+ self.keyOrder.remove(key)
+
+ def __iter__(self):
+ for k in self.keyOrder:
+ yield k
+
+ def pop(self, k, *args):
+ result = super(OrderedDict, self).pop(k, *args)
+ try:
+ self.keyOrder.remove(k)
+ except ValueError:
+ # Key wasn't in the dictionary in the first place. No problem.
+ pass
+ return result
+
+ def popitem(self):
+ result = super(OrderedDict, self).popitem()
+ self.keyOrder.remove(result[0])
+ return result
+
+ def items(self):
+ return zip(self.keyOrder, self.values())
+
+ def iteritems(self):
+ for key in self.keyOrder:
+ yield key, super(OrderedDict, self).__getitem__(key)
+
+ def keys(self):
+ return self.keyOrder[:]
+
+ def iterkeys(self):
+ return iter(self.keyOrder)
+
+ def values(self):
+ return [super(OrderedDict, self).__getitem__(k) for k in self.keyOrder]
+
+ def itervalues(self):
+ for key in self.keyOrder:
+ yield super(OrderedDict, self).__getitem__(key)
+
+ def update(self, dict_):
+ for k, v in dict_.items():
+ self.__setitem__(k, v)
+
+ def setdefault(self, key, default):
+ if key not in self.keyOrder:
+ self.keyOrder.append(key)
+ return super(OrderedDict, self).setdefault(key, default)
+
+ def value_for_index(self, index):
+ """Return the value of the item at the given zero-based index."""
+ return self[self.keyOrder[index]]
+
+ def insert(self, index, key, value):
+ """Insert the key, value pair before the item with the given index."""
+ if key in self.keyOrder:
+ n = self.keyOrder.index(key)
+ del self.keyOrder[n]
+ if n < index:
+ index -= 1
+ self.keyOrder.insert(index, key)
+ super(OrderedDict, self).__setitem__(key, value)
+
+ def copy(self):
+ """Return a copy of this object."""
+ # This way of initializing the copy means it works for subclasses, too.
+ obj = self.__class__(self)
+ obj.keyOrder = self.keyOrder[:]
+ return obj
+
+ def __repr__(self):
+ """
+ Replace the normal dict.__repr__ with a version that returns the keys
+ in their sorted order.
+ """
+ return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
+
+ def clear(self):
+ super(OrderedDict, self).clear()
+ self.keyOrder = []
+
+ def index(self, key):
+ """ Return the index of a given key. """
+ return self.keyOrder.index(key)
+
+ def index_for_location(self, location):
+ """ Return index or None for a given location. """
+ if location == '_begin':
+ i = 0
+ elif location == '_end':
+ i = None
+ elif location.startswith('<') or location.startswith('>'):
+ i = self.index(location[1:])
+ if location.startswith('>'):
+ if i >= len(self):
+ # last item
+ i = None
+ else:
+ i += 1
+ else:
+ raise ValueError('Not a valid location: "%s". Location key '
+ 'must start with a ">" or "<".' % location)
+ return i
+
+ def add(self, key, value, location):
+ """ Insert by key location. """
+ i = self.index_for_location(location)
+ if i is not None:
+ self.insert(i, key, value)
+ else:
+ self.__setitem__(key, value)
+
+ def link(self, key, location):
+ """ Change location of an existing item. """
+ n = self.keyOrder.index(key)
+ del self.keyOrder[n]
+ i = self.index_for_location(location)
+ try:
+ if i is not None:
+ self.keyOrder.insert(i, key)
+ else:
+ self.keyOrder.append(key)
+ except Error:
+ # restore to prevent data loss and reraise
+ self.keyOrder.insert(n, key)
+ raise Error
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/postprocessors.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/postprocessors.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/postprocessors.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,77 @@
+"""
+POST-PROCESSORS
+=============================================================================
+
+Markdown also allows post-processors, which are similar to preprocessors in
+that they need to implement a "run" method. However, they are run after core
+processing.
+
+"""
+
+
+import markdown
+
+class Processor:
+ def __init__(self, markdown_instance=None):
+ if markdown_instance:
+ self.markdown = markdown_instance
+
+class Postprocessor(Processor):
+ """
+ Postprocessors are run after the ElementTree it converted back into text.
+
+ Each Postprocessor implements a "run" method that takes a pointer to a
+ text string, modifies it as necessary and returns a text string.
+
+ Postprocessors must extend markdown.Postprocessor.
+
+ """
+
+ def run(self, text):
+ """
+ Subclasses of Postprocessor should implement a `run` method, which
+ takes the html document as a single text string and returns a
+ (possibly modified) string.
+
+ """
+ pass
+
+
+class RawHtmlPostprocessor(Postprocessor):
+ """ Restore raw html to the document. """
+
+ def run(self, text):
+ """ Iterate over html stash and restore "safe" html. """
+ for i in range(self.markdown.htmlStash.html_counter):
+ html, safe = self.markdown.htmlStash.rawHtmlBlocks[i]
+ if self.markdown.safeMode and not safe:
+ if str(self.markdown.safeMode).lower() == 'escape':
+ html = self.escape(html)
+ elif str(self.markdown.safeMode).lower() == 'remove':
+ html = ''
+ else:
+ html = markdown.HTML_REMOVED_TEXT
+ if safe or not self.markdown.safeMode:
+ text = text.replace("<p>%s</p>" %
+ (markdown.preprocessors.HTML_PLACEHOLDER % i),
+ html + "\n")
+ text = text.replace(markdown.preprocessors.HTML_PLACEHOLDER % i,
+ html)
+ return text
+
+ def escape(self, html):
+ """ Basic html escaping """
+ html = html.replace('&', '&')
+ html = html.replace('<', '<')
+ html = html.replace('>', '>')
+ return html.replace('"', '"')
+
+
+class AndSubstitutePostprocessor(Postprocessor):
+ """ Restore valid entities """
+ def __init__(self):
+ pass
+
+ def run(self, text):
+ text = text.replace(markdown.AMP_SUBSTITUTE, "&")
+ return text
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/preprocessors.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/preprocessors.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/preprocessors.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,214 @@
+
+"""
+PRE-PROCESSORS
+=============================================================================
+
+Preprocessors work on source text before we start doing anything too
+complicated.
+"""
+
+import re
+import markdown
+
+HTML_PLACEHOLDER_PREFIX = markdown.STX+"wzxhzdk:"
+HTML_PLACEHOLDER = HTML_PLACEHOLDER_PREFIX + "%d" + markdown.ETX
+
+class Processor:
+ def __init__(self, markdown_instance=None):
+ if markdown_instance:
+ self.markdown = markdown_instance
+
+class Preprocessor (Processor):
+ """
+ Preprocessors are run after the text is broken into lines.
+
+ Each preprocessor implements a "run" method that takes a pointer to a
+ list of lines of the document, modifies it as necessary and returns
+ either the same pointer or a pointer to a new list.
+
+ Preprocessors must extend markdown.Preprocessor.
+
+ """
+ def run(self, lines):
+ """
+ Each subclass of Preprocessor should override the `run` method, which
+ takes the document as a list of strings split by newlines and returns
+ the (possibly modified) list of lines.
+
+ """
+ pass
+
+class HtmlStash:
+ """
+ This class is used for stashing HTML objects that we extract
+ in the beginning and replace with place-holders.
+ """
+
+ def __init__ (self):
+ """ Create a HtmlStash. """
+ self.html_counter = 0 # for counting inline html segments
+ self.rawHtmlBlocks=[]
+
+ def store(self, html, safe=False):
+ """
+ Saves an HTML segment for later reinsertion. Returns a
+ placeholder string that needs to be inserted into the
+ document.
+
+ Keyword arguments:
+
+ * html: an html segment
+ * safe: label an html segment as safe for safemode
+
+ Returns : a placeholder string
+
+ """
+ self.rawHtmlBlocks.append((html, safe))
+ placeholder = HTML_PLACEHOLDER % self.html_counter
+ self.html_counter += 1
+ return placeholder
+
+ def reset(self):
+ self.html_counter = 0
+ self.rawHtmlBlocks = []
+
+
+class HtmlBlockPreprocessor(Preprocessor):
+ """Remove html blocks from the text and store them for later retrieval."""
+
+ right_tag_patterns = ["</%s>", "%s>"]
+
+ def _get_left_tag(self, block):
+ return block[1:].replace(">", " ", 1).split()[0].lower()
+
+ def _get_right_tag(self, left_tag, block):
+ for p in self.right_tag_patterns:
+ tag = p % left_tag
+ i = block.rfind(tag)
+ if i > 2:
+ return tag.lstrip("<").rstrip(">"), i + len(p)-2 + len(left_tag)
+ return block.rstrip()[-len(left_tag)-2:-1].lower(), len(block)
+
+ def _equal_tags(self, left_tag, right_tag):
+ if left_tag == 'div' or left_tag[0] in ['?', '@', '%']: # handle PHP, etc.
+ return True
+ if ("/" + left_tag) == right_tag:
+ return True
+ if (right_tag == "--" and left_tag == "--"):
+ return True
+ elif left_tag == right_tag[1:] \
+ and right_tag[0] != "<":
+ return True
+ else:
+ return False
+
+ def _is_oneliner(self, tag):
+ return (tag in ['hr', 'hr/'])
+
+ def run(self, lines):
+ text = "\n".join(lines)
+ new_blocks = []
+ text = text.split("\n\n")
+ items = []
+ left_tag = ''
+ right_tag = ''
+ in_tag = False # flag
+
+ while text:
+ block = text[0]
+ if block.startswith("\n"):
+ block = block[1:]
+ text = text[1:]
+
+ if block.startswith("\n"):
+ block = block[1:]
+
+ if not in_tag:
+ if block.startswith("<"):
+ left_tag = self._get_left_tag(block)
+ right_tag, data_index = self._get_right_tag(left_tag, block)
+
+ if data_index < len(block):
+ text.insert(0, block[data_index:])
+ block = block[:data_index]
+
+ if not (markdown.isBlockLevel(left_tag) \
+ or block[1] in ["!", "?", "@", "%"]):
+ new_blocks.append(block)
+ continue
+
+ if self._is_oneliner(left_tag):
+ new_blocks.append(block.strip())
+ continue
+
+ if block[1] == "!":
+ # is a comment block
+ left_tag = "--"
+ right_tag, data_index = self._get_right_tag(left_tag, block)
+ # keep checking conditions below and maybe just append
+
+ if block.rstrip().endswith(">") \
+ and self._equal_tags(left_tag, right_tag):
+ new_blocks.append(
+ self.markdown.htmlStash.store(block.strip()))
+ continue
+ else: #if not block[1] == "!":
+ # if is block level tag and is not complete
+
+ if markdown.isBlockLevel(left_tag) or left_tag == "--" \
+ and not block.rstrip().endswith(">"):
+ items.append(block.strip())
+ in_tag = True
+ else:
+ new_blocks.append(
+ self.markdown.htmlStash.store(block.strip()))
+
+ continue
+
+ new_blocks.append(block)
+
+ else:
+ items.append(block.strip())
+
+ right_tag, data_index = self._get_right_tag(left_tag, block)
+
+ if self._equal_tags(left_tag, right_tag):
+ # if find closing tag
+ in_tag = False
+ new_blocks.append(
+ self.markdown.htmlStash.store('\n\n'.join(items)))
+ items = []
+
+ if items:
+ new_blocks.append(self.markdown.htmlStash.store('\n\n'.join(items)))
+ new_blocks.append('\n')
+
+ new_text = "\n\n".join(new_blocks)
+ return new_text.split("\n")
+
+
+class ReferencePreprocessor(Preprocessor):
+ """ Remove reference definitions from text and store for later use. """
+
+ RE = re.compile(r'^(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)$', re.DOTALL)
+
+ def run (self, lines):
+ new_text = [];
+ for line in lines:
+ m = self.RE.match(line)
+ if m:
+ id = m.group(2).strip().lower()
+ t = m.group(4).strip() # potential title
+ if not t:
+ self.markdown.references[id] = (m.group(3), t)
+ elif (len(t) >= 2
+ and (t[0] == t[-1] == "\""
+ or t[0] == t[-1] == "\'"
+ or (t[0] == "(" and t[-1] == ")") ) ):
+ self.markdown.references[id] = (m.group(3), t[1:-1])
+ else:
+ new_text.append(line)
+ else:
+ new_text.append(line)
+
+ return new_text #+ "\n"
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/treeprocessors.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/treeprocessors.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/contrib/markdown/treeprocessors.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,329 @@
+import markdown
+import re
+
+def isString(s):
+ """ Check if it's string """
+ return isinstance(s, unicode) or isinstance(s, str)
+
+class Processor:
+ def __init__(self, markdown_instance=None):
+ if markdown_instance:
+ self.markdown = markdown_instance
+
+class Treeprocessor(Processor):
+ """
+ Treeprocessors are run on the ElementTree object before serialization.
+
+ Each Treeprocessor implements a "run" method that takes a pointer to an
+ ElementTree, modifies it as necessary and returns an ElementTree
+ object.
+
+ Treeprocessors must extend markdown.Treeprocessor.
+
+ """
+ def run(self, root):
+ """
+ Subclasses of Treeprocessor should implement a `run` method, which
+ takes a root ElementTree. This method can return another ElementTree
+ object, and the existing root ElementTree will be replaced, or it can
+ modify the current tree and return None.
+ """
+ pass
+
+
+class InlineProcessor(Treeprocessor):
+ """
+ A Treeprocessor that traverses a tree, applying inline patterns.
+ """
+
+ def __init__ (self, md):
+ self.__placeholder_prefix = markdown.INLINE_PLACEHOLDER_PREFIX
+ self.__placeholder_suffix = markdown.ETX
+ self.__placeholder_length = 4 + len(self.__placeholder_prefix) \
+ + len(self.__placeholder_suffix)
+ self.__placeholder_re = re.compile(markdown.INLINE_PLACEHOLDER % r'([0-9]{4})')
+ self.markdown = md
+
+ def __makePlaceholder(self, type):
+ """ Generate a placeholder """
+ id = "%04d" % len(self.stashed_nodes)
+ hash = markdown.INLINE_PLACEHOLDER % id
+ return hash, id
+
+ def __findPlaceholder(self, data, index):
+ """
+ Extract id from data string, start from index
+
+ Keyword arguments:
+
+ * data: string
+ * index: index, from which we start search
+
+ Returns: placeholder id and string index, after the found placeholder.
+ """
+
+ m = self.__placeholder_re.search(data, index)
+ if m:
+ return m.group(1), m.end()
+ else:
+ return None, index + 1
+
+ def __stashNode(self, node, type):
+ """ Add node to stash """
+ placeholder, id = self.__makePlaceholder(type)
+ self.stashed_nodes[id] = node
+ return placeholder
+
+ def __handleInline(self, data, patternIndex=0):
+ """
+ Process string with inline patterns and replace it
+ with placeholders
+
+ Keyword arguments:
+
+ * data: A line of Markdown text
+ * patternIndex: The index of the inlinePattern to start with
+
+ Returns: String with placeholders.
+
+ """
+ if not isinstance(data, markdown.AtomicString):
+ startIndex = 0
+ while patternIndex < len(self.markdown.inlinePatterns):
+ data, matched, startIndex = self.__applyPattern(
+ self.markdown.inlinePatterns.value_for_index(patternIndex),
+ data, patternIndex, startIndex)
+ if not matched:
+ patternIndex += 1
+ return data
+
+ def __processElementText(self, node, subnode, isText=True):
+ """
+ Process placeholders in Element.text or Element.tail
+ of Elements popped from self.stashed_nodes.
+
+ Keywords arguments:
+
+ * node: parent node
+ * subnode: processing node
+ * isText: bool variable, True - it's text, False - it's tail
+
+ Returns: None
+
+ """
+ if isText:
+ text = subnode.text
+ subnode.text = None
+ else:
+ text = subnode.tail
+ subnode.tail = None
+
+ childResult = self.__processPlaceholders(text, subnode)
+
+ if not isText and node is not subnode:
+ pos = node.getchildren().index(subnode)
+ node.remove(subnode)
+ else:
+ pos = 0
+
+ childResult.reverse()
+ for newChild in childResult:
+ node.insert(pos, newChild)
+
+ def __processPlaceholders(self, data, parent):
+ """
+ Process string with placeholders and generate ElementTree tree.
+
+ Keyword arguments:
+
+ * data: string with placeholders instead of ElementTree elements.
+ * parent: Element, which contains processing inline data
+
+ Returns: list with ElementTree elements with applied inline patterns.
+ """
+ def linkText(text):
+ if text:
+ if result:
+ if result[-1].tail:
+ result[-1].tail += text
+ else:
+ result[-1].tail = text
+ else:
+ if parent.text:
+ parent.text += text
+ else:
+ parent.text = text
+
+ result = []
+ strartIndex = 0
+ while data:
+ index = data.find(self.__placeholder_prefix, strartIndex)
+ if index != -1:
+ id, phEndIndex = self.__findPlaceholder(data, index)
+
+ if id in self.stashed_nodes:
+ node = self.stashed_nodes.get(id)
+
+ if index > 0:
+ text = data[strartIndex:index]
+ linkText(text)
+
+ if not isString(node): # it's Element
+ for child in [node] + node.getchildren():
+ if child.tail:
+ if child.tail.strip():
+ self.__processElementText(node, child, False)
+ if child.text:
+ if child.text.strip():
+ self.__processElementText(child, child)
+ else: # it's just a string
+ linkText(node)
+ strartIndex = phEndIndex
+ continue
+
+ strartIndex = phEndIndex
+ result.append(node)
+
+ else: # wrong placeholder
+ end = index + len(prefix)
+ linkText(data[strartIndex:end])
+ strartIndex = end
+ else:
+ text = data[strartIndex:]
+ linkText(text)
+ data = ""
+
+ return result
+
+ def __applyPattern(self, pattern, data, patternIndex, startIndex=0):
+ """
+ Check if the line fits the pattern, create the necessary
+ elements, add it to stashed_nodes.
+
+ Keyword arguments:
+
+ * data: the text to be processed
+ * pattern: the pattern to be checked
+ * patternIndex: index of current pattern
+ * startIndex: string index, from which we starting search
+
+ Returns: String with placeholders instead of ElementTree elements.
+
+ """
+ match = pattern.getCompiledRegExp().match(data[startIndex:])
+ leftData = data[:startIndex]
+
+ if not match:
+ return data, False, 0
+
+ node = pattern.handleMatch(match)
+
+ if node is None:
+ return data, True, len(leftData) + match.span(len(match.groups()))[0]
+
+ if not isString(node):
+ if not isinstance(node.text, markdown.AtomicString):
+ # We need to process current node too
+ for child in [node] + node.getchildren():
+ if not isString(node):
+ if child.text:
+ child.text = self.__handleInline(child.text,
+ patternIndex + 1)
+ if child.tail:
+ child.tail = self.__handleInline(child.tail,
+ patternIndex)
+
+ placeholder = self.__stashNode(node, pattern.type())
+
+ return "%s%s%s%s" % (leftData,
+ match.group(1),
+ placeholder, match.groups()[-1]), True, 0
+
+ def run(self, tree):
+ """Apply inline patterns to a parsed Markdown tree.
+
+ Iterate over ElementTree, find elements with inline tag, apply inline
+ patterns and append newly created Elements to tree. If you don't
+ want process your data with inline paterns, instead of normal string,
+ use subclass AtomicString:
+
+ node.text = markdown.AtomicString("data won't be processed with inline patterns")
+
+ Arguments:
+
+ * markdownTree: ElementTree object, representing Markdown tree.
+
+ Returns: ElementTree object with applied inline patterns.
+
+ """
+ self.stashed_nodes = {}
+
+ stack = [tree]
+
+ while stack:
+ currElement = stack.pop()
+ insertQueue = []
+ for child in currElement.getchildren():
+ if child.text and not isinstance(child.text, markdown.AtomicString):
+ text = child.text
+ child.text = None
+ lst = self.__processPlaceholders(self.__handleInline(
+ text), child)
+ stack += lst
+ insertQueue.append((child, lst))
+
+ if child.getchildren():
+ stack.append(child)
+
+ for element, lst in insertQueue:
+ if element.text:
+ element.text = \
+ markdown.inlinepatterns.handleAttributes(element.text,
+ element)
+ i = 0
+ for newChild in lst:
+ # Processing attributes
+ if newChild.tail:
+ newChild.tail = \
+ markdown.inlinepatterns.handleAttributes(newChild.tail,
+ element)
+ if newChild.text:
+ newChild.text = \
+ markdown.inlinepatterns.handleAttributes(newChild.text,
+ newChild)
+ element.insert(i, newChild)
+ i += 1
+ return tree
+
+
+class PrettifyTreeprocessor(Treeprocessor):
+ """ Add linebreaks to the html document. """
+
+ def _prettifyETree(self, elem):
+ """ Recursively add linebreaks to ElementTree children. """
+
+ i = "\n"
+ if markdown.isBlockLevel(elem.tag) and elem.tag not in ['code', 'pre']:
+ if (not elem.text or not elem.text.strip()) \
+ and len(elem) and markdown.isBlockLevel(elem[0].tag):
+ elem.text = i
+ for e in elem:
+ if markdown.isBlockLevel(e.tag):
+ self._prettifyETree(e)
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+
+ def run(self, root):
+ """ Add linebreaks to ElementTree root object. """
+
+ self._prettifyETree(root)
+ # Do <br />'s seperately as they are often in the middle of
+ # inline content and missed by _prettifyETree.
+ brs = root.getiterator('br')
+ for br in brs:
+ if not br.tail or not br.tail.strip():
+ br.tail = '\n'
+ else:
+ br.tail = '\n%s' % br.tail
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/convertTmplPathToModuleName.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/convertTmplPathToModuleName.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/Cheetah/convertTmplPathToModuleName.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,15 @@
+import os.path
+import string
+
+l = ['_'] * 256
+for c in string.digits + string.letters:
+ l[ord(c)] = c
+_pathNameTransChars = string.join(l, '')
+del l, c
+
+def convertTmplPathToModuleName(tmplPath,
+ _pathNameTransChars=_pathNameTransChars,
+ splitdrive=os.path.splitdrive,
+ translate=string.translate,
+ ):
+ return translate(splitdrive(tmplPath)[1], _pathNameTransChars)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+Metadata-Version: 1.0
+Name: Cheetah
+Version: 2.2.1
+Summary: Cheetah is a template engine and code generation tool.
+Home-page: http://www.cheetahtemplate.org/
+Author: R. Tyler Ballance
+Author-email: cheetahtemplate-discuss at lists.sf.net
+License: UNKNOWN
+Description: Cheetah is an open source template engine and code generation tool.
+
+ It can be used standalone or combined with other tools and frameworks. Web
+ development is its principle use, but Cheetah is very flexible and is also being
+ used to generate C++ game code, Java, sql, form emails and even Python code.
+
+ Documentation
+ ================================================================================
+ For a high-level introduction to Cheetah please refer to the User's Guide
+ at http://www.cheetahtemplate.org/learn.html
+
+ Mailing list
+ ================================================================================
+ cheetahtemplate-discuss at lists.sourceforge.net
+ Subscribe at http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss
+
+ Credits
+ ================================================================================
+ http://www.cheetahtemplate.org/credits.html
+
+ Recent Changes
+ ================================================================================
+ See http://www.cheetahtemplate.org/CHANGES.txt for full details
+
+
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
+Classifier: Topic :: Software Development :: Code Generators
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: User Interfaces
+Classifier: Topic :: Text Processing
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,101 @@
+CHANGES
+LICENSE
+MANIFEST.in
+README
+SetupConfig.py
+SetupTools.py
+TODO
+setup.py
+Cheetah.egg-info/PKG-INFO
+Cheetah.egg-info/SOURCES.txt
+Cheetah.egg-info/dependency_links.txt
+Cheetah.egg-info/top_level.txt
+bin/cheetah
+bin/cheetah-compile
+src/CacheRegion.py
+src/CacheStore.py
+src/CheetahWrapper.py
+src/Compiler.py
+src/Django.py
+src/DummyTransaction.py
+src/ErrorCatchers.py
+src/FileUtils.py
+src/Filters.py
+src/ImportHooks.py
+src/ImportManager.py
+src/NameMapper.py
+src/Parser.py
+src/Servlet.py
+src/SettingsManager.py
+src/SourceReader.py
+src/Template.py
+src/TemplateCmdLineIface.py
+src/Unspecified.py
+src/Version.py
+src/__init__.py
+src/_namemapper.c
+src/convertTmplPathToModuleName.py
+src/Macros/I18n.py
+src/Macros/__init__.py
+src/Templates/SkeletonPage.py
+src/Templates/SkeletonPage.tmpl
+src/Templates/_SkeletonPage.py
+src/Templates/__init__.py
+src/Tests/CheetahWrapper.py
+src/Tests/Filters.py
+src/Tests/NameMapper.py
+src/Tests/Regressions.py
+src/Tests/SyntaxAndOutput.py
+src/Tests/Template.py
+src/Tests/Test.py
+src/Tests/Unicode.py
+src/Tests/__init__.py
+src/Tests/unittest_local_copy.py
+src/Tests/xmlrunner.py
+src/Tools/CGITemplate.py
+src/Tools/MondoReport.py
+src/Tools/MondoReportDoc.txt
+src/Tools/RecursiveNull.py
+src/Tools/SiteHierarchy.py
+src/Tools/__init__.py
+src/Tools/turbocheetah/__init__.py
+src/Tools/turbocheetah/cheetahsupport.py
+src/Tools/turbocheetah/tests/__init__.py
+src/Tools/turbocheetah/tests/test_template.py
+src/Utils/Indenter.py
+src/Utils/Misc.py
+src/Utils/VerifyType.py
+src/Utils/WebInputMixin.py
+src/Utils/__init__.py
+src/Utils/htmlDecode.py
+src/Utils/htmlEncode.py
+src/Utils/memcache.py
+src/Utils/statprof.py
+src/contrib/__init__.py
+src/contrib/markdown/__init__.py
+src/contrib/markdown/blockparser.py
+src/contrib/markdown/blockprocessors.py
+src/contrib/markdown/commandline.py
+src/contrib/markdown/etree_loader.py
+src/contrib/markdown/html4.py
+src/contrib/markdown/inlinepatterns.py
+src/contrib/markdown/odict.py
+src/contrib/markdown/postprocessors.py
+src/contrib/markdown/preprocessors.py
+src/contrib/markdown/treeprocessors.py
+src/contrib/markdown/extensions/__init__.py
+src/contrib/markdown/extensions/abbr.py
+src/contrib/markdown/extensions/codehilite.py
+src/contrib/markdown/extensions/def_list.py
+src/contrib/markdown/extensions/extra.py
+src/contrib/markdown/extensions/fenced_code.py
+src/contrib/markdown/extensions/footnotes.py
+src/contrib/markdown/extensions/headerid.py
+src/contrib/markdown/extensions/html_tidy.py
+src/contrib/markdown/extensions/imagelinks.py
+src/contrib/markdown/extensions/legacy.py
+src/contrib/markdown/extensions/meta.py
+src/contrib/markdown/extensions/rss.py
+src/contrib/markdown/extensions/tables.py
+src/contrib/markdown/extensions/toc.py
+src/contrib/markdown/extensions/wikilinks.py
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/native_libs.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/native_libs.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/native_libs.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Cheetah/_namemapper.so
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+from Cheetah.CheetahWrapper import CheetahWrapper
+CheetahWrapper().main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah-compile
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah-compile (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/scripts/cheetah-compile 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+import sys
+from Cheetah.CheetahWrapper import CheetahWrapper
+sys.argv.insert(1, "compile")
+CheetahWrapper().main()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Cheetah-2.2.1-py2.6-linux-x86_64.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Cheetah
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,119 @@
+Metadata-Version: 1.0
+Name: Paste
+Version: 1.7.5.1
+Summary: Tools for using a Web Server Gateway Interface stack
+Home-page: http://pythonpaste.org
+Author: Ian Bicking
+Author-email: ianb at colorstudy.com
+License: MIT
+Description: These provide several pieces of "middleware" (or filters) that can be nested to build web applications. Each
+ piece of middleware uses the WSGI (`PEP 333`_) interface, and should
+ be compatible with other middleware based on those interfaces.
+
+ .. _PEP 333: http://www.python.org/peps/pep-0333.html
+
+ Includes these features...
+
+ Testing
+ -------
+
+ * A fixture for testing WSGI applications conveniently and in-process,
+ in ``paste.fixture``
+
+ * A fixture for testing command-line applications, also in
+ ``paste.fixture``
+
+ * Check components for WSGI-compliance in ``paste.lint``
+
+ Dispatching
+ -----------
+
+ * Chain and cascade WSGI applications (returning the first non-error
+ response) in ``paste.cascade``
+
+ * Dispatch to several WSGI applications based on URL prefixes, in
+ ``paste.urlmap``
+
+ * Allow applications to make subrequests and forward requests
+ internally, in ``paste.recursive``
+
+ Web Application
+ ---------------
+
+ * Run CGI programs as WSGI applications in ``paste.cgiapp``
+
+ * Traverse files and load WSGI applications from ``.py`` files (or
+ static files), in ``paste.urlparser``
+
+ * Serve static directories of files, also in ``paste.urlparser``; also
+ in that module serving from Egg resources using ``pkg_resources``.
+
+ Tools
+ -----
+
+ * Catch HTTP-related exceptions (e.g., ``HTTPNotFound``) and turn them
+ into proper responses in ``paste.httpexceptions``
+
+ * Several authentication techniques, including HTTP (Basic and
+ Digest), signed cookies, and CAS single-signon, in the
+ ``paste.auth`` package.
+
+ * Create sessions in ``paste.session`` and ``paste.flup_session``
+
+ * Gzip responses in ``paste.gzip``
+
+ * A wide variety of routines for manipulating WSGI requests and
+ producing responses, in ``paste.request``, ``paste.response`` and
+ ``paste.wsgilib``
+
+ Debugging Filters
+ -----------------
+
+ * Catch (optionally email) errors with extended tracebacks (using
+ Zope/ZPT conventions) in ``paste.exceptions``
+
+ * Catch errors presenting a `cgitb
+ <http://python.org/doc/current/lib/module-cgitb.html>`_-based
+ output, in ``paste.cgitb_catcher``.
+
+ * Profile each request and append profiling information to the HTML,
+ in ``paste.debug.profile``
+
+ * Capture ``print`` output and present it in the browser for
+ debugging, in ``paste.debug.prints``
+
+ * Validate all HTML output from applications using the `WDG Validator
+ <http://www.htmlhelp.com/tools/validator/>`_, appending any errors
+ or warnings to the page, in ``paste.debug.wdg_validator``
+
+ Other Tools
+ -----------
+
+ * A file monitor to allow restarting the server when files have been
+ updated (for automatic restarting when editing code) in
+ ``paste.reloader``
+
+ * A class for generating and traversing URLs, and creating associated
+ HTML code, in ``paste.url``
+
+ The latest version is available in a `Subversion repository
+ <http://svn.pythonpaste.org/Paste/trunk#egg=Paste-dev>`_.
+
+ For the latest changes see the `news file
+ <http://pythonpaste.org/news.html>`_.
+
+
+Keywords: web application server wsgi
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
+Classifier: Framework :: Paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,286 @@
+MANIFEST.in
+setup.cfg
+setup.py
+Paste.egg-info/PKG-INFO
+Paste.egg-info/SOURCES.txt
+Paste.egg-info/dependency_links.txt
+Paste.egg-info/entry_points.txt
+Paste.egg-info/namespace_packages.txt
+Paste.egg-info/not-zip-safe
+Paste.egg-info/requires.txt
+Paste.egg-info/top_level.txt
+docs/DeveloperGuidelines.txt
+docs/StyleGuide.txt
+docs/conf.py
+docs/developer-features.txt
+docs/do-it-yourself-framework.txt
+docs/future.txt
+docs/index.txt
+docs/license.txt
+docs/news.txt
+docs/paste-httpserver-threadpool.txt
+docs/testing-applications.txt
+docs/url-parsing-with-wsgi.txt
+docs/_build/DeveloperGuidelines.html
+docs/_build/StyleGuide.html
+docs/_build/developer-features.html
+docs/_build/do-it-yourself-framework.html
+docs/_build/future.html
+docs/_build/genindex.html
+docs/_build/index.html
+docs/_build/license.html
+docs/_build/modindex.html
+docs/_build/news.html
+docs/_build/paste-httpserver-threadpool.html
+docs/_build/py-modindex.html
+docs/_build/search.html
+docs/_build/testing-applications.html
+docs/_build/url-parsing-with-wsgi.html
+docs/_build/community/index.html
+docs/_build/community/mailing-list.html
+docs/_build/community/repository.html
+docs/_build/download/index.html
+docs/_build/include/contact.html
+docs/_build/include/reference_header.html
+docs/_build/modules/auth.auth_tkt.html
+docs/_build/modules/auth.basic.html
+docs/_build/modules/auth.cas.html
+docs/_build/modules/auth.cookie.html
+docs/_build/modules/auth.digest.html
+docs/_build/modules/auth.form.html
+docs/_build/modules/auth.grantip.html
+docs/_build/modules/auth.multi.html
+docs/_build/modules/auth.open_id.html
+docs/_build/modules/cascade.html
+docs/_build/modules/cgiapp.html
+docs/_build/modules/cgitb_catcher.html
+docs/_build/modules/debug.debugapp.html
+docs/_build/modules/debug.fsdiff.html
+docs/_build/modules/debug.prints.html
+docs/_build/modules/debug.profile.html
+docs/_build/modules/debug.watchthreads.html
+docs/_build/modules/debug.wdg_validate.html
+docs/_build/modules/errordocument.html
+docs/_build/modules/evalexception.html
+docs/_build/modules/exceptions.html
+docs/_build/modules/fileapp.html
+docs/_build/modules/fixture.html
+docs/_build/modules/gzipper.html
+docs/_build/modules/httpexceptions.html
+docs/_build/modules/httpheaders.html
+docs/_build/modules/httpserver.html
+docs/_build/modules/lint.html
+docs/_build/modules/pony.html
+docs/_build/modules/progress.html
+docs/_build/modules/proxy.html
+docs/_build/modules/recursive.html
+docs/_build/modules/registry.html
+docs/_build/modules/reloader.html
+docs/_build/modules/request.html
+docs/_build/modules/response.html
+docs/_build/modules/session.html
+docs/_build/modules/transaction.html
+docs/_build/modules/translogger.html
+docs/_build/modules/url.html
+docs/_build/modules/urlmap.html
+docs/_build/modules/urlparser.html
+docs/_build/modules/util.import_string.html
+docs/_build/modules/util.multidict.html
+docs/_build/modules/wsgilib.html
+docs/_build/modules/wsgiwrappers.html
+docs/community/index.txt
+docs/community/mailing-list.txt
+docs/community/repository.txt
+docs/download/index.txt
+docs/include/contact.txt
+docs/include/reference_header.txt
+docs/modules/auth.auth_tkt.txt
+docs/modules/auth.basic.txt
+docs/modules/auth.cas.txt
+docs/modules/auth.cookie.txt
+docs/modules/auth.digest.txt
+docs/modules/auth.form.txt
+docs/modules/auth.grantip.txt
+docs/modules/auth.multi.txt
+docs/modules/cascade.txt
+docs/modules/cgiapp.txt
+docs/modules/cgitb_catcher.txt
+docs/modules/debug.debugapp.txt
+docs/modules/debug.fsdiff.txt
+docs/modules/debug.prints.txt
+docs/modules/debug.profile.txt
+docs/modules/debug.watchthreads.txt
+docs/modules/debug.wdg_validate.txt
+docs/modules/errordocument.txt
+docs/modules/evalexception.txt
+docs/modules/exceptions.txt
+docs/modules/fileapp.txt
+docs/modules/fixture.txt
+docs/modules/gzipper.txt
+docs/modules/httpexceptions.txt
+docs/modules/httpheaders.txt
+docs/modules/httpserver.txt
+docs/modules/lint.txt
+docs/modules/pony.txt
+docs/modules/progress.txt
+docs/modules/proxy.txt
+docs/modules/recursive.txt
+docs/modules/registry.txt
+docs/modules/reloader.txt
+docs/modules/request.txt
+docs/modules/response.txt
+docs/modules/session.txt
+docs/modules/transaction.txt
+docs/modules/translogger.txt
+docs/modules/url.txt
+docs/modules/urlmap.txt
+docs/modules/urlparser.txt
+docs/modules/util.import_string.txt
+docs/modules/util.multidict.txt
+docs/modules/wsgilib.txt
+docs/modules/wsgiwrappers.txt
+paste/__init__.py
+paste/cascade.py
+paste/cgiapp.py
+paste/cgitb_catcher.py
+paste/config.py
+paste/errordocument.py
+paste/fileapp.py
+paste/fixture.py
+paste/flup_session.py
+paste/gzipper.py
+paste/httpexceptions.py
+paste/httpheaders.py
+paste/httpserver.py
+paste/lint.py
+paste/modpython.py
+paste/pony.py
+paste/progress.py
+paste/proxy.py
+paste/recursive.py
+paste/registry.py
+paste/reloader.py
+paste/request.py
+paste/response.py
+paste/session.py
+paste/transaction.py
+paste/translogger.py
+paste/url.py
+paste/urlmap.py
+paste/urlparser.py
+paste/wsgilib.py
+paste/wsgiwrappers.py
+paste/auth/__init__.py
+paste/auth/auth_tkt.py
+paste/auth/basic.py
+paste/auth/cas.py
+paste/auth/cookie.py
+paste/auth/digest.py
+paste/auth/form.py
+paste/auth/grantip.py
+paste/auth/multi.py
+paste/auth/open_id.py
+paste/cowbell/__init__.py
+paste/debug/__init__.py
+paste/debug/debugapp.py
+paste/debug/doctest_webapp.py
+paste/debug/fsdiff.py
+paste/debug/prints.py
+paste/debug/profile.py
+paste/debug/testserver.py
+paste/debug/watchthreads.py
+paste/debug/wdg_validate.py
+paste/evalexception/__init__.py
+paste/evalexception/evalcontext.py
+paste/evalexception/middleware.py
+paste/evalexception/media/MochiKit.packed.js
+paste/evalexception/media/debug.js
+paste/evalexception/media/minus.jpg
+paste/evalexception/media/plus.jpg
+paste/exceptions/__init__.py
+paste/exceptions/collector.py
+paste/exceptions/errormiddleware.py
+paste/exceptions/formatter.py
+paste/exceptions/reporter.py
+paste/exceptions/serial_number_generator.py
+paste/util/PySourceColor.py
+paste/util/UserDict24.py
+paste/util/__init__.py
+paste/util/classinit.py
+paste/util/classinstance.py
+paste/util/converters.py
+paste/util/dateinterval.py
+paste/util/datetimeutil.py
+paste/util/doctest24.py
+paste/util/filemixin.py
+paste/util/finddata.py
+paste/util/findpackage.py
+paste/util/import_string.py
+paste/util/intset.py
+paste/util/ip4.py
+paste/util/killthread.py
+paste/util/looper.py
+paste/util/mimeparse.py
+paste/util/multidict.py
+paste/util/quoting.py
+paste/util/scgiserver.py
+paste/util/string24.py
+paste/util/subprocess24.py
+paste/util/template.py
+paste/util/threadedprint.py
+paste/util/threadinglocal.py
+tests/__init__.py
+tests/test_cgiapp.py
+tests/test_cgitb_catcher.py
+tests/test_config.py
+tests/test_doctests.py
+tests/test_errordocument.py
+tests/test_fileapp.py
+tests/test_fixture.py
+tests/test_grantip.py
+tests/test_gzipper.py
+tests/test_httpheaders.py
+tests/test_import_string.py
+tests/test_multidict.py
+tests/test_profilemiddleware.py
+tests/test_proxy.py
+tests/test_recursive.py
+tests/test_registry.py
+tests/test_request.py
+tests/test_request_form.py
+tests/test_response.py
+tests/test_session.py
+tests/test_template.txt
+tests/test_urlmap.py
+tests/test_urlparser.py
+tests/test_wsgiwrappers.py
+tests/test_auth/__init__.py
+tests/test_auth/test_auth_cookie.py
+tests/test_auth/test_auth_digest.py
+tests/test_exceptions/__init__.py
+tests/test_exceptions/test_error_middleware.py
+tests/test_exceptions/test_formatter.py
+tests/test_exceptions/test_httpexceptions.py
+tests/test_exceptions/test_reporter.py
+tests/test_util/__init__.py
+tests/test_util/test_datetimeutil.py
+tests/test_util/test_mimeparse.py
+tests/urlparser_data/__init__.py
+tests/urlparser_data/secured.txt
+tests/urlparser_data/deep/sub/Main.txt
+tests/urlparser_data/find_file/index.txt
+tests/urlparser_data/hook/__init__.py
+tests/urlparser_data/hook/app.py
+tests/urlparser_data/hook/index.py
+tests/urlparser_data/not_found/__init__.py
+tests/urlparser_data/not_found/recur/__init__.py
+tests/urlparser_data/not_found/recur/isfound.txt
+tests/urlparser_data/not_found/simple/__init__.py
+tests/urlparser_data/not_found/simple/found.txt
+tests/urlparser_data/not_found/user/__init__.py
+tests/urlparser_data/not_found/user/list.py
+tests/urlparser_data/python/__init__.py
+tests/urlparser_data/python/simpleapp.py
+tests/urlparser_data/python/stream.py
+tests/urlparser_data/python/sub/__init__.py
+tests/urlparser_data/python/sub/simpleapp.py
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/entry_points.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/entry_points.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/entry_points.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+
+ [paste.app_factory]
+ cgi = paste.cgiapp:make_cgi_application [subprocess]
+ static = paste.urlparser:make_static
+ pkg_resources = paste.urlparser:make_pkg_resources
+ urlparser = paste.urlparser:make_url_parser
+ proxy = paste.proxy:make_proxy
+ test = paste.debug.debugapp:make_test_app
+ test_slow = paste.debug.debugapp:make_slow_app
+ transparent_proxy = paste.proxy:make_transparent_proxy
+ watch_threads = paste.debug.watchthreads:make_watch_threads
+
+ [paste.composite_factory]
+ urlmap = paste.urlmap:urlmap_factory
+ cascade = paste.cascade:make_cascade
+
+ [paste.filter_app_factory]
+ error_catcher = paste.exceptions.errormiddleware:make_error_middleware
+ cgitb = paste.cgitb_catcher:make_cgitb_middleware
+ flup_session = paste.flup_session:make_session_middleware [Flup]
+ gzip = paste.gzipper:make_gzip_middleware
+ httpexceptions = paste.httpexceptions:make_middleware
+ lint = paste.lint:make_middleware
+ printdebug = paste.debug.prints:PrintDebugMiddleware
+ profile = paste.debug.profile:make_profile_middleware [hotshot]
+ recursive = paste.recursive:make_recursive_middleware
+ # This isn't good enough to deserve the name egg:Paste#session:
+ paste_session = paste.session:make_session_middleware
+ wdg_validate = paste.debug.wdg_validate:make_wdg_validate_middleware [subprocess]
+ evalerror = paste.evalexception.middleware:make_eval_exception
+ auth_tkt = paste.auth.auth_tkt:make_auth_tkt_middleware
+ auth_basic = paste.auth.basic:make_basic
+ auth_digest = paste.auth.digest:make_digest
+ auth_form = paste.auth.form:make_form
+ grantip = paste.auth.grantip:make_grantip
+ openid = paste.auth.open_id:make_open_id_middleware [openid]
+ pony = paste.pony:make_pony
+ cowbell = paste.cowbell:make_cowbell
+ errordocument = paste.errordocument:make_errordocument
+ auth_cookie = paste.auth.cookie:make_auth_cookie
+ translogger = paste.translogger:make_filter
+ config = paste.config:make_config_filter
+ registry = paste.registry:make_registry_manager
+
+ [paste.server_runner]
+ http = paste.httpserver:server_runner
+
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/namespace_packages.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/namespace_packages.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/namespace_packages.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/requires.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/requires.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/requires.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,15 @@
+
+
+[Flup]
+flup
+
+[openid]
+python-openid
+
+[Paste]
+
+
+[hotshot]
+
+
+[subprocess]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ # don't prevent use of paste if pkg_resources isn't installed
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
+
+try:
+ import modulefinder
+except ImportError:
+ pass
+else:
+ for p in __path__:
+ modulefinder.AddPackagePath(__name__, p)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Package for authentication/identification of requests.
+
+The objective of this package is to provide single-focused middleware
+components that implement a particular specification. Integration of
+the components into a usable system is up to a higher-level framework.
+"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/auth_tkt.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/auth_tkt.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/auth_tkt.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,396 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+##########################################################################
+#
+# Copyright (c) 2005 Imaginary Landscape LLC and Contributors.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+##########################################################################
+"""
+Implementation of cookie signing as done in `mod_auth_tkt
+<http://www.openfusion.com.au/labs/mod_auth_tkt/>`_.
+
+mod_auth_tkt is an Apache module that looks for these signed cookies
+and sets ``REMOTE_USER``, ``REMOTE_USER_TOKENS`` (a comma-separated
+list of groups) and ``REMOTE_USER_DATA`` (arbitrary string data).
+
+This module is an alternative to the ``paste.auth.cookie`` module;
+it's primary benefit is compatibility with mod_auth_tkt, which in turn
+makes it possible to use the same authentication process with
+non-Python code run under Apache.
+"""
+
+import time as time_mod
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import Cookie
+from paste import request
+from urllib import quote as url_quote
+from urllib import unquote as url_unquote
+
+
+class AuthTicket(object):
+
+ """
+ This class represents an authentication token. You must pass in
+ the shared secret, the userid, and the IP address. Optionally you
+ can include tokens (a list of strings, representing role names),
+ 'user_data', which is arbitrary data available for your own use in
+ later scripts. Lastly, you can override the cookie name and
+ timestamp.
+
+ Once you provide all the arguments, use .cookie_value() to
+ generate the appropriate authentication ticket. .cookie()
+ generates a Cookie object, the str() of which is the complete
+ cookie header to be sent.
+
+ CGI usage::
+
+ token = auth_tkt.AuthTick('sharedsecret', 'username',
+ os.environ['REMOTE_ADDR'], tokens=['admin'])
+ print 'Status: 200 OK'
+ print 'Content-type: text/html'
+ print token.cookie()
+ print
+ ... redirect HTML ...
+
+ Webware usage::
+
+ token = auth_tkt.AuthTick('sharedsecret', 'username',
+ self.request().environ()['REMOTE_ADDR'], tokens=['admin'])
+ self.response().setCookie('auth_tkt', token.cookie_value())
+
+ Be careful not to do an HTTP redirect after login; use meta
+ refresh or Javascript -- some browsers have bugs where cookies
+ aren't saved when set on a redirect.
+ """
+
+ def __init__(self, secret, userid, ip, tokens=(), user_data='',
+ time=None, cookie_name='auth_tkt',
+ secure=False):
+ self.secret = secret
+ self.userid = userid
+ self.ip = ip
+ self.tokens = ','.join(tokens)
+ self.user_data = user_data
+ if time is None:
+ self.time = time_mod.time()
+ else:
+ self.time = time
+ self.cookie_name = cookie_name
+ self.secure = secure
+
+ def digest(self):
+ return calculate_digest(
+ self.ip, self.time, self.secret, self.userid, self.tokens,
+ self.user_data)
+
+ def cookie_value(self):
+ v = '%s%08x%s!' % (self.digest(), int(self.time), url_quote(self.userid))
+ if self.tokens:
+ v += self.tokens + '!'
+ v += self.user_data
+ return v
+
+ def cookie(self):
+ c = Cookie.SimpleCookie()
+ c[self.cookie_name] = self.cookie_value().encode('base64').strip().replace('\n', '')
+ c[self.cookie_name]['path'] = '/'
+ if self.secure:
+ c[self.cookie_name]['secure'] = 'true'
+ return c
+
+
+class BadTicket(Exception):
+ """
+ Exception raised when a ticket can't be parsed. If we get
+ far enough to determine what the expected digest should have
+ been, expected is set. This should not be shown by default,
+ but can be useful for debugging.
+ """
+ def __init__(self, msg, expected=None):
+ self.expected = expected
+ Exception.__init__(self, msg)
+
+
+def parse_ticket(secret, ticket, ip):
+ """
+ Parse the ticket, returning (timestamp, userid, tokens, user_data).
+
+ If the ticket cannot be parsed, ``BadTicket`` will be raised with
+ an explanation.
+ """
+ ticket = ticket.strip('"')
+ digest = ticket[:32]
+ try:
+ timestamp = int(ticket[32:40], 16)
+ except ValueError, e:
+ raise BadTicket('Timestamp is not a hex integer: %s' % e)
+ try:
+ userid, data = ticket[40:].split('!', 1)
+ except ValueError:
+ raise BadTicket('userid is not followed by !')
+ userid = url_unquote(userid)
+ if '!' in data:
+ tokens, user_data = data.split('!', 1)
+ else:
+ # @@: Is this the right order?
+ tokens = ''
+ user_data = data
+
+ expected = calculate_digest(ip, timestamp, secret,
+ userid, tokens, user_data)
+
+ if expected != digest:
+ raise BadTicket('Digest signature is not correct',
+ expected=(expected, digest))
+
+ tokens = tokens.split(',')
+
+ return (timestamp, userid, tokens, user_data)
+
+
+def calculate_digest(ip, timestamp, secret, userid, tokens, user_data):
+ secret = maybe_encode(secret)
+ userid = maybe_encode(userid)
+ tokens = maybe_encode(tokens)
+ user_data = maybe_encode(user_data)
+ digest0 = md5(
+ encode_ip_timestamp(ip, timestamp) + secret + userid + '\0'
+ + tokens + '\0' + user_data).hexdigest()
+ digest = md5(digest0 + secret).hexdigest()
+ return digest
+
+
+def encode_ip_timestamp(ip, timestamp):
+ ip_chars = ''.join(map(chr, map(int, ip.split('.'))))
+ t = int(timestamp)
+ ts = ((t & 0xff000000) >> 24,
+ (t & 0xff0000) >> 16,
+ (t & 0xff00) >> 8,
+ t & 0xff)
+ ts_chars = ''.join(map(chr, ts))
+ return ip_chars + ts_chars
+
+
+def maybe_encode(s, encoding='utf8'):
+ if isinstance(s, unicode):
+ s = s.encode(encoding)
+ return s
+
+
+class AuthTKTMiddleware(object):
+
+ """
+ Middleware that checks for signed cookies that match what
+ `mod_auth_tkt <http://www.openfusion.com.au/labs/mod_auth_tkt/>`_
+ looks for (if you have mod_auth_tkt installed, you don't need this
+ middleware, since Apache will set the environmental variables for
+ you).
+
+ Arguments:
+
+ ``secret``:
+ A secret that should be shared by any instances of this application.
+ If this app is served from more than one machine, they should all
+ have the same secret.
+
+ ``cookie_name``:
+ The name of the cookie to read and write from. Default ``auth_tkt``.
+
+ ``secure``:
+ If the cookie should be set as 'secure' (only sent over SSL) and if
+ the login must be over SSL. (Defaults to False)
+
+ ``httponly``:
+ If the cookie should be marked as HttpOnly, which means that it's
+ not accessible to JavaScript. (Defaults to False)
+
+ ``include_ip``:
+ If the cookie should include the user's IP address. If so, then
+ if they change IPs their cookie will be invalid.
+
+ ``logout_path``:
+ The path under this middleware that should signify a logout. The
+ page will be shown as usual, but the user will also be logged out
+ when they visit this page.
+
+ If used with mod_auth_tkt, then these settings (except logout_path) should
+ match the analogous Apache configuration settings.
+
+ This also adds two functions to the request:
+
+ ``environ['paste.auth_tkt.set_user'](userid, tokens='', user_data='')``
+
+ This sets a cookie that logs the user in. ``tokens`` is a
+ string (comma-separated groups) or a list of strings.
+ ``user_data`` is a string for your own use.
+
+ ``environ['paste.auth_tkt.logout_user']()``
+
+ Logs out the user.
+ """
+
+ def __init__(self, app, secret, cookie_name='auth_tkt', secure=False,
+ include_ip=True, logout_path=None, httponly=False,
+ no_domain_cookie=True, current_domain_cookie=True,
+ wildcard_cookie=True):
+ self.app = app
+ self.secret = secret
+ self.cookie_name = cookie_name
+ self.secure = secure
+ self.httponly = httponly
+ self.include_ip = include_ip
+ self.logout_path = logout_path
+ self.no_domain_cookie = no_domain_cookie
+ self.current_domain_cookie = current_domain_cookie
+ self.wildcard_cookie = wildcard_cookie
+
+ def __call__(self, environ, start_response):
+ cookies = request.get_cookies(environ)
+ if self.cookie_name in cookies:
+ cookie_value = cookies[self.cookie_name].value
+ else:
+ cookie_value = ''
+ if cookie_value:
+ if self.include_ip:
+ remote_addr = environ['REMOTE_ADDR']
+ else:
+ # mod_auth_tkt uses this dummy value when IP is not
+ # checked:
+ remote_addr = '0.0.0.0'
+ # @@: This should handle bad signatures better:
+ # Also, timeouts should cause cookie refresh
+ try:
+ timestamp, userid, tokens, user_data = parse_ticket(
+ self.secret, cookie_value, remote_addr)
+ tokens = ','.join(tokens)
+ environ['REMOTE_USER'] = userid
+ if environ.get('REMOTE_USER_TOKENS'):
+ # We want to add tokens/roles to what's there:
+ tokens = environ['REMOTE_USER_TOKENS'] + ',' + tokens
+ environ['REMOTE_USER_TOKENS'] = tokens
+ environ['REMOTE_USER_DATA'] = user_data
+ environ['AUTH_TYPE'] = 'cookie'
+ except BadTicket:
+ # bad credentials, just ignore without logging the user
+ # in or anything
+ pass
+ set_cookies = []
+
+ def set_user(userid, tokens='', user_data=''):
+ set_cookies.extend(self.set_user_cookie(
+ environ, userid, tokens, user_data))
+
+ def logout_user():
+ set_cookies.extend(self.logout_user_cookie(environ))
+
+ environ['paste.auth_tkt.set_user'] = set_user
+ environ['paste.auth_tkt.logout_user'] = logout_user
+ if self.logout_path and environ.get('PATH_INFO') == self.logout_path:
+ logout_user()
+
+ def cookie_setting_start_response(status, headers, exc_info=None):
+ headers.extend(set_cookies)
+ return start_response(status, headers, exc_info)
+
+ return self.app(environ, cookie_setting_start_response)
+
+ def set_user_cookie(self, environ, userid, tokens, user_data):
+ if not isinstance(tokens, basestring):
+ tokens = ','.join(tokens)
+ if self.include_ip:
+ remote_addr = environ['REMOTE_ADDR']
+ else:
+ remote_addr = '0.0.0.0'
+ ticket = AuthTicket(
+ self.secret,
+ userid,
+ remote_addr,
+ tokens=tokens,
+ user_data=user_data,
+ cookie_name=self.cookie_name,
+ secure=self.secure)
+ # @@: Should we set REMOTE_USER etc in the current
+ # environment right now as well?
+ cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
+ wild_domain = '.' + cur_domain
+
+ cookie_options = ""
+ if self.secure:
+ cookie_options += "; secure"
+ if self.httponly:
+ cookie_options += "; HttpOnly"
+
+ cookies = []
+ if self.no_domain_cookie:
+ cookies.append(('Set-Cookie', '%s=%s; Path=/%s' % (
+ self.cookie_name, ticket.cookie_value(), cookie_options)))
+ if self.current_domain_cookie:
+ cookies.append(('Set-Cookie', '%s=%s; Path=/; Domain=%s%s' % (
+ self.cookie_name, ticket.cookie_value(), cur_domain,
+ cookie_options)))
+ if self.wildcard_cookie:
+ cookies.append(('Set-Cookie', '%s=%s; Path=/; Domain=%s%s' % (
+ self.cookie_name, ticket.cookie_value(), wild_domain,
+ cookie_options)))
+
+ return cookies
+
+ def logout_user_cookie(self, environ):
+ cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
+ wild_domain = '.' + cur_domain
+ expires = 'Sat, 01-Jan-2000 12:00:00 GMT'
+ cookies = [
+ ('Set-Cookie', '%s=""; Expires="%s"; Path=/' % (self.cookie_name, expires)),
+ ('Set-Cookie', '%s=""; Expires="%s"; Path=/; Domain=%s' %
+ (self.cookie_name, expires, cur_domain)),
+ ('Set-Cookie', '%s=""; Expires="%s"; Path=/; Domain=%s' %
+ (self.cookie_name, expires, wild_domain)),
+ ]
+ return cookies
+
+
+def make_auth_tkt_middleware(
+ app,
+ global_conf,
+ secret=None,
+ cookie_name='auth_tkt',
+ secure=False,
+ include_ip=True,
+ logout_path=None):
+ """
+ Creates the `AuthTKTMiddleware
+ <class-paste.auth.auth_tkt.AuthTKTMiddleware.html>`_.
+
+ ``secret`` is requird, but can be set globally or locally.
+ """
+ from paste.deploy.converters import asbool
+ secure = asbool(secure)
+ include_ip = asbool(include_ip)
+ if secret is None:
+ secret = global_conf.get('secret')
+ if not secret:
+ raise ValueError(
+ "You must provide a 'secret' (in global or local configuration)")
+ return AuthTKTMiddleware(
+ app, secret, cookie_name, secure, include_ip, logout_path or None)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/basic.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/basic.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/basic.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,122 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Basic HTTP/1.0 Authentication
+
+This module implements ``Basic`` authentication as described in
+HTTP/1.0 specification [1]_ . Do not use this module unless you
+are using SSL or need to work with very out-dated clients, instead
+use ``digest`` authentication.
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> # from paste.auth.basic import AuthBasicHandler
+>>> realm = 'Test Realm'
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> serve(AuthBasicHandler(dump_environ, realm, authfunc))
+serving on...
+
+.. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
+"""
+from paste.httpexceptions import HTTPUnauthorized
+from paste.httpheaders import *
+
+class AuthBasicAuthenticator(object):
+ """
+ implements ``Basic`` authentication details
+ """
+ type = 'basic'
+ def __init__(self, realm, authfunc):
+ self.realm = realm
+ self.authfunc = authfunc
+
+ def build_authentication(self):
+ head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
+ return HTTPUnauthorized(headers=head)
+
+ def authenticate(self, environ):
+ authorization = AUTHORIZATION(environ)
+ if not authorization:
+ return self.build_authentication()
+ (authmeth, auth) = authorization.split(' ', 1)
+ if 'basic' != authmeth.lower():
+ return self.build_authentication()
+ auth = auth.strip().decode('base64')
+ username, password = auth.split(':', 1)
+ if self.authfunc(environ, username, password):
+ return username
+ return self.build_authentication()
+
+ __call__ = authenticate
+
+class AuthBasicHandler(object):
+ """
+ HTTP/1.0 ``Basic`` authentication middleware
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``realm``
+
+ This is a identifier for the authority that is requesting
+ authorization. It is shown to the user and should be unique
+ within the domain it is being used.
+
+ ``authfunc``
+
+ This is a mandatory user-defined function which takes a
+ ``environ``, ``username`` and ``password`` for its first
+ three arguments. It should return ``True`` if the user is
+ authenticated.
+
+ """
+ def __init__(self, application, realm, authfunc):
+ self.application = application
+ self.authenticate = AuthBasicAuthenticator(realm, authfunc)
+
+ def __call__(self, environ, start_response):
+ username = REMOTE_USER(environ)
+ if not username:
+ result = self.authenticate(environ)
+ if isinstance(result, str):
+ AUTH_TYPE.update(environ, 'basic')
+ REMOTE_USER.update(environ, result)
+ else:
+ return result.wsgi_application(environ, start_response)
+ return self.application(environ, start_response)
+
+middleware = AuthBasicHandler
+
+__all__ = ['AuthBasicHandler']
+
+def make_basic(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via basic authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_basic
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ return AuthBasicHandler(app, realm, authfunc)
+
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cas.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cas.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cas.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,99 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+CAS 1.0 Authentication
+
+The Central Authentication System is a straight-forward single sign-on
+mechanism developed by Yale University's ITS department. It has since
+enjoyed widespread success and is deployed at many major universities
+and some corporations.
+
+ https://clearinghouse.ja-sig.org/wiki/display/CAS/Home
+ http://www.yale.edu/tp/auth/usingcasatyale.html
+
+This implementation has the goal of maintaining current path arguments
+passed to the system so that it can be used as middleware at any stage
+of processing. It has the secondary goal of allowing for other
+authentication methods to be used concurrently.
+"""
+import urllib
+from paste.request import construct_url
+from paste.httpexceptions import HTTPSeeOther, HTTPForbidden
+
+class CASLoginFailure(HTTPForbidden):
+ """ The exception raised if the authority returns 'no' """
+
+class CASAuthenticate(HTTPSeeOther):
+ """ The exception raised to authenticate the user """
+
+def AuthCASHandler(application, authority):
+ """
+ middleware to implement CAS 1.0 authentication
+
+ There are several possible outcomes:
+
+ 0. If the REMOTE_USER environment variable is already populated;
+ then this middleware is a no-op, and the request is passed along
+ to the application.
+
+ 1. If a query argument 'ticket' is found, then an attempt to
+ validate said ticket /w the authentication service done. If the
+ ticket is not validated; an 403 'Forbidden' exception is raised.
+ Otherwise, the REMOTE_USER variable is set with the NetID that
+ was validated and AUTH_TYPE is set to "cas".
+
+ 2. Otherwise, a 303 'See Other' is returned to the client directing
+ them to login using the CAS service. After logon, the service
+ will send them back to this same URL, only with a 'ticket' query
+ argument.
+
+ Parameters:
+
+ ``authority``
+
+ This is a fully-qualified URL to a CAS 1.0 service. The URL
+ should end with a '/' and have the 'login' and 'validate'
+ sub-paths as described in the CAS 1.0 documentation.
+
+ """
+ assert authority.endswith("/") and authority.startswith("http")
+ def cas_application(environ, start_response):
+ username = environ.get('REMOTE_USER','')
+ if username:
+ return application(environ, start_response)
+ qs = environ.get('QUERY_STRING','').split("&")
+ if qs and qs[-1].startswith("ticket="):
+ # assume a response from the authority
+ ticket = qs.pop().split("=", 1)[1]
+ environ['QUERY_STRING'] = "&".join(qs)
+ service = construct_url(environ)
+ args = urllib.urlencode(
+ {'service': service,'ticket': ticket})
+ requrl = authority + "validate?" + args
+ result = urllib.urlopen(requrl).read().split("\n")
+ if 'yes' == result[0]:
+ environ['REMOTE_USER'] = result[1]
+ environ['AUTH_TYPE'] = 'cas'
+ return application(environ, start_response)
+ exce = CASLoginFailure()
+ else:
+ service = construct_url(environ)
+ args = urllib.urlencode({'service': service})
+ location = authority + "login?" + args
+ exce = CASAuthenticate(location)
+ return exce.wsgi_application(environ, start_response)
+ return cas_application
+
+middleware = AuthCASHandler
+
+__all__ = ['CASLoginFailure', 'CASAuthenticate', 'AuthCASHandler' ]
+
+if '__main__' == __name__:
+ authority = "https://secure.its.yale.edu/cas/servlet/"
+ from paste.wsgilib import dump_environ
+ from paste.httpserver import serve
+ from paste.httpexceptions import *
+ serve(HTTPExceptionHandler(
+ AuthCASHandler(dump_environ, authority)))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cookie.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cookie.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/cookie.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,396 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Cookie "Saved" Authentication
+
+This authentication middleware saves the current REMOTE_USER,
+REMOTE_SESSION, and any other environment variables specified in a
+cookie so that it can be retrieved during the next request without
+requiring re-authentication. This uses a session cookie on the client
+side (so it goes away when the user closes their window) and does
+server-side expiration.
+
+Following is a very simple example where a form is presented asking for
+a user name (no actual checking), and dummy session identifier (perhaps
+corresponding to a database session id) is stored in the cookie.
+
+::
+
+ >>> from paste.httpserver import serve
+ >>> from paste.fileapp import DataApp
+ >>> from paste.httpexceptions import *
+ >>> from paste.auth.cookie import AuthCookieHandler
+ >>> from paste.wsgilib import parse_querystring
+ >>> def testapp(environ, start_response):
+ ... user = dict(parse_querystring(environ)).get('user','')
+ ... if user:
+ ... environ['REMOTE_USER'] = user
+ ... environ['REMOTE_SESSION'] = 'a-session-id'
+ ... if environ.get('REMOTE_USER'):
+ ... page = '<html><body>Welcome %s (%s)</body></html>'
+ ... page %= (environ['REMOTE_USER'], environ['REMOTE_SESSION'])
+ ... else:
+ ... page = ('<html><body><form><input name="user" />'
+ ... '<input type="submit" /></form></body></html>')
+ ... return DataApp(page, content_type="text/html")(
+ ... environ, start_response)
+ >>> serve(AuthCookieHandler(testapp))
+ serving on...
+
+"""
+
+import hmac, base64, random, time, warnings
+try:
+ from hashlib import sha1
+except ImportError:
+ # NOTE: We have to use the callable with hashlib (hashlib.sha1),
+ # otherwise hmac only accepts the sha module object itself
+ import sha as sha1
+from paste.request import get_cookies
+
+def make_time(value):
+ return time.strftime("%Y%m%d%H%M", time.gmtime(value))
+_signature_size = len(hmac.new('x', 'x', sha1).digest())
+_header_size = _signature_size + len(make_time(time.time()))
+
+# @@: Should this be using urllib.quote?
+# build encode/decode functions to safely pack away values
+_encode = [('\\', '\\x5c'), ('"', '\\x22'),
+ ('=', '\\x3d'), (';', '\\x3b')]
+_decode = [(v, k) for (k, v) in _encode]
+_decode.reverse()
+def encode(s, sublist = _encode):
+ return reduce((lambda a, (b, c): a.replace(b, c)), sublist, str(s))
+decode = lambda s: encode(s, _decode)
+
+class CookieTooLarge(RuntimeError):
+ def __init__(self, content, cookie):
+ RuntimeError.__init__("Signed cookie exceeds maximum size of 4096")
+ self.content = content
+ self.cookie = cookie
+
+_all_chars = ''.join([chr(x) for x in range(0, 255)])
+def new_secret():
+ """ returns a 64 byte secret """
+ return ''.join(random.sample(_all_chars, 64))
+
+class AuthCookieSigner(object):
+ """
+ save/restore ``environ`` entries via digially signed cookie
+
+ This class converts content into a timed and digitally signed
+ cookie, as well as having the facility to reverse this procedure.
+ If the cookie, after the content is encoded and signed exceeds the
+ maximum length (4096), then CookieTooLarge exception is raised.
+
+ The timeout of the cookie is handled on the server side for a few
+ reasons. First, if a 'Expires' directive is added to a cookie, then
+ the cookie becomes persistent (lasting even after the browser window
+ has closed). Second, the user's clock may be wrong (perhaps
+ intentionally). The timeout is specified in minutes; and expiration
+ date returned is rounded to one second.
+
+ Constructor Arguments:
+
+ ``secret``
+
+ This is a secret key if you want to syncronize your keys so
+ that the cookie will be good across a cluster of computers.
+ It is recommended via the HMAC specification (RFC 2104) that
+ the secret key be 64 bytes since this is the block size of
+ the hashing. If you do not provide a secret key, a random
+ one is generated each time you create the handler; this
+ should be sufficient for most cases.
+
+ ``timeout``
+
+ This is the time (in minutes) from which the cookie is set
+ to expire. Note that on each request a new (replacement)
+ cookie is sent, hence this is effectively a session timeout
+ parameter for your entire cluster. If you do not provide a
+ timeout, it is set at 30 minutes.
+
+ ``maxlen``
+
+ This is the maximum size of the *signed* cookie; hence the
+ actual content signed will be somewhat less. If the cookie
+ goes over this size, a ``CookieTooLarge`` exception is
+ raised so that unexpected handling of cookies on the client
+ side are avoided. By default this is set at 4k (4096 bytes),
+ which is the standard cookie size limit.
+
+ """
+ def __init__(self, secret = None, timeout = None, maxlen = None):
+ self.timeout = timeout or 30
+ if isinstance(timeout, basestring):
+ raise ValueError(
+ "Timeout must be a number (minutes), not a string (%r)"
+ % timeout)
+ self.maxlen = maxlen or 4096
+ self.secret = secret or new_secret()
+
+ def sign(self, content):
+ """
+ Sign the content returning a valid cookie (that does not
+ need to be escaped and quoted). The expiration of this
+ cookie is handled server-side in the auth() function.
+ """
+ cookie = base64.encodestring(
+ hmac.new(self.secret, content, sha1).digest() +
+ make_time(time.time() + 60*self.timeout) +
+ content)
+ cookie = cookie.replace("/", "_").replace("=", "~")
+ cookie = cookie.replace('\n', '').replace('\r', '')
+ if len(cookie) > self.maxlen:
+ raise CookieTooLarge(content, cookie)
+ return cookie
+
+ def auth(self, cookie):
+ """
+ Authenticate the cooke using the signature, verify that it
+ has not expired; and return the cookie's content
+ """
+ decode = base64.decodestring(
+ cookie.replace("_", "/").replace("~", "="))
+ signature = decode[:_signature_size]
+ expires = decode[_signature_size:_header_size]
+ content = decode[_header_size:]
+ if signature == hmac.new(self.secret, content, sha1).digest():
+ if int(expires) > int(make_time(time.time())):
+ return content
+ else:
+ # This is the normal case of an expired cookie; just
+ # don't bother doing anything here.
+ pass
+ else:
+ # This case can happen if the server is restarted with a
+ # different secret; or if the user's IP address changed
+ # due to a proxy. However, it could also be a break-in
+ # attempt -- so should it be reported?
+ pass
+
+class AuthCookieEnviron(list):
+ """
+ a list of environment keys to be saved via cookie
+
+ An instance of this object, found at ``environ['paste.auth.cookie']``
+ lists the `environ` keys that were restored from or will be added
+ to the digially signed cookie. This object can be accessed from an
+ `environ` variable by using this module's name.
+ """
+ def __init__(self, handler, scanlist):
+ list.__init__(self, scanlist)
+ self.handler = handler
+ def append(self, value):
+ if value in self:
+ return
+ list.append(self, str(value))
+
+class AuthCookieHandler(object):
+ """
+ the actual handler that should be put in your middleware stack
+
+ This middleware uses cookies to stash-away a previously authenticated
+ user (and perhaps other variables) so that re-authentication is not
+ needed. This does not implement sessions; and therefore N servers
+ can be syncronized to accept the same saved authentication if they
+ all use the same cookie_name and secret.
+
+ By default, this handler scans the `environ` for the REMOTE_USER
+ and REMOTE_SESSION key; if found, it is stored. It can be
+ configured to scan other `environ` keys as well -- but be careful
+ not to exceed 2-3k (so that the encoded and signed cookie does not
+ exceed 4k). You can ask it to handle other environment variables
+ by doing:
+
+ ``environ['paste.auth.cookie'].append('your.environ.variable')``
+
+
+ Constructor Arguments:
+
+ ``application``
+
+ This is the wrapped application which will have access to
+ the ``environ['REMOTE_USER']`` restored by this middleware.
+
+ ``cookie_name``
+
+ The name of the cookie used to store this content, by default
+ it is ``PASTE_AUTH_COOKIE``.
+
+ ``scanlist``
+
+ This is the initial set of ``environ`` keys to
+ save/restore to the signed cookie. By default is consists
+ only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any tuple
+ or list of environment keys will work. However, be
+ careful, as the total saved size is limited to around 3k.
+
+ ``signer``
+
+ This is the signer object used to create the actual cookie
+ values, by default, it is ``AuthCookieSigner`` and is passed
+ the remaining arguments to this function: ``secret``,
+ ``timeout``, and ``maxlen``.
+
+ At this time, each cookie is individually signed. To store more
+ than the 4k of data; it is possible to sub-class this object to
+ provide different ``environ_name`` and ``cookie_name``
+ """
+ environ_name = 'paste.auth.cookie'
+ cookie_name = 'PASTE_AUTH_COOKIE'
+ signer_class = AuthCookieSigner
+ environ_class = AuthCookieEnviron
+
+ def __init__(self, application, cookie_name=None, scanlist=None,
+ signer=None, secret=None, timeout=None, maxlen=None):
+ if not signer:
+ signer = self.signer_class(secret, timeout, maxlen)
+ self.signer = signer
+ self.scanlist = scanlist or ('REMOTE_USER','REMOTE_SESSION')
+ self.application = application
+ self.cookie_name = cookie_name or self.cookie_name
+
+ def __call__(self, environ, start_response):
+ if self.environ_name in environ:
+ raise AssertionError("AuthCookie already installed!")
+ scanlist = self.environ_class(self, self.scanlist)
+ jar = get_cookies(environ)
+ if jar.has_key(self.cookie_name):
+ content = self.signer.auth(jar[self.cookie_name].value)
+ if content:
+ for pair in content.split(";"):
+ (k, v) = pair.split("=")
+ k = decode(k)
+ if k not in scanlist:
+ scanlist.append(k)
+ if k in environ:
+ continue
+ environ[k] = decode(v)
+ if 'REMOTE_USER' == k:
+ environ['AUTH_TYPE'] = 'cookie'
+ environ[self.environ_name] = scanlist
+ if "paste.httpexceptions" in environ:
+ warnings.warn("Since paste.httpexceptions is hooked in your "
+ "processing chain before paste.auth.cookie, if an "
+ "HTTPRedirection is raised, the cookies this module sets "
+ "will not be included in your response.\n")
+
+ def response_hook(status, response_headers, exc_info=None):
+ """
+ Scan the environment for keys specified in the scanlist,
+ pack up their values, signs the content and issues a cookie.
+ """
+ scanlist = environ.get(self.environ_name)
+ assert scanlist and isinstance(scanlist, self.environ_class)
+ content = []
+ for k in scanlist:
+ v = environ.get(k)
+ if v is not None:
+ if type(v) is not str:
+ raise ValueError(
+ "The value of the environmental variable %r "
+ "is not a str (only str is allowed; got %r)"
+ % (k, v))
+ content.append("%s=%s" % (encode(k), encode(v)))
+ if content:
+ content = ";".join(content)
+ content = self.signer.sign(content)
+ cookie = '%s=%s; Path=/;' % (self.cookie_name, content)
+ if 'https' == environ['wsgi.url_scheme']:
+ cookie += ' secure;'
+ response_headers.append(('Set-Cookie', cookie))
+ return start_response(status, response_headers, exc_info)
+ return self.application(environ, response_hook)
+
+middleware = AuthCookieHandler
+
+# Paste Deploy entry point:
+def make_auth_cookie(
+ app, global_conf,
+ # Should this get picked up from global_conf somehow?:
+ cookie_name='PASTE_AUTH_COOKIE',
+ scanlist=('REMOTE_USER', 'REMOTE_SESSION'),
+ # signer cannot be set
+ secret=None,
+ timeout=30,
+ maxlen=4096):
+ """
+ This middleware uses cookies to stash-away a previously
+ authenticated user (and perhaps other variables) so that
+ re-authentication is not needed. This does not implement
+ sessions; and therefore N servers can be syncronized to accept the
+ same saved authentication if they all use the same cookie_name and
+ secret.
+
+ By default, this handler scans the `environ` for the REMOTE_USER
+ and REMOTE_SESSION key; if found, it is stored. It can be
+ configured to scan other `environ` keys as well -- but be careful
+ not to exceed 2-3k (so that the encoded and signed cookie does not
+ exceed 4k). You can ask it to handle other environment variables
+ by doing:
+
+ ``environ['paste.auth.cookie'].append('your.environ.variable')``
+
+ Configuration:
+
+ ``cookie_name``
+
+ The name of the cookie used to store this content, by
+ default it is ``PASTE_AUTH_COOKIE``.
+
+ ``scanlist``
+
+ This is the initial set of ``environ`` keys to
+ save/restore to the signed cookie. By default is consists
+ only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any
+ space-separated list of environment keys will work.
+ However, be careful, as the total saved size is limited to
+ around 3k.
+
+ ``secret``
+
+ The secret that will be used to sign the cookies. If you
+ don't provide one (and none is set globally) then a random
+ secret will be created. Each time the server is restarted
+ a new secret will then be created and all cookies will
+ become invalid! This can be any string value.
+
+ ``timeout``
+
+ The time to keep the cookie, expressed in minutes. This
+ is handled server-side, so a new cookie with a new timeout
+ is added to every response.
+
+ ``maxlen``
+
+ The maximum length of the cookie that is sent (default 4k,
+ which is a typical browser maximum)
+
+ """
+ if isinstance(scanlist, basestring):
+ scanlist = scanlist.split()
+ if secret is None and global_conf.get('secret'):
+ secret = global_conf['secret']
+ try:
+ timeout = int(timeout)
+ except ValueError:
+ raise ValueError('Bad value for timeout (must be int): %r'
+ % timeout)
+ try:
+ maxlen = int(maxlen)
+ except ValueError:
+ raise ValueError('Bad value for maxlen (must be int): %r'
+ % maxlen)
+ return AuthCookieHandler(
+ app, cookie_name=cookie_name, scanlist=scanlist,
+ secret=secret, timeout=timeout, maxlen=maxlen)
+
+__all__ = ['AuthCookieHandler', 'AuthCookieSigner', 'AuthCookieEnviron']
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/digest.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/digest.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/digest.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,214 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Digest HTTP/1.1 Authentication
+
+This module implements ``Digest`` authentication as described by
+RFC 2617 [1]_ .
+
+Basically, you just put this module before your application, and it
+takes care of requesting and handling authentication requests. This
+module has been tested with several common browsers "out-in-the-wild".
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> # from paste.auth.digest import digest_password, AuthDigestHandler
+>>> realm = 'Test Realm'
+>>> def authfunc(environ, realm, username):
+... return digest_password(realm, username, username)
+>>> serve(AuthDigestHandler(dump_environ, realm, authfunc))
+serving on...
+
+This code has not been audited by a security expert, please use with
+caution (or better yet, report security holes). At this time, this
+implementation does not provide for further challenges, nor does it
+support Authentication-Info header. It also uses md5, and an option
+to use sha would be a good thing.
+
+.. [1] http://www.faqs.org/rfcs/rfc2617.html
+"""
+from paste.httpexceptions import HTTPUnauthorized
+from paste.httpheaders import *
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import time, random
+from urllib import quote as url_quote
+
+def digest_password(realm, username, password):
+ """ construct the appropriate hashcode needed for HTTP digest """
+ return md5("%s:%s:%s" % (username, realm, password)).hexdigest()
+
+class AuthDigestAuthenticator(object):
+ """ implementation of RFC 2617 - HTTP Digest Authentication """
+ def __init__(self, realm, authfunc):
+ self.nonce = {} # list to prevent replay attacks
+ self.authfunc = authfunc
+ self.realm = realm
+
+ def build_authentication(self, stale = ''):
+ """ builds the authentication error """
+ nonce = md5(
+ "%s:%s" % (time.time(), random.random())).hexdigest()
+ opaque = md5(
+ "%s:%s" % (time.time(), random.random())).hexdigest()
+ self.nonce[nonce] = None
+ parts = {'realm': self.realm, 'qop': 'auth',
+ 'nonce': nonce, 'opaque': opaque }
+ if stale:
+ parts['stale'] = 'true'
+ head = ", ".join(['%s="%s"' % (k, v) for (k, v) in parts.items()])
+ head = [("WWW-Authenticate", 'Digest %s' % head)]
+ return HTTPUnauthorized(headers=head)
+
+ def compute(self, ha1, username, response, method,
+ path, nonce, nc, cnonce, qop):
+ """ computes the authentication, raises error if unsuccessful """
+ if not ha1:
+ return self.build_authentication()
+ ha2 = md5('%s:%s' % (method, path)).hexdigest()
+ if qop:
+ chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
+ else:
+ chk = "%s:%s:%s" % (ha1, nonce, ha2)
+ if response != md5(chk).hexdigest():
+ if nonce in self.nonce:
+ del self.nonce[nonce]
+ return self.build_authentication()
+ pnc = self.nonce.get(nonce,'00000000')
+ if nc <= pnc:
+ if nonce in self.nonce:
+ del self.nonce[nonce]
+ return self.build_authentication(stale = True)
+ self.nonce[nonce] = nc
+ return username
+
+ def authenticate(self, environ):
+ """ This function takes a WSGI environment and authenticates
+ the request returning authenticated user or error.
+ """
+ method = REQUEST_METHOD(environ)
+ fullpath = url_quote(SCRIPT_NAME(environ)) + url_quote(PATH_INFO(environ))
+ authorization = AUTHORIZATION(environ)
+ if not authorization:
+ return self.build_authentication()
+ (authmeth, auth) = authorization.split(" ", 1)
+ if 'digest' != authmeth.lower():
+ return self.build_authentication()
+ amap = {}
+ for itm in auth.split(", "):
+ (k,v) = [s.strip() for s in itm.split("=", 1)]
+ amap[k] = v.replace('"', '')
+ try:
+ username = amap['username']
+ authpath = amap['uri']
+ nonce = amap['nonce']
+ realm = amap['realm']
+ response = amap['response']
+ assert authpath.split("?", 1)[0] in fullpath
+ assert realm == self.realm
+ qop = amap.get('qop', '')
+ cnonce = amap.get('cnonce', '')
+ nc = amap.get('nc', '00000000')
+ if qop:
+ assert 'auth' == qop
+ assert nonce and nc
+ except:
+ return self.build_authentication()
+ ha1 = self.authfunc(environ, realm, username)
+ return self.compute(ha1, username, response, method, authpath,
+ nonce, nc, cnonce, qop)
+
+ __call__ = authenticate
+
+class AuthDigestHandler(object):
+ """
+ middleware for HTTP Digest authentication (RFC 2617)
+
+ This component follows the procedure below:
+
+ 0. If the REMOTE_USER environment variable is already populated;
+ then this middleware is a no-op, and the request is passed
+ along to the application.
+
+ 1. If the HTTP_AUTHORIZATION header was not provided or specifies
+ an algorithem other than ``digest``, then a HTTPUnauthorized
+ response is generated with the challenge.
+
+ 2. If the response is malformed or or if the user's credientials
+ do not pass muster, another HTTPUnauthorized is raised.
+
+ 3. If all goes well, and the user's credintials pass; then
+ REMOTE_USER environment variable is filled in and the
+ AUTH_TYPE is listed as 'digest'.
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``realm``
+
+ This is a identifier for the authority that is requesting
+ authorization. It is shown to the user and should be unique
+ within the domain it is being used.
+
+ ``authfunc``
+
+ This is a callback function which performs the actual
+ authentication; the signature of this callback is:
+
+ authfunc(environ, realm, username) -> hashcode
+
+ This module provides a 'digest_password' helper function
+ which can help construct the hashcode; it is recommended
+ that the hashcode is stored in a database, not the user's
+ actual password (since you only need the hashcode).
+ """
+ def __init__(self, application, realm, authfunc):
+ self.authenticate = AuthDigestAuthenticator(realm, authfunc)
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ username = REMOTE_USER(environ)
+ if not username:
+ result = self.authenticate(environ)
+ if isinstance(result, str):
+ AUTH_TYPE.update(environ,'digest')
+ REMOTE_USER.update(environ, result)
+ else:
+ return result.wsgi_application(environ, start_response)
+ return self.application(environ, start_response)
+
+middleware = AuthDigestHandler
+
+__all__ = ['digest_password', 'AuthDigestHandler' ]
+
+def make_digest(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via digest authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_digest
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ return AuthDigestHandler(app, realm, authfunc)
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/form.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/form.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/form.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,149 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Authentication via HTML Form
+
+This is a very simple HTML form login screen that asks for the username
+and password. This middleware component requires that an authorization
+function taking the name and passsword and that it be placed in your
+application stack. This class does not include any session management
+code or way to save the user's authorization; however, it is easy enough
+to put ``paste.auth.cookie`` in your application stack.
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> from paste.auth.cookie import AuthCookieHandler
+>>> from paste.auth.form import AuthFormHandler
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> serve(AuthCookieHandler(
+... AuthFormHandler(dump_environ, authfunc)))
+serving on...
+
+"""
+from paste.request import construct_url, parse_formvars
+
+TEMPLATE = """\
+<html>
+ <head><title>Please Login!</title></head>
+ <body>
+ <h1>Please Login</h1>
+ <form action="%s" method="post">
+ <dl>
+ <dt>Username:</dt>
+ <dd><input type="text" name="username"></dd>
+ <dt>Password:</dt>
+ <dd><input type="password" name="password"></dd>
+ </dl>
+ <input type="submit" name="authform" />
+ <hr />
+ </form>
+ </body>
+</html>
+"""
+
+class AuthFormHandler(object):
+ """
+ HTML-based login middleware
+
+ This causes a HTML form to be returned if ``REMOTE_USER`` is
+ not found in the ``environ``. If the form is returned, the
+ ``username`` and ``password`` combination are given to a
+ user-supplied authentication function, ``authfunc``. If this
+ is successful, then application processing continues.
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``authfunc``
+
+ This is a mandatory user-defined function which takes a
+ ``environ``, ``username`` and ``password`` for its first
+ three arguments. It should return ``True`` if the user is
+ authenticated.
+
+ ``template``
+
+ This is an optional (a default is provided) HTML
+ fragment that takes exactly one ``%s`` substution
+ argument; which *must* be used for the form's ``action``
+ to ensure that this middleware component does not alter
+ the current path. The HTML form must use ``POST`` and
+ have two input names: ``username`` and ``password``.
+
+ Since the authentication form is submitted (via ``POST``)
+ neither the ``PATH_INFO`` nor the ``QUERY_STRING`` are accessed,
+ and hence the current path remains _unaltered_ through the
+ entire authentication process. If authentication succeeds, the
+ ``REQUEST_METHOD`` is converted from a ``POST`` to a ``GET``,
+ so that a redirect is unnecessary (unlike most form auth
+ implementations)
+ """
+
+ def __init__(self, application, authfunc, template=None):
+ self.application = application
+ self.authfunc = authfunc
+ self.template = template or TEMPLATE
+
+ def __call__(self, environ, start_response):
+ username = environ.get('REMOTE_USER','')
+ if username:
+ return self.application(environ, start_response)
+
+ if 'POST' == environ['REQUEST_METHOD']:
+ formvars = parse_formvars(environ, include_get_vars=False)
+ username = formvars.get('username')
+ password = formvars.get('password')
+ if username and password:
+ if self.authfunc(environ, username, password):
+ environ['AUTH_TYPE'] = 'form'
+ environ['REMOTE_USER'] = username
+ environ['REQUEST_METHOD'] = 'GET'
+ environ['CONTENT_LENGTH'] = ''
+ environ['CONTENT_TYPE'] = ''
+ del environ['paste.parsed_formvars']
+ return self.application(environ, start_response)
+
+ content = self.template % construct_url(environ)
+ start_response("200 OK", [('Content-Type', 'text/html'),
+ ('Content-Length', str(len(content)))])
+ return [content]
+
+middleware = AuthFormHandler
+
+__all__ = ['AuthFormHandler']
+
+def make_form(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via form authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_form
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ template = kw.get('template')
+ if template is not None:
+ template = eval_import(template)
+ assert isinstance(template, str), "template must resolve to a string"
+
+ return AuthFormHandler(app, authfunc, template)
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/grantip.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/grantip.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/grantip.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,113 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Grant roles and logins based on IP address.
+"""
+from paste.util import ip4
+
+class GrantIPMiddleware(object):
+
+ """
+ On each request, ``ip_map`` is checked against ``REMOTE_ADDR``
+ and logins and roles are assigned based on that.
+
+ ``ip_map`` is a map of {ip_mask: (username, roles)}. Either
+ ``username`` or ``roles`` may be None. Roles may also be prefixed
+ with ``-``, like ``'-system'`` meaning that role should be
+ revoked. ``'__remove__'`` for a username will remove the username.
+
+ If ``clobber_username`` is true (default) then any user
+ specification will override the current value of ``REMOTE_USER``.
+ ``'__remove__'`` will always clobber the username.
+
+ ``ip_mask`` is something that `paste.util.ip4:IP4Range
+ <class-paste.util.ip4.IP4Range.html>`_ can parse. Simple IP
+ addresses, IP/mask, ip<->ip ranges, and hostnames are allowed.
+ """
+
+ def __init__(self, app, ip_map, clobber_username=True):
+ self.app = app
+ self.ip_map = []
+ for key, value in ip_map.items():
+ self.ip_map.append((ip4.IP4Range(key),
+ self._convert_user_role(value[0], value[1])))
+ self.clobber_username = clobber_username
+
+ def _convert_user_role(self, username, roles):
+ if roles and isinstance(roles, basestring):
+ roles = roles.split(',')
+ return (username, roles)
+
+ def __call__(self, environ, start_response):
+ addr = ip4.ip2int(environ['REMOTE_ADDR'], False)
+ remove_user = False
+ add_roles = []
+ for range, (username, roles) in self.ip_map:
+ if addr in range:
+ if roles:
+ add_roles.extend(roles)
+ if username == '__remove__':
+ remove_user = True
+ elif username:
+ if (not environ.get('REMOTE_USER')
+ or self.clobber_username):
+ environ['REMOTE_USER'] = username
+ if (remove_user and 'REMOTE_USER' in environ):
+ del environ['REMOTE_USER']
+ if roles:
+ self._set_roles(environ, add_roles)
+ return self.app(environ, start_response)
+
+ def _set_roles(self, environ, roles):
+ cur_roles = environ.get('REMOTE_USER_TOKENS', '').split(',')
+ # Get rid of empty roles:
+ cur_roles = filter(None, cur_roles)
+ remove_roles = []
+ for role in roles:
+ if role.startswith('-'):
+ remove_roles.append(role[1:])
+ else:
+ if role not in cur_roles:
+ cur_roles.append(role)
+ for role in remove_roles:
+ if role in cur_roles:
+ cur_roles.remove(role)
+ environ['REMOTE_USER_TOKENS'] = ','.join(cur_roles)
+
+
+def make_grantip(app, global_conf, clobber_username=False, **kw):
+ """
+ Grant roles or usernames based on IP addresses.
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#grantip
+ clobber_username = true
+ # Give localhost system role (no username):
+ 127.0.0.1 = -:system
+ # Give everyone in 192.168.0.* editor role:
+ 192.168.0.0/24 = -:editor
+ # Give one IP the username joe:
+ 192.168.0.7 = joe
+ # And one IP is should not be logged in:
+ 192.168.0.10 = __remove__:-editor
+
+ """
+ from paste.deploy.converters import asbool
+ clobber_username = asbool(clobber_username)
+ ip_map = {}
+ for key, value in kw.items():
+ if ':' in value:
+ username, role = value.split(':', 1)
+ else:
+ username = value
+ role = ''
+ if username == '-':
+ username = ''
+ if role == '-':
+ role = ''
+ ip_map[key] = value
+ return GrantIPMiddleware(app, ip_map, clobber_username)
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/multi.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/multi.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/multi.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,79 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Authentication via Multiple Methods
+
+In some environments, the choice of authentication method to be used
+depends upon the environment and is not "fixed". This middleware allows
+N authentication methods to be registered along with a goodness function
+which determines which method should be used. The following example
+demonstrates how to use both form and digest authentication in a server
+stack; by default it uses form-based authentication unless
+``*authmeth=digest`` is specified as a query argument.
+
+>>> from paste.auth import form, cookie, digest, multi
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>>
+>>> multi = multi.MultiHandler(dump_environ)
+>>> def authfunc(environ, realm, user):
+... return digest.digest_password(realm, user, user)
+>>> multi.add_method('digest', digest.middleware, "Test Realm", authfunc)
+>>> multi.set_query_argument('digest')
+>>>
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> multi.add_method('form', form.middleware, authfunc)
+>>> multi.set_default('form')
+>>> serve(cookie.middleware(multi))
+serving on...
+
+"""
+
+class MultiHandler(object):
+ """
+ Multiple Authentication Handler
+
+ This middleware provides two othogonal facilities:
+
+ - a manner to register any number of authentication middlewares
+
+ - a mechanism to register predicates which cause one of the
+ registered middlewares to be used depending upon the request
+
+ If none of the predicates returns True, then the application is
+ invoked directly without middleware
+ """
+ def __init__(self, application):
+ self.application = application
+ self.default = application
+ self.binding = {}
+ self.predicate = []
+ def add_method(self, name, factory, *args, **kwargs):
+ self.binding[name] = factory(self.application, *args, **kwargs)
+ def add_predicate(self, name, checker):
+ self.predicate.append((checker, self.binding[name]))
+ def set_default(self, name):
+ """ set default authentication method """
+ self.default = self.binding[name]
+ def set_query_argument(self, name, key = '*authmeth', value = None):
+ """ choose authentication method based on a query argument """
+ lookfor = "%s=%s" % (key, value or name)
+ self.add_predicate(name,
+ lambda environ: lookfor in environ.get('QUERY_STRING',''))
+ def __call__(self, environ, start_response):
+ for (checker, binding) in self.predicate:
+ if checker(environ):
+ return binding(environ, start_response)
+ return self.default(environ, start_response)
+
+middleware = MultiHandler
+
+__all__ = ['MultiHandler']
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/open_id.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/open_id.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/auth/open_id.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,412 @@
+# (c) 2005 Ben Bangert
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+OpenID Authentication (Consumer)
+
+OpenID is a distributed authentication system for single sign-on originally
+developed at/for LiveJournal.com.
+
+ http://openid.net/
+
+URL. You can have multiple identities in the same way you can have multiple
+URLs. All OpenID does is provide a way to prove that you own a URL (identity).
+And it does this without passing around your password, your email address, or
+anything you don't want it to. There's no profile exchange component at all:
+your profiile is your identity URL, but recipients of your identity can then
+learn more about you from any public, semantically interesting documents
+linked thereunder (FOAF, RSS, Atom, vCARD, etc.).
+
+``Note``: paste.auth.openid requires installation of the Python-OpenID
+libraries::
+
+ http://www.openidenabled.com/
+
+This module is based highly off the consumer.py that Python OpenID comes with.
+
+Using the OpenID Middleware
+===========================
+
+Using the OpenID middleware is fairly easy, the most minimal example using the
+basic login form thats included::
+
+ # Add to your wsgi app creation
+ from paste.auth import open_id
+
+ wsgi_app = open_id.middleware(wsgi_app, '/somewhere/to/store/openid/data')
+
+You will now have the OpenID form available at /oid on your site. Logging in will
+verify that the login worked.
+
+A more complete login should involve having the OpenID middleware load your own
+login page after verifying the OpenID URL so that you can retain the login
+information in your webapp (session, cookies, etc.)::
+
+ wsgi_app = open_id.middleware(wsgi_app, '/somewhere/to/store/openid/data',
+ login_redirect='/your/login/code')
+
+Your login code should then be configured to retrieve 'paste.auth.open_id' for
+the users OpenID URL. If this key does not exist, the user has not logged in.
+
+Once the login is retrieved, it should be saved in your webapp, and the user
+should be redirected to wherever they would normally go after a successful
+login.
+"""
+
+__all__ = ['AuthOpenIDHandler']
+
+import cgi
+import urlparse
+import re
+
+import paste.request
+from paste import httpexceptions
+
+def quoteattr(s):
+ qs = cgi.escape(s, 1)
+ return '"%s"' % (qs,)
+
+# You may need to manually add the openid package into your
+# python path if you don't have it installed with your system python.
+# If so, uncomment the line below, and change the path where you have
+# Python-OpenID.
+# sys.path.append('/path/to/openid/')
+
+from openid.store import filestore
+from openid.consumer import consumer
+from openid.oidutil import appendArgs
+
+class AuthOpenIDHandler(object):
+ """
+ This middleware implements OpenID Consumer behavior to authenticate a
+ URL against an OpenID Server.
+ """
+
+ def __init__(self, app, data_store_path, auth_prefix='/oid',
+ login_redirect=None, catch_401=False,
+ url_to_username=None):
+ """
+ Initialize the OpenID middleware
+
+ ``app``
+ Your WSGI app to call
+
+ ``data_store_path``
+ Directory to store crypto data in for use with OpenID servers.
+
+ ``auth_prefix``
+ Location for authentication process/verification
+
+ ``login_redirect``
+ Location to load after successful process of login
+
+ ``catch_401``
+ If true, then any 401 responses will turn into open ID login
+ requirements.
+
+ ``url_to_username``
+ A function called like ``url_to_username(environ, url)``, which should
+ return a string username. If not given, the URL will be the username.
+ """
+ store = filestore.FileOpenIDStore(data_store_path)
+ self.oidconsumer = consumer.OpenIDConsumer(store)
+
+ self.app = app
+ self.auth_prefix = auth_prefix
+ self.data_store_path = data_store_path
+ self.login_redirect = login_redirect
+ self.catch_401 = catch_401
+ self.url_to_username = url_to_username
+
+ def __call__(self, environ, start_response):
+ if environ['PATH_INFO'].startswith(self.auth_prefix):
+ # Let's load everything into a request dict to pass around easier
+ request = dict(environ=environ, start=start_response, body=[])
+ request['base_url'] = paste.request.construct_url(environ, with_path_info=False,
+ with_query_string=False)
+
+ path = re.sub(self.auth_prefix, '', environ['PATH_INFO'])
+ request['parsed_uri'] = urlparse.urlparse(path)
+ request['query'] = dict(paste.request.parse_querystring(environ))
+
+ path = request['parsed_uri'][2]
+ if path == '/' or not path:
+ return self.render(request)
+ elif path == '/verify':
+ return self.do_verify(request)
+ elif path == '/process':
+ return self.do_process(request)
+ else:
+ return self.not_found(request)
+ else:
+ if self.catch_401:
+ return self.catch_401_app_call(environ, start_response)
+ return self.app(environ, start_response)
+
+ def catch_401_app_call(self, environ, start_response):
+ """
+ Call the application, and redirect if the app returns a 401 response
+ """
+ was_401 = []
+ def replacement_start_response(status, headers, exc_info=None):
+ if int(status.split(None, 1)) == 401:
+ # @@: Do I need to append something to go back to where we
+ # came from?
+ was_401.append(1)
+ def dummy_writer(v):
+ pass
+ return dummy_writer
+ else:
+ return start_response(status, headers, exc_info)
+ app_iter = self.app(environ, replacement_start_response)
+ if was_401:
+ try:
+ list(app_iter)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ redir_url = paste.request.construct_url(environ, with_path_info=False,
+ with_query_string=False)
+ exc = httpexceptions.HTTPTemporaryRedirect(redir_url)
+ return exc.wsgi_application(environ, start_response)
+ else:
+ return app_iter
+
+ def do_verify(self, request):
+ """Process the form submission, initating OpenID verification.
+ """
+
+ # First, make sure that the user entered something
+ openid_url = request['query'].get('openid_url')
+ if not openid_url:
+ return self.render(request, 'Enter an identity URL to verify.',
+ css_class='error', form_contents=openid_url)
+
+ oidconsumer = self.oidconsumer
+
+ # Then, ask the library to begin the authorization.
+ # Here we find out the identity server that will verify the
+ # user's identity, and get a token that allows us to
+ # communicate securely with the identity server.
+ status, info = oidconsumer.beginAuth(openid_url)
+
+ # If the URL was unusable (either because of network
+ # conditions, a server error, or that the response returned
+ # was not an OpenID identity page), the library will return
+ # an error code. Let the user know that that URL is unusable.
+ if status in [consumer.HTTP_FAILURE, consumer.PARSE_ERROR]:
+ if status == consumer.HTTP_FAILURE:
+ fmt = 'Failed to retrieve <q>%s</q>'
+ else:
+ fmt = 'Could not find OpenID information in <q>%s</q>'
+
+ message = fmt % (cgi.escape(openid_url),)
+ return self.render(request, message, css_class='error', form_contents=openid_url)
+ elif status == consumer.SUCCESS:
+ # The URL was a valid identity URL. Now we construct a URL
+ # that will get us to process the server response. We will
+ # need the token from the beginAuth call when processing
+ # the response. A cookie or a session object could be used
+ # to accomplish this, but for simplicity here we just add
+ # it as a query parameter of the return-to URL.
+ return_to = self.build_url(request, 'process', token=info.token)
+
+ # Now ask the library for the URL to redirect the user to
+ # his OpenID server. It is required for security that the
+ # return_to URL must be under the specified trust_root. We
+ # just use the base_url for this server as a trust root.
+ redirect_url = oidconsumer.constructRedirect(
+ info, return_to, trust_root=request['base_url'])
+
+ # Send the redirect response
+ return self.redirect(request, redirect_url)
+ else:
+ assert False, 'Not reached'
+
+ def do_process(self, request):
+ """Handle the redirect from the OpenID server.
+ """
+ oidconsumer = self.oidconsumer
+
+ # retrieve the token from the environment (in this case, the URL)
+ token = request['query'].get('token', '')
+
+ # Ask the library to check the response that the server sent
+ # us. Status is a code indicating the response type. info is
+ # either None or a string containing more information about
+ # the return type.
+ status, info = oidconsumer.completeAuth(token, request['query'])
+
+ css_class = 'error'
+ openid_url = None
+ if status == consumer.FAILURE and info:
+ # In the case of failure, if info is non-None, it is the
+ # URL that we were verifying. We include it in the error
+ # message to help the user figure out what happened.
+ openid_url = info
+ fmt = "Verification of %s failed."
+ message = fmt % (cgi.escape(openid_url),)
+ elif status == consumer.SUCCESS:
+ # Success means that the transaction completed without
+ # error. If info is None, it means that the user cancelled
+ # the verification.
+ css_class = 'alert'
+ if info:
+ # This is a successful verification attempt. If this
+ # was a real application, we would do our login,
+ # comment posting, etc. here.
+ openid_url = info
+ if self.url_to_username:
+ username = self.url_to_username(request['environ'], openid_url)
+ else:
+ username = openid_url
+ if 'paste.auth_tkt.set_user' in request['environ']:
+ request['environ']['paste.auth_tkt.set_user'](username)
+ if not self.login_redirect:
+ fmt = ("If you had supplied a login redirect path, you would have "
+ "been redirected there. "
+ "You have successfully verified %s as your identity.")
+ message = fmt % (cgi.escape(openid_url),)
+ else:
+ # @@: This stuff doesn't make sense to me; why not a remote redirect?
+ request['environ']['paste.auth.open_id'] = openid_url
+ request['environ']['PATH_INFO'] = self.login_redirect
+ return self.app(request['environ'], request['start'])
+ #exc = httpexceptions.HTTPTemporaryRedirect(self.login_redirect)
+ #return exc.wsgi_application(request['environ'], request['start'])
+ else:
+ # cancelled
+ message = 'Verification cancelled'
+ else:
+ # Either we don't understand the code or there is no
+ # openid_url included with the error. Give a generic
+ # failure message. The library should supply debug
+ # information in a log.
+ message = 'Verification failed.'
+
+ return self.render(request, message, css_class, openid_url)
+
+ def build_url(self, request, action, **query):
+ """Build a URL relative to the server base_url, with the given
+ query parameters added."""
+ base = urlparse.urljoin(request['base_url'], self.auth_prefix + '/' + action)
+ return appendArgs(base, query)
+
+ def redirect(self, request, redirect_url):
+ """Send a redirect response to the given URL to the browser."""
+ response_headers = [('Content-type', 'text/plain'),
+ ('Location', redirect_url)]
+ request['start']('302 REDIRECT', response_headers)
+ return ["Redirecting to %s" % redirect_url]
+
+ def not_found(self, request):
+ """Render a page with a 404 return code and a message."""
+ fmt = 'The path <q>%s</q> was not understood by this server.'
+ msg = fmt % (request['parsed_uri'],)
+ openid_url = request['query'].get('openid_url')
+ return self.render(request, msg, 'error', openid_url, status='404 Not Found')
+
+ def render(self, request, message=None, css_class='alert', form_contents=None,
+ status='200 OK', title="Python OpenID Consumer"):
+ """Render a page."""
+ response_headers = [('Content-type', 'text/html')]
+ request['start'](str(status), response_headers)
+
+ self.page_header(request, title)
+ if message:
+ request['body'].append("<div class='%s'>" % (css_class,))
+ request['body'].append(message)
+ request['body'].append("</div>")
+ self.page_footer(request, form_contents)
+ return request['body']
+
+ def page_header(self, request, title):
+ """Render the page header"""
+ request['body'].append('''\
+<html>
+ <head><title>%s</title></head>
+ <style type="text/css">
+ * {
+ font-family: verdana,sans-serif;
+ }
+ body {
+ width: 50em;
+ margin: 1em;
+ }
+ div {
+ padding: .5em;
+ }
+ table {
+ margin: none;
+ padding: none;
+ }
+ .alert {
+ border: 1px solid #e7dc2b;
+ background: #fff888;
+ }
+ .error {
+ border: 1px solid #ff0000;
+ background: #ffaaaa;
+ }
+ #verify-form {
+ border: 1px solid #777777;
+ background: #dddddd;
+ margin-top: 1em;
+ padding-bottom: 0em;
+ }
+ </style>
+ <body>
+ <h1>%s</h1>
+ <p>
+ This example consumer uses the <a
+ href="http://openid.schtuff.com/">Python OpenID</a> library. It
+ just verifies that the URL that you enter is your identity URL.
+ </p>
+''' % (title, title))
+
+ def page_footer(self, request, form_contents):
+ """Render the page footer"""
+ if not form_contents:
+ form_contents = ''
+
+ request['body'].append('''\
+ <div id="verify-form">
+ <form method="get" action=%s>
+ Identity URL:
+ <input type="text" name="openid_url" value=%s />
+ <input type="submit" value="Verify" />
+ </form>
+ </div>
+ </body>
+</html>
+''' % (quoteattr(self.build_url(request, 'verify')), quoteattr(form_contents)))
+
+
+middleware = AuthOpenIDHandler
+
+def make_open_id_middleware(
+ app,
+ global_conf,
+ # Should this default to something, or inherit something from global_conf?:
+ data_store_path,
+ auth_prefix='/oid',
+ login_redirect=None,
+ catch_401=False,
+ url_to_username=None,
+ apply_auth_tkt=False,
+ auth_tkt_logout_path=None):
+ from paste.deploy.converters import asbool
+ from paste.util import import_string
+ catch_401 = asbool(catch_401)
+ if url_to_username and isinstance(url_to_username, basestring):
+ url_to_username = import_string.eval_import(url_to_username)
+ apply_auth_tkt = asbool(apply_auth_tkt)
+ new_app = AuthOpenIDHandler(
+ app, data_store_path=data_store_path, auth_prefix=auth_prefix,
+ login_redirect=login_redirect, catch_401=catch_401,
+ url_to_username=url_to_username or None)
+ if apply_auth_tkt:
+ from paste.auth import auth_tkt
+ new_app = auth_tkt.make_auth_tkt_middleware(
+ new_app, global_conf, logout_path=auth_tkt_logout_path)
+ return new_app
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cascade.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cascade.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cascade.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,133 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Cascades through several applications, so long as applications
+return ``404 Not Found``.
+"""
+from paste import httpexceptions
+from paste.util import converters
+import tempfile
+from cStringIO import StringIO
+
+__all__ = ['Cascade']
+
+def make_cascade(loader, global_conf, catch='404', **local_conf):
+ """
+ Entry point for Paste Deploy configuration
+
+ Expects configuration like::
+
+ [composit:cascade]
+ use = egg:Paste#cascade
+ # all start with 'app' and are sorted alphabetically
+ app1 = foo
+ app2 = bar
+ ...
+ catch = 404 500 ...
+ """
+ catch = map(int, converters.aslist(catch))
+ apps = []
+ for name, value in local_conf.items():
+ if not name.startswith('app'):
+ raise ValueError(
+ "Bad configuration key %r (=%r); all configuration keys "
+ "must start with 'app'"
+ % (name, value))
+ app = loader.get_app(value, global_conf=global_conf)
+ apps.append((name, app))
+ apps.sort()
+ apps = [app for name, app in apps]
+ return Cascade(apps, catch=catch)
+
+class Cascade(object):
+
+ """
+ Passed a list of applications, ``Cascade`` will try each of them
+ in turn. If one returns a status code listed in ``catch`` (by
+ default just ``404 Not Found``) then the next application is
+ tried.
+
+ If all applications fail, then the last application's failure
+ response is used.
+
+ Instances of this class are WSGI applications.
+ """
+
+ def __init__(self, applications, catch=(404,)):
+ self.apps = applications
+ self.catch_codes = {}
+ self.catch_exceptions = []
+ for error in catch:
+ if isinstance(error, str):
+ error = int(error.split(None, 1)[0])
+ if isinstance(error, httpexceptions.HTTPException):
+ exc = error
+ code = error.code
+ else:
+ exc = httpexceptions.get_exception(error)
+ code = error
+ self.catch_codes[code] = exc
+ self.catch_exceptions.append(exc)
+ self.catch_exceptions = tuple(self.catch_exceptions)
+
+ def __call__(self, environ, start_response):
+ """
+ WSGI application interface
+ """
+ failed = []
+ def repl_start_response(status, headers, exc_info=None):
+ code = int(status.split(None, 1)[0])
+ if code in self.catch_codes:
+ failed.append(None)
+ return _consuming_writer
+ return start_response(status, headers, exc_info)
+
+ try:
+ length = int(environ.get('CONTENT_LENGTH', 0) or 0)
+ except ValueError:
+ length = 0
+ if length > 0:
+ # We have to copy wsgi.input
+ copy_wsgi_input = True
+ if length > 4096 or length < 0:
+ f = tempfile.TemporaryFile()
+ if length < 0:
+ f.write(environ['wsgi.input'].read())
+ else:
+ copy_len = length
+ while copy_len > 0:
+ chunk = environ['wsgi.input'].read(min(copy_len, 4096))
+ if not chunk:
+ raise IOError("Request body truncated")
+ f.write(chunk)
+ copy_len -= len(chunk)
+ f.seek(0)
+ else:
+ f = StringIO(environ['wsgi.input'].read(length))
+ environ['wsgi.input'] = f
+ else:
+ copy_wsgi_input = False
+ for app in self.apps[:-1]:
+ environ_copy = environ.copy()
+ if copy_wsgi_input:
+ environ_copy['wsgi.input'].seek(0)
+ failed = []
+ try:
+ v = app(environ_copy, repl_start_response)
+ if not failed:
+ return v
+ else:
+ if hasattr(v, 'close'):
+ # Exhaust the iterator first:
+ list(v)
+ # then close:
+ v.close()
+ except self.catch_exceptions, e:
+ pass
+ if copy_wsgi_input:
+ environ['wsgi.input'].seek(0)
+ return self.apps[-1](environ, start_response)
+
+def _consuming_writer(s):
+ pass
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgiapp.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgiapp.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgiapp.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,276 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Application that runs a CGI script.
+"""
+import os
+import sys
+import subprocess
+import urllib
+try:
+ import select
+except ImportError:
+ select = None
+
+from paste.util import converters
+
+__all__ = ['CGIError', 'CGIApplication']
+
+class CGIError(Exception):
+ """
+ Raised when the CGI script can't be found or doesn't
+ act like a proper CGI script.
+ """
+
+class CGIApplication(object):
+
+ """
+ This object acts as a proxy to a CGI application. You pass in the
+ script path (``script``), an optional path to search for the
+ script (if the name isn't absolute) (``path``). If you don't give
+ a path, then ``$PATH`` will be used.
+ """
+
+ def __init__(self,
+ global_conf,
+ script,
+ path=None,
+ include_os_environ=True,
+ query_string=None):
+ if global_conf:
+ raise NotImplemented(
+ "global_conf is no longer supported for CGIApplication "
+ "(use make_cgi_application); please pass None instead")
+ self.script_filename = script
+ if path is None:
+ path = os.environ.get('PATH', '').split(':')
+ self.path = path
+ if '?' in script:
+ assert query_string is None, (
+ "You cannot have '?' in your script name (%r) and also "
+ "give a query_string (%r)" % (script, query_string))
+ script, query_string = script.split('?', 1)
+ if os.path.abspath(script) != script:
+ # relative path
+ for path_dir in self.path:
+ if os.path.exists(os.path.join(path_dir, script)):
+ self.script = os.path.join(path_dir, script)
+ break
+ else:
+ raise CGIError(
+ "Script %r not found in path %r"
+ % (script, self.path))
+ else:
+ self.script = script
+ self.include_os_environ = include_os_environ
+ self.query_string = query_string
+
+ def __call__(self, environ, start_response):
+ if 'REQUEST_URI' not in environ:
+ environ['REQUEST_URI'] = (
+ urllib.quote(environ.get('SCRIPT_NAME', ''))
+ + urllib.quote(environ.get('PATH_INFO', '')))
+ if self.include_os_environ:
+ cgi_environ = os.environ.copy()
+ else:
+ cgi_environ = {}
+ for name in environ:
+ # Should unicode values be encoded?
+ if (name.upper() == name
+ and isinstance(environ[name], str)):
+ cgi_environ[name] = environ[name]
+ if self.query_string is not None:
+ old = cgi_environ.get('QUERY_STRING', '')
+ if old:
+ old += '&'
+ cgi_environ['QUERY_STRING'] = old + self.query_string
+ cgi_environ['SCRIPT_FILENAME'] = self.script
+ proc = subprocess.Popen(
+ [self.script],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=cgi_environ,
+ cwd=os.path.dirname(self.script),
+ )
+ writer = CGIWriter(environ, start_response)
+ if select and sys.platform != 'win32':
+ proc_communicate(
+ proc,
+ stdin=StdinReader.from_environ(environ),
+ stdout=writer,
+ stderr=environ['wsgi.errors'])
+ else:
+ stdout, stderr = proc.communicate(StdinReader.from_environ(environ).read())
+ if stderr:
+ environ['wsgi.errors'].write(stderr)
+ writer.write(stdout)
+ if not writer.headers_finished:
+ start_response(writer.status, writer.headers)
+ return []
+
+class CGIWriter(object):
+
+ def __init__(self, environ, start_response):
+ self.environ = environ
+ self.start_response = start_response
+ self.status = '200 OK'
+ self.headers = []
+ self.headers_finished = False
+ self.writer = None
+ self.buffer = ''
+
+ def write(self, data):
+ if self.headers_finished:
+ self.writer(data)
+ return
+ self.buffer += data
+ while '\n' in self.buffer:
+ if '\r\n' in self.buffer and self.buffer.find('\r\n') < self.buffer.find('\n'):
+ line1, self.buffer = self.buffer.split('\r\n', 1)
+ else:
+ line1, self.buffer = self.buffer.split('\n', 1)
+ if not line1:
+ self.headers_finished = True
+ self.writer = self.start_response(
+ self.status, self.headers)
+ self.writer(self.buffer)
+ del self.buffer
+ del self.headers
+ del self.status
+ break
+ elif ':' not in line1:
+ raise CGIError(
+ "Bad header line: %r" % line1)
+ else:
+ name, value = line1.split(':', 1)
+ value = value.lstrip()
+ name = name.strip()
+ if name.lower() == 'status':
+ if ' ' not in value:
+ # WSGI requires this space, sometimes CGI scripts don't set it:
+ value = '%s General' % value
+ self.status = value
+ else:
+ self.headers.append((name, value))
+
+class StdinReader(object):
+
+ def __init__(self, stdin, content_length):
+ self.stdin = stdin
+ self.content_length = content_length
+
+ def from_environ(cls, environ):
+ length = environ.get('CONTENT_LENGTH')
+ if length:
+ length = int(length)
+ else:
+ length = 0
+ return cls(environ['wsgi.input'], length)
+
+ from_environ = classmethod(from_environ)
+
+ def read(self, size=None):
+ if not self.content_length:
+ return ''
+ if size is None:
+ text = self.stdin.read(self.content_length)
+ else:
+ text = self.stdin.read(min(self.content_length, size))
+ self.content_length -= len(text)
+ return text
+
+def proc_communicate(proc, stdin=None, stdout=None, stderr=None):
+ """
+ Run the given process, piping input/output/errors to the given
+ file-like objects (which need not be actual file objects, unlike
+ the arguments passed to Popen). Wait for process to terminate.
+
+ Note: this is taken from the posix version of
+ subprocess.Popen.communicate, but made more general through the
+ use of file-like objects.
+ """
+ read_set = []
+ write_set = []
+ input_buffer = ''
+ trans_nl = proc.universal_newlines and hasattr(open, 'newlines')
+
+ if proc.stdin:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ proc.stdin.flush()
+ if input:
+ write_set.append(proc.stdin)
+ else:
+ proc.stdin.close()
+ else:
+ assert stdin is None
+ if proc.stdout:
+ read_set.append(proc.stdout)
+ else:
+ assert stdout is None
+ if proc.stderr:
+ read_set.append(proc.stderr)
+ else:
+ assert stderr is None
+
+ while read_set or write_set:
+ rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+ if proc.stdin in wlist:
+ # When select has indicated that the file is writable,
+ # we can write up to PIPE_BUF bytes without risk
+ # blocking. POSIX defines PIPE_BUF >= 512
+ next, input_buffer = input_buffer, ''
+ next_len = 512-len(next)
+ if next_len:
+ next += stdin.read(next_len)
+ if not next:
+ proc.stdin.close()
+ write_set.remove(proc.stdin)
+ else:
+ bytes_written = os.write(proc.stdin.fileno(), next)
+ if bytes_written < len(next):
+ input_buffer = next[bytes_written:]
+
+ if proc.stdout in rlist:
+ data = os.read(proc.stdout.fileno(), 1024)
+ if data == "":
+ proc.stdout.close()
+ read_set.remove(proc.stdout)
+ if trans_nl:
+ data = proc._translate_newlines(data)
+ stdout.write(data)
+
+ if proc.stderr in rlist:
+ data = os.read(proc.stderr.fileno(), 1024)
+ if data == "":
+ proc.stderr.close()
+ read_set.remove(proc.stderr)
+ if trans_nl:
+ data = proc._translate_newlines(data)
+ stderr.write(data)
+
+ try:
+ proc.wait()
+ except OSError, e:
+ if e.errno != 10:
+ raise
+
+def make_cgi_application(global_conf, script, path=None, include_os_environ=None,
+ query_string=None):
+ """
+ Paste Deploy interface for :class:`CGIApplication`
+
+ This object acts as a proxy to a CGI application. You pass in the
+ script path (``script``), an optional path to search for the
+ script (if the name isn't absolute) (``path``). If you don't give
+ a path, then ``$PATH`` will be used.
+ """
+ if path is None:
+ path = global_conf.get('path') or global_conf.get('PATH')
+ include_os_environ = converters.asbool(include_os_environ)
+ return CGIApplication(
+ script, path=path, include_os_environ=include_os_environ,
+ query_string=query_string)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgitb_catcher.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgitb_catcher.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cgitb_catcher.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,116 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+WSGI middleware
+
+Captures any exceptions and prints a pretty report. See the `cgitb
+documentation <http://python.org/doc/current/lib/module-cgitb.html>`_
+for more.
+"""
+
+import cgitb
+from cStringIO import StringIO
+import sys
+
+from paste.util import converters
+
+class NoDefault(object):
+ pass
+
+class CgitbMiddleware(object):
+
+ def __init__(self, app,
+ global_conf=None,
+ display=NoDefault,
+ logdir=None,
+ context=5,
+ format="html"):
+ self.app = app
+ if global_conf is None:
+ global_conf = {}
+ if display is NoDefault:
+ display = global_conf.get('debug')
+ if isinstance(display, basestring):
+ display = converters.asbool(display)
+ self.display = display
+ self.logdir = logdir
+ self.context = int(context)
+ self.format = format
+
+ def __call__(self, environ, start_response):
+ try:
+ app_iter = self.app(environ, start_response)
+ return self.catching_iter(app_iter, environ)
+ except:
+ exc_info = sys.exc_info()
+ start_response('500 Internal Server Error',
+ [('content-type', 'text/html')],
+ exc_info)
+ response = self.exception_handler(exc_info, environ)
+ return [response]
+
+ def catching_iter(self, app_iter, environ):
+ if not app_iter:
+ raise StopIteration
+ error_on_close = False
+ try:
+ for v in app_iter:
+ yield v
+ if hasattr(app_iter, 'close'):
+ error_on_close = True
+ app_iter.close()
+ except:
+ response = self.exception_handler(sys.exc_info(), environ)
+ if not error_on_close and hasattr(app_iter, 'close'):
+ try:
+ app_iter.close()
+ except:
+ close_response = self.exception_handler(
+ sys.exc_info(), environ)
+ response += (
+ '<hr noshade>Error in .close():<br>%s'
+ % close_response)
+ yield response
+
+ def exception_handler(self, exc_info, environ):
+ dummy_file = StringIO()
+ hook = cgitb.Hook(file=dummy_file,
+ display=self.display,
+ logdir=self.logdir,
+ context=self.context,
+ format=self.format)
+ hook(*exc_info)
+ return dummy_file.getvalue()
+
+def make_cgitb_middleware(app, global_conf,
+ display=NoDefault,
+ logdir=None,
+ context=5,
+ format='html'):
+ """
+ Wraps the application in the ``cgitb`` (standard library)
+ error catcher.
+
+ display:
+ If true (or debug is set in the global configuration)
+ then the traceback will be displayed in the browser
+
+ logdir:
+ Writes logs of all errors in that directory
+
+ context:
+ Number of lines of context to show around each line of
+ source code
+ """
+ from paste.deploy.converters import asbool
+ if display is not NoDefault:
+ display = asbool(display)
+ if 'debug' in global_conf:
+ global_conf['debug'] = asbool(global_conf['debug'])
+ return CgitbMiddleware(
+ app, global_conf=global_conf,
+ display=display,
+ logdir=logdir,
+ context=context,
+ format=format)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/config.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/config.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/config.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,120 @@
+# (c) 2006 Ian Bicking, Philip Jenvey and contributors
+# Written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""Paste Configuration Middleware and Objects"""
+from paste.registry import RegistryManager, StackedObjectProxy
+
+__all__ = ['DispatchingConfig', 'CONFIG', 'ConfigMiddleware']
+
+class DispatchingConfig(StackedObjectProxy):
+ """
+ This is a configuration object that can be used globally,
+ imported, have references held onto. The configuration may differ
+ by thread (or may not).
+
+ Specific configurations are registered (and deregistered) either
+ for the process or for threads.
+ """
+ # @@: What should happen when someone tries to add this
+ # configuration to itself? Probably the conf should become
+ # resolved, and get rid of this delegation wrapper
+
+ def __init__(self, name='DispatchingConfig'):
+ super(DispatchingConfig, self).__init__(name=name)
+ self.__dict__['_process_configs'] = []
+
+ def push_thread_config(self, conf):
+ """
+ Make ``conf`` the active configuration for this thread.
+ Thread-local configuration always overrides process-wide
+ configuration.
+
+ This should be used like::
+
+ conf = make_conf()
+ dispatching_config.push_thread_config(conf)
+ try:
+ ... do stuff ...
+ finally:
+ dispatching_config.pop_thread_config(conf)
+ """
+ self._push_object(conf)
+
+ def pop_thread_config(self, conf=None):
+ """
+ Remove a thread-local configuration. If ``conf`` is given,
+ it is checked against the popped configuration and an error
+ is emitted if they don't match.
+ """
+ self._pop_object(conf)
+
+ def push_process_config(self, conf):
+ """
+ Like push_thread_config, but applies the configuration to
+ the entire process.
+ """
+ self._process_configs.append(conf)
+
+ def pop_process_config(self, conf=None):
+ self._pop_from(self._process_configs, conf)
+
+ def _pop_from(self, lst, conf):
+ popped = lst.pop()
+ if conf is not None and popped is not conf:
+ raise AssertionError(
+ "The config popped (%s) is not the same as the config "
+ "expected (%s)"
+ % (popped, conf))
+
+ def _current_obj(self):
+ try:
+ return super(DispatchingConfig, self)._current_obj()
+ except TypeError:
+ if self._process_configs:
+ return self._process_configs[-1]
+ raise AttributeError(
+ "No configuration has been registered for this process "
+ "or thread")
+ current = current_conf = _current_obj
+
+CONFIG = DispatchingConfig()
+
+no_config = object()
+class ConfigMiddleware(RegistryManager):
+ """
+ A WSGI middleware that adds a ``paste.config`` key (by default)
+ to the request environment, as well as registering the
+ configuration temporarily (for the length of the request) with
+ ``paste.config.CONFIG`` (or any other ``DispatchingConfig``
+ object).
+ """
+
+ def __init__(self, application, config, dispatching_config=CONFIG,
+ environ_key='paste.config'):
+ """
+ This delegates all requests to `application`, adding a *copy*
+ of the configuration `config`.
+ """
+ def register_config(environ, start_response):
+ popped_config = environ.get(environ_key, no_config)
+ current_config = environ[environ_key] = config.copy()
+ environ['paste.registry'].register(dispatching_config,
+ current_config)
+
+ try:
+ app_iter = application(environ, start_response)
+ finally:
+ if popped_config is no_config:
+ environ.pop(environ_key, None)
+ else:
+ environ[environ_key] = popped_config
+ return app_iter
+
+ super(self.__class__, self).__init__(register_config)
+
+def make_config_filter(app, global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return ConfigMiddleware(app, conf)
+
+make_config_middleware = ConfigMiddleware.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cowbell/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cowbell/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/cowbell/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,104 @@
+# Cowbell images: http://commons.wikimedia.org/wiki/Image:Cowbell-1.jpg
+import os
+import re
+from paste.fileapp import FileApp
+from paste.response import header_value, remove_header
+
+SOUND = "http://www.c-eye.net/eyeon/WalkenWAVS/explorestudiospace.wav"
+
+class MoreCowbell(object):
+ def __init__(self, app):
+ self.app = app
+ def __call__(self, environ, start_response):
+ path_info = environ.get('PATH_INFO', '')
+ script_name = environ.get('SCRIPT_NAME', '')
+ for filename in ['bell-ascending.png', 'bell-descending.png']:
+ if path_info == '/.cowbell/'+ filename:
+ app = FileApp(os.path.join(os.path.dirname(__file__), filename))
+ return app(environ, start_response)
+ type = []
+ body = []
+ def repl_start_response(status, headers, exc_info=None):
+ ct = header_value(headers, 'content-type')
+ if ct and ct.startswith('text/html'):
+ type.append(ct)
+ remove_header(headers, 'content-length')
+ start_response(status, headers, exc_info)
+ return body.append
+ return start_response(status, headers, exc_info)
+ app_iter = self.app(environ, repl_start_response)
+ if type:
+ # Got text/html
+ body.extend(app_iter)
+ body = ''.join(body)
+ body = insert_head(body, self.javascript.replace('__SCRIPT_NAME__', script_name))
+ body = insert_body(body, self.resources.replace('__SCRIPT_NAME__', script_name))
+ return [body]
+ else:
+ return app_iter
+
+ javascript = '''\
+<script type="text/javascript">
+var cowbellState = 'hidden';
+var lastCowbellPosition = null;
+function showSomewhere() {
+ var sec, el;
+ if (cowbellState == 'hidden') {
+ el = document.getElementById('cowbell-ascending');
+ lastCowbellPosition = [parseInt(Math.random()*(window.innerWidth-200)),
+ parseInt(Math.random()*(window.innerHeight-200))];
+ el.style.left = lastCowbellPosition[0] + 'px';
+ el.style.top = lastCowbellPosition[1] + 'px';
+ el.style.display = '';
+ cowbellState = 'ascending';
+ sec = 1;
+ } else if (cowbellState == 'ascending') {
+ document.getElementById('cowbell-ascending').style.display = 'none';
+ el = document.getElementById('cowbell-descending');
+ el.style.left = lastCowbellPosition[0] + 'px';
+ el.style.top = lastCowbellPosition[1] + 'px';
+ el.style.display = '';
+ cowbellState = 'descending';
+ sec = 1;
+ } else {
+ document.getElementById('cowbell-descending').style.display = 'none';
+ cowbellState = 'hidden';
+ sec = Math.random()*20;
+ }
+ setTimeout(showSomewhere, sec*1000);
+}
+setTimeout(showSomewhere, Math.random()*20*1000);
+</script>
+'''
+
+ resources = '''\
+<div id="cowbell-ascending" style="display: none; position: fixed">
+<img src="__SCRIPT_NAME__/.cowbell/bell-ascending.png">
+</div>
+<div id="cowbell-descending" style="display: none; position: fixed">
+<img src="__SCRIPT_NAME__/.cowbell/bell-descending.png">
+</div>
+'''
+
+def insert_head(body, text):
+ end_head = re.search(r'</head>', body, re.I)
+ if end_head:
+ return body[:end_head.start()] + text + body[end_head.end():]
+ else:
+ return text + body
+
+def insert_body(body, text):
+ end_body = re.search(r'</body>', body, re.I)
+ if end_body:
+ return body[:end_body.start()] + text + body[end_body.end():]
+ else:
+ return body + text
+
+def make_cowbell(global_conf, app):
+ return MoreCowbell(app)
+
+if __name__ == '__main__':
+ from paste.debug.debugapp import SimpleApplication
+ app = MoreCowbell(SimpleApplication())
+ from paste.httpserver import serve
+ serve(app)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Package for debugging and development tools
+"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/debugapp.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/debugapp.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/debugapp.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,79 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Various Applications for Debugging/Testing Purposes
+"""
+
+import time
+__all__ = ['SimpleApplication', 'SlowConsumer']
+
+
+class SimpleApplication(object):
+ """
+ Produces a simple web page
+ """
+ def __call__(self, environ, start_response):
+ body = "<html><body>simple</body></html>"
+ start_response("200 OK", [('Content-Type', 'text/html'),
+ ('Content-Length', str(len(body)))])
+ return [body]
+
+class SlowConsumer(object):
+ """
+ Consumes an upload slowly...
+
+ NOTE: This should use the iterator form of ``wsgi.input``,
+ but it isn't implemented in paste.httpserver.
+ """
+ def __init__(self, chunk_size = 4096, delay = 1, progress = True):
+ self.chunk_size = chunk_size
+ self.delay = delay
+ self.progress = True
+
+ def __call__(self, environ, start_response):
+ size = 0
+ total = environ.get('CONTENT_LENGTH')
+ if total:
+ remaining = int(total)
+ while remaining > 0:
+ if self.progress:
+ print "%s of %s remaining" % (remaining, total)
+ if remaining > 4096:
+ chunk = environ['wsgi.input'].read(4096)
+ else:
+ chunk = environ['wsgi.input'].read(remaining)
+ if not chunk:
+ break
+ size += len(chunk)
+ remaining -= len(chunk)
+ if self.delay:
+ time.sleep(self.delay)
+ body = "<html><body>%d bytes</body></html>" % size
+ else:
+ body = ('<html><body>\n'
+ '<form method="post" enctype="multipart/form-data">\n'
+ '<input type="file" name="file">\n'
+ '<input type="submit" >\n'
+ '</form></body></html>\n')
+ print "bingles"
+ start_response("200 OK", [('Content-Type', 'text/html'),
+ ('Content-Length', len(body))])
+ return [body]
+
+def make_test_app(global_conf):
+ return SimpleApplication()
+
+make_test_app.__doc__ = SimpleApplication.__doc__
+
+def make_slow_app(global_conf, chunk_size=4096, delay=1, progress=True):
+ from paste.deploy.converters import asbool
+ return SlowConsumer(
+ chunk_size=int(chunk_size),
+ delay=int(delay),
+ progress=asbool(progress))
+
+make_slow_app.__doc__ = SlowConsumer.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/doctest_webapp.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/doctest_webapp.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/doctest_webapp.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,435 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+#!/usr/bin/env python2.4
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+These are functions for use when doctest-testing a document.
+"""
+
+try:
+ import subprocess
+except ImportError:
+ from paste.util import subprocess24 as subprocess
+import doctest
+import os
+import sys
+import shutil
+import re
+import cgi
+import rfc822
+from cStringIO import StringIO
+from paste.util import PySourceColor
+
+
+here = os.path.abspath(__file__)
+paste_parent = os.path.dirname(
+ os.path.dirname(os.path.dirname(here)))
+
+def run(command):
+ data = run_raw(command)
+ if data:
+ print data
+
+def run_raw(command):
+ """
+ Runs the string command, returns any output.
+ """
+ proc = subprocess.Popen(command, shell=True,
+ stderr=subprocess.STDOUT,
+ stdout=subprocess.PIPE, env=_make_env())
+ data = proc.stdout.read()
+ proc.wait()
+ while data.endswith('\n') or data.endswith('\r'):
+ data = data[:-1]
+ if data:
+ data = '\n'.join(
+ [l for l in data.splitlines() if l])
+ return data
+ else:
+ return ''
+
+def run_command(command, name, and_print=False):
+ output = run_raw(command)
+ data = '$ %s\n%s' % (command, output)
+ show_file('shell-command', name, description='shell transcript',
+ data=data)
+ if and_print and output:
+ print output
+
+def _make_env():
+ env = os.environ.copy()
+ env['PATH'] = (env.get('PATH', '')
+ + ':'
+ + os.path.join(paste_parent, 'scripts')
+ + ':'
+ + os.path.join(paste_parent, 'paste', '3rd-party',
+ 'sqlobject-files', 'scripts'))
+ env['PYTHONPATH'] = (env.get('PYTHONPATH', '')
+ + ':'
+ + paste_parent)
+ return env
+
+def clear_dir(dir):
+ """
+ Clears (deletes) the given directory
+ """
+ shutil.rmtree(dir, True)
+
+def ls(dir=None, recurse=False, indent=0):
+ """
+ Show a directory listing
+ """
+ dir = dir or os.getcwd()
+ fns = os.listdir(dir)
+ fns.sort()
+ for fn in fns:
+ full = os.path.join(dir, fn)
+ if os.path.isdir(full):
+ fn = fn + '/'
+ print ' '*indent + fn
+ if os.path.isdir(full) and recurse:
+ ls(dir=full, recurse=True, indent=indent+2)
+
+default_app = None
+default_url = None
+
+def set_default_app(app, url):
+ global default_app
+ global default_url
+ default_app = app
+ default_url = url
+
+def resource_filename(fn):
+ """
+ Returns the filename of the resource -- generally in the directory
+ resources/DocumentName/fn
+ """
+ return os.path.join(
+ os.path.dirname(sys.testing_document_filename),
+ 'resources',
+ os.path.splitext(os.path.basename(sys.testing_document_filename))[0],
+ fn)
+
+def show(path_info, example_name):
+ fn = resource_filename(example_name + '.html')
+ out = StringIO()
+ assert default_app is not None, (
+ "No default_app set")
+ url = default_url + path_info
+ out.write('<span class="doctest-url"><a href="%s">%s</a></span><br>\n'
+ % (url, url))
+ out.write('<div class="doctest-example">\n')
+ proc = subprocess.Popen(
+ ['paster', 'serve' '--server=console', '--no-verbose',
+ '--url=' + path_info],
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ env=_make_env())
+ stdout, errors = proc.communicate()
+ stdout = StringIO(stdout)
+ headers = rfc822.Message(stdout)
+ content = stdout.read()
+ for header, value in headers.items():
+ if header.lower() == 'status' and int(value.split()[0]) == 200:
+ continue
+ if header.lower() in ('content-type', 'content-length'):
+ continue
+ if (header.lower() == 'set-cookie'
+ and value.startswith('_SID_')):
+ continue
+ out.write('<span class="doctest-header">%s: %s</span><br>\n'
+ % (header, value))
+ lines = [l for l in content.splitlines() if l.strip()]
+ for line in lines:
+ out.write(line + '\n')
+ if errors:
+ out.write('<pre class="doctest-errors">%s</pre>'
+ % errors)
+ out.write('</div>\n')
+ result = out.getvalue()
+ if not os.path.exists(fn):
+ f = open(fn, 'wb')
+ f.write(result)
+ f.close()
+ else:
+ f = open(fn, 'rb')
+ expected = f.read()
+ f.close()
+ if not html_matches(expected, result):
+ print 'Pages did not match. Expected from %s:' % fn
+ print '-'*60
+ print expected
+ print '='*60
+ print 'Actual output:'
+ print '-'*60
+ print result
+
+def html_matches(pattern, text):
+ regex = re.escape(pattern)
+ regex = regex.replace(r'\.\.\.', '.*')
+ regex = re.sub(r'0x[0-9a-f]+', '.*', regex)
+ regex = '^%s$' % regex
+ return re.search(regex, text)
+
+def convert_docstring_string(data):
+ if data.startswith('\n'):
+ data = data[1:]
+ lines = data.splitlines()
+ new_lines = []
+ for line in lines:
+ if line.rstrip() == '.':
+ new_lines.append('')
+ else:
+ new_lines.append(line)
+ data = '\n'.join(new_lines) + '\n'
+ return data
+
+def create_file(path, version, data):
+ data = convert_docstring_string(data)
+ write_data(path, data)
+ show_file(path, version)
+
+def append_to_file(path, version, data):
+ data = convert_docstring_string(data)
+ f = open(path, 'a')
+ f.write(data)
+ f.close()
+ # I think these appends can happen so quickly (in less than a second)
+ # that the .pyc file doesn't appear to be expired, even though it
+ # is after we've made this change; so we have to get rid of the .pyc
+ # file:
+ if path.endswith('.py'):
+ pyc_file = path + 'c'
+ if os.path.exists(pyc_file):
+ os.unlink(pyc_file)
+ show_file(path, version, description='added to %s' % path,
+ data=data)
+
+def show_file(path, version, description=None, data=None):
+ ext = os.path.splitext(path)[1]
+ if data is None:
+ f = open(path, 'rb')
+ data = f.read()
+ f.close()
+ if ext == '.py':
+ html = ('<div class="source-code">%s</div>'
+ % PySourceColor.str2html(data, PySourceColor.dark))
+ else:
+ html = '<pre class="source-code">%s</pre>' % cgi.escape(data, 1)
+ html = '<span class="source-filename">%s</span><br>%s' % (
+ description or path, html)
+ write_data(resource_filename('%s.%s.gen.html' % (path, version)),
+ html)
+
+def call_source_highlight(input, format):
+ proc = subprocess.Popen(['source-highlight', '--out-format=html',
+ '--no-doc', '--css=none',
+ '--src-lang=%s' % format], shell=False,
+ stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate(input)
+ result = stdout
+ proc.wait()
+ return result
+
+
+def write_data(path, data):
+ dir = os.path.dirname(os.path.abspath(path))
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ f = open(path, 'wb')
+ f.write(data)
+ f.close()
+
+
+def change_file(path, changes):
+ f = open(os.path.abspath(path), 'rb')
+ lines = f.readlines()
+ f.close()
+ for change_type, line, text in changes:
+ if change_type == 'insert':
+ lines[line:line] = [text]
+ elif change_type == 'delete':
+ lines[line:text] = []
+ else:
+ assert 0, (
+ "Unknown change_type: %r" % change_type)
+ f = open(path, 'wb')
+ f.write(''.join(lines))
+ f.close()
+
+class LongFormDocTestParser(doctest.DocTestParser):
+
+ """
+ This parser recognizes some reST comments as commands, without
+ prompts or expected output, like:
+
+ .. run:
+
+ do_this(...
+ ...)
+ """
+
+ _EXAMPLE_RE = re.compile(r"""
+ # Source consists of a PS1 line followed by zero or more PS2 lines.
+ (?: (?P<source>
+ (?:^(?P<indent> [ ]*) >>> .*) # PS1 line
+ (?:\n [ ]* \.\.\. .*)*) # PS2 lines
+ \n?
+ # Want consists of any non-blank lines that do not start with PS1.
+ (?P<want> (?:(?![ ]*$) # Not a blank line
+ (?![ ]*>>>) # Not a line starting with PS1
+ .*$\n? # But any other line
+ )*))
+ |
+ (?: # This is for longer commands that are prefixed with a reST
+ # comment like '.. run:' (two colons makes that a directive).
+ # These commands cannot have any output.
+
+ (?:^\.\.[ ]*(?P<run>run):[ ]*\n) # Leading command/command
+ (?:[ ]*\n)? # Blank line following
+ (?P<runsource>
+ (?:(?P<runindent> [ ]+)[^ ].*$)
+ (?:\n [ ]+ .*)*)
+ )
+ |
+ (?: # This is for shell commands
+
+ (?P<shellsource>
+ (?:^(P<shellindent> [ ]*) [$] .*) # Shell line
+ (?:\n [ ]* [>] .*)*) # Continuation
+ \n?
+ # Want consists of any non-blank lines that do not start with $
+ (?P<shellwant> (?:(?![ ]*$)
+ (?![ ]*[$]$)
+ .*$\n?
+ )*))
+ """, re.MULTILINE | re.VERBOSE)
+
+ def _parse_example(self, m, name, lineno):
+ r"""
+ Given a regular expression match from `_EXAMPLE_RE` (`m`),
+ return a pair `(source, want)`, where `source` is the matched
+ example's source code (with prompts and indentation stripped);
+ and `want` is the example's expected output (with indentation
+ stripped).
+
+ `name` is the string's name, and `lineno` is the line number
+ where the example starts; both are used for error messages.
+
+ >>> def parseit(s):
+ ... p = LongFormDocTestParser()
+ ... return p._parse_example(p._EXAMPLE_RE.search(s), '<string>', 1)
+ >>> parseit('>>> 1\n1')
+ ('1', {}, '1', None)
+ >>> parseit('>>> (1\n... +1)\n2')
+ ('(1\n+1)', {}, '2', None)
+ >>> parseit('.. run:\n\n test1\n test2\n')
+ ('test1\ntest2', {}, '', None)
+ """
+ # Get the example's indentation level.
+ runner = m.group('run') or ''
+ indent = len(m.group('%sindent' % runner))
+
+ # Divide source into lines; check that they're properly
+ # indented; and then strip their indentation & prompts.
+ source_lines = m.group('%ssource' % runner).split('\n')
+ if runner:
+ self._check_prefix(source_lines[1:], ' '*indent, name, lineno)
+ else:
+ self._check_prompt_blank(source_lines, indent, name, lineno)
+ self._check_prefix(source_lines[2:], ' '*indent + '.', name, lineno)
+ if runner:
+ source = '\n'.join([sl[indent:] for sl in source_lines])
+ else:
+ source = '\n'.join([sl[indent+4:] for sl in source_lines])
+
+ if runner:
+ want = ''
+ exc_msg = None
+ else:
+ # Divide want into lines; check that it's properly indented; and
+ # then strip the indentation. Spaces before the last newline should
+ # be preserved, so plain rstrip() isn't good enough.
+ want = m.group('want')
+ want_lines = want.split('\n')
+ if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+ del want_lines[-1] # forget final newline & spaces after it
+ self._check_prefix(want_lines, ' '*indent, name,
+ lineno + len(source_lines))
+ want = '\n'.join([wl[indent:] for wl in want_lines])
+
+ # If `want` contains a traceback message, then extract it.
+ m = self._EXCEPTION_RE.match(want)
+ if m:
+ exc_msg = m.group('msg')
+ else:
+ exc_msg = None
+
+ # Extract options from the source.
+ options = self._find_options(source, name, lineno)
+
+ return source, options, want, exc_msg
+
+
+ def parse(self, string, name='<string>'):
+ """
+ Divide the given string into examples and intervening text,
+ and return them as a list of alternating Examples and strings.
+ Line numbers for the Examples are 0-based. The optional
+ argument `name` is a name identifying this string, and is only
+ used for error messages.
+ """
+ string = string.expandtabs()
+ # If all lines begin with the same indentation, then strip it.
+ min_indent = self._min_indent(string)
+ if min_indent > 0:
+ string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+
+ output = []
+ charno, lineno = 0, 0
+ # Find all doctest examples in the string:
+ for m in self._EXAMPLE_RE.finditer(string):
+ # Add the pre-example text to `output`.
+ output.append(string[charno:m.start()])
+ # Update lineno (lines before this example)
+ lineno += string.count('\n', charno, m.start())
+ # Extract info from the regexp match.
+ (source, options, want, exc_msg) = \
+ self._parse_example(m, name, lineno)
+ # Create an Example, and add it to the list.
+ if not self._IS_BLANK_OR_COMMENT(source):
+ # @@: Erg, this is the only line I need to change...
+ output.append(doctest.Example(
+ source, want, exc_msg,
+ lineno=lineno,
+ indent=min_indent+len(m.group('indent') or m.group('runindent')),
+ options=options))
+ # Update lineno (lines inside this example)
+ lineno += string.count('\n', m.start(), m.end())
+ # Update charno.
+ charno = m.end()
+ # Add any remaining post-example text to `output`.
+ output.append(string[charno:])
+ return output
+
+
+
+if __name__ == '__main__':
+ if sys.argv[1:] and sys.argv[1] == 'doctest':
+ doctest.testmod()
+ sys.exit()
+ if not paste_parent in sys.path:
+ sys.path.append(paste_parent)
+ for fn in sys.argv[1:]:
+ fn = os.path.abspath(fn)
+ # @@: OK, ick; but this module gets loaded twice
+ sys.testing_document_filename = fn
+ doctest.testfile(
+ fn, module_relative=False,
+ optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,
+ parser=LongFormDocTestParser())
+ new = os.path.splitext(fn)[0] + '.html'
+ assert new != fn
+ os.system('rst2html.py %s > %s' % (fn, new))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/fsdiff.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/fsdiff.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/fsdiff.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,409 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Module to find differences over time in a filesystem
+
+Basically this takes a snapshot of a directory, then sees what changes
+were made. The contents of the files are not checked, so you can
+detect that the content was changed, but not what the old version of
+the file was.
+"""
+
+import os
+from fnmatch import fnmatch
+from datetime import datetime
+from paste.util.UserDict24 import IterableUserDict
+import operator
+import re
+
+__all__ = ['Diff', 'Snapshot', 'File', 'Dir', 'report_expected_diffs',
+ 'show_diff']
+
+class Diff(object):
+
+ """
+ Represents the difference between two snapshots
+ """
+
+ def __init__(self, before, after):
+ self.before = before
+ self.after = after
+ self._calculate()
+
+ def _calculate(self):
+ before = self.before.data
+ after = self.after.data
+ self.deleted = {}
+ self.updated = {}
+ self.created = after.copy()
+ for path, f in before.items():
+ if path not in after:
+ self.deleted[path] = f
+ continue
+ del self.created[path]
+ if f.mtime < after[path].mtime:
+ self.updated[path] = after[path]
+
+ def __str__(self):
+ return self.report()
+
+ def report(self, header=True, dates=False):
+ s = []
+ if header:
+ s.append('Difference in %s from %s to %s:' %
+ (self.before.base_path,
+ self.before.calculated,
+ self.after.calculated))
+ for name, files, show_size in [
+ ('created', self.created, True),
+ ('deleted', self.deleted, True),
+ ('updated', self.updated, True)]:
+ if files:
+ s.append('-- %s: -------------------' % name)
+ files = files.items()
+ files.sort()
+ last = ''
+ for path, f in files:
+ t = ' %s' % _space_prefix(last, path, indent=4,
+ include_sep=False)
+ last = path
+ if show_size and f.size != 'N/A':
+ t += ' (%s bytes)' % f.size
+ if dates:
+ parts = []
+ if self.before.get(path):
+ parts.append(self.before[path].mtime)
+ if self.after.get(path):
+ parts.append(self.after[path].mtime)
+ t += ' (mtime: %s)' % ('->'.join(map(repr, parts)))
+ s.append(t)
+ if len(s) == 1:
+ s.append(' (no changes)')
+ return '\n'.join(s)
+
+class Snapshot(IterableUserDict):
+
+ """
+ Represents a snapshot of a set of files. Has a dictionary-like
+ interface, keyed relative to ``base_path``
+ """
+
+ def __init__(self, base_path, files=None, ignore_wildcards=(),
+ ignore_paths=(), ignore_hidden=True):
+ self.base_path = base_path
+ self.ignore_wildcards = ignore_wildcards
+ self.ignore_hidden = ignore_hidden
+ self.ignore_paths = ignore_paths
+ self.calculated = None
+ self.data = files or {}
+ if files is None:
+ self.find_files()
+
+ ############################################################
+ ## File finding
+ ############################################################
+
+ def find_files(self):
+ """
+ Find all the files under the base path, and put them in
+ ``self.data``
+ """
+ self._find_traverse('', self.data)
+ self.calculated = datetime.now()
+
+ def _ignore_file(self, fn):
+ if fn in self.ignore_paths:
+ return True
+ if self.ignore_hidden and os.path.basename(fn).startswith('.'):
+ return True
+ for pat in self.ignore_wildcards:
+ if fnmatch(fn, pat):
+ return True
+ return False
+
+ def _ignore_file(self, fn):
+ if fn in self.ignore_paths:
+ return True
+ if self.ignore_hidden and os.path.basename(fn).startswith('.'):
+ return True
+ return False
+
+ def _find_traverse(self, path, result):
+ full = os.path.join(self.base_path, path)
+ if os.path.isdir(full):
+ if path:
+ # Don't actually include the base path
+ result[path] = Dir(self.base_path, path)
+ for fn in os.listdir(full):
+ fn = os.path.join(path, fn)
+ if self._ignore_file(fn):
+ continue
+ self._find_traverse(fn, result)
+ else:
+ result[path] = File(self.base_path, path)
+
+ def __repr__(self):
+ return '<%s in %r from %r>' % (
+ self.__class__.__name__, self.base_path,
+ self.calculated or '(no calculation done)')
+
+ def compare_expected(self, expected, comparison=operator.eq,
+ differ=None, not_found=None,
+ include_success=False):
+ """
+ Compares a dictionary of ``path: content`` to the
+ found files. Comparison is done by equality, or the
+ ``comparison(actual_content, expected_content)`` function given.
+
+ Returns dictionary of differences, keyed by path. Each
+ difference is either noted, or the output of
+ ``differ(actual_content, expected_content)`` is given.
+
+ If a file does not exist and ``not_found`` is given, then
+ ``not_found(path)`` is put in.
+ """
+ result = {}
+ for path in expected:
+ orig_path = path
+ path = path.strip('/')
+ if path not in self.data:
+ if not_found:
+ msg = not_found(path)
+ else:
+ msg = 'not found'
+ result[path] = msg
+ continue
+ expected_content = expected[orig_path]
+ file = self.data[path]
+ actual_content = file.bytes
+ if not comparison(actual_content, expected_content):
+ if differ:
+ msg = differ(actual_content, expected_content)
+ else:
+ if len(actual_content) < len(expected_content):
+ msg = 'differ (%i bytes smaller)' % (
+ len(expected_content) - len(actual_content))
+ elif len(actual_content) > len(expected_content):
+ msg = 'differ (%i bytes larger)' % (
+ len(actual_content) - len(expected_content))
+ else:
+ msg = 'diff (same size)'
+ result[path] = msg
+ elif include_success:
+ result[path] = 'same!'
+ return result
+
+ def diff_to_now(self):
+ return Diff(self, self.clone())
+
+ def clone(self):
+ return self.__class__(base_path=self.base_path,
+ ignore_wildcards=self.ignore_wildcards,
+ ignore_paths=self.ignore_paths,
+ ignore_hidden=self.ignore_hidden)
+
+class File(object):
+
+ """
+ Represents a single file found as the result of a command.
+
+ Has attributes:
+
+ ``path``:
+ The path of the file, relative to the ``base_path``
+
+ ``full``:
+ The full path
+
+ ``stat``:
+ The results of ``os.stat``. Also ``mtime`` and ``size``
+ contain the ``.st_mtime`` and ``st_size`` of the stat.
+
+ ``bytes``:
+ The contents of the file.
+
+ You may use the ``in`` operator with these objects (tested against
+ the contents of the file), and the ``.mustcontain()`` method.
+ """
+
+ file = True
+ dir = False
+
+ def __init__(self, base_path, path):
+ self.base_path = base_path
+ self.path = path
+ self.full = os.path.join(base_path, path)
+ self.stat = os.stat(self.full)
+ self.mtime = self.stat.st_mtime
+ self.size = self.stat.st_size
+ self._bytes = None
+
+ def bytes__get(self):
+ if self._bytes is None:
+ f = open(self.full, 'rb')
+ self._bytes = f.read()
+ f.close()
+ return self._bytes
+ bytes = property(bytes__get)
+
+ def __contains__(self, s):
+ return s in self.bytes
+
+ def mustcontain(self, s):
+ __tracebackhide__ = True
+ bytes = self.bytes
+ if s not in bytes:
+ print 'Could not find %r in:' % s
+ print bytes
+ assert s in bytes
+
+ def __repr__(self):
+ return '<%s %s:%s>' % (
+ self.__class__.__name__,
+ self.base_path, self.path)
+
+class Dir(File):
+
+ """
+ Represents a directory created by a command.
+ """
+
+ file = False
+ dir = True
+
+ def __init__(self, base_path, path):
+ self.base_path = base_path
+ self.path = path
+ self.full = os.path.join(base_path, path)
+ self.size = 'N/A'
+ self.mtime = 'N/A'
+
+ def __repr__(self):
+ return '<%s %s:%s>' % (
+ self.__class__.__name__,
+ self.base_path, self.path)
+
+ def bytes__get(self):
+ raise NotImplementedError(
+ "Directory %r doesn't have content" % self)
+
+ bytes = property(bytes__get)
+
+
+def _space_prefix(pref, full, sep=None, indent=None, include_sep=True):
+ """
+ Anything shared by pref and full will be replaced with spaces
+ in full, and full returned.
+
+ Example::
+
+ >>> _space_prefix('/foo/bar', '/foo')
+ ' /bar'
+ """
+ if sep is None:
+ sep = os.path.sep
+ pref = pref.split(sep)
+ full = full.split(sep)
+ padding = []
+ while pref and full and pref[0] == full[0]:
+ if indent is None:
+ padding.append(' ' * (len(full[0]) + len(sep)))
+ else:
+ padding.append(' ' * indent)
+ full.pop(0)
+ pref.pop(0)
+ if padding:
+ if include_sep:
+ return ''.join(padding) + sep + sep.join(full)
+ else:
+ return ''.join(padding) + sep.join(full)
+ else:
+ return sep.join(full)
+
+def report_expected_diffs(diffs, colorize=False):
+ """
+ Takes the output of compare_expected, and returns a string
+ description of the differences.
+ """
+ if not diffs:
+ return 'No differences'
+ diffs = diffs.items()
+ diffs.sort()
+ s = []
+ last = ''
+ for path, desc in diffs:
+ t = _space_prefix(last, path, indent=4, include_sep=False)
+ if colorize:
+ t = color_line(t, 11)
+ last = path
+ if len(desc.splitlines()) > 1:
+ cur_indent = len(re.search(r'^[ ]*', t).group(0))
+ desc = indent(cur_indent+2, desc)
+ if colorize:
+ t += '\n'
+ for line in desc.splitlines():
+ if line.strip().startswith('+'):
+ line = color_line(line, 10)
+ elif line.strip().startswith('-'):
+ line = color_line(line, 9)
+ else:
+ line = color_line(line, 14)
+ t += line+'\n'
+ else:
+ t += '\n' + desc
+ else:
+ t += ' '+desc
+ s.append(t)
+ s.append('Files with differences: %s' % len(diffs))
+ return '\n'.join(s)
+
+def color_code(foreground=None, background=None):
+ """
+ 0 black
+ 1 red
+ 2 green
+ 3 yellow
+ 4 blue
+ 5 magenta (purple)
+ 6 cyan
+ 7 white (gray)
+
+ Add 8 to get high-intensity
+ """
+ if foreground is None and background is None:
+ # Reset
+ return '\x1b[0m'
+ codes = []
+ if foreground is None:
+ codes.append('[39m')
+ elif foreground > 7:
+ codes.append('[1m')
+ codes.append('[%im' % (22+foreground))
+ else:
+ codes.append('[%im' % (30+foreground))
+ if background is None:
+ codes.append('[49m')
+ else:
+ codes.append('[%im' % (40+background))
+ return '\x1b' + '\x1b'.join(codes)
+
+def color_line(line, foreground=None, background=None):
+ match = re.search(r'^(\s*)', line)
+ return (match.group(1) + color_code(foreground, background)
+ + line[match.end():] + color_code())
+
+def indent(indent, text):
+ return '\n'.join(
+ [' '*indent + l for l in text.splitlines()])
+
+def show_diff(actual_content, expected_content):
+ actual_lines = [l.strip() for l in actual_content.splitlines()
+ if l.strip()]
+ expected_lines = [l.strip() for l in expected_content.splitlines()
+ if l.strip()]
+ if len(actual_lines) == len(expected_lines) == 1:
+ return '%r not %r' % (actual_lines[0], expected_lines[0])
+ if not actual_lines:
+ return 'Empty; should have:\n'+expected_content
+ import difflib
+ return '\n'.join(difflib.ndiff(actual_lines, expected_lines))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/prints.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/prints.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/prints.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,148 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware that displays everything that is printed inline in
+application pages.
+
+Anything printed during the request will get captured and included on
+the page. It will usually be included as a floating element in the
+top right hand corner of the page. If you want to override this
+you can include a tag in your template where it will be placed::
+
+ <pre id="paste-debug-prints"></pre>
+
+You might want to include ``style="white-space: normal"``, as all the
+whitespace will be quoted, and this allows the text to wrap if
+necessary.
+
+"""
+
+from cStringIO import StringIO
+import re
+import cgi
+from paste.util import threadedprint
+from paste import wsgilib
+from paste import response
+import sys
+
+_threadedprint_installed = False
+
+__all__ = ['PrintDebugMiddleware']
+
+class TeeFile(object):
+
+ def __init__(self, files):
+ self.files = files
+
+ def write(self, v):
+ if isinstance(v, unicode):
+ # WSGI is picky in this case
+ v = str(v)
+ for file in self.files:
+ file.write(v)
+
+class PrintDebugMiddleware(object):
+
+ """
+ This middleware captures all the printed statements, and inlines
+ them in HTML pages, so that you can see all the (debug-intended)
+ print statements in the page itself.
+
+ There are two keys added to the environment to control this:
+ ``environ['paste.printdebug_listeners']`` is a list of functions
+ that will be called everytime something is printed.
+
+ ``environ['paste.remove_printdebug']`` is a function that, if
+ called, will disable printing of output for that request.
+
+ If you have ``replace_stdout=True`` then stdout is replaced, not
+ captured.
+ """
+
+ log_template = (
+ '<pre style="width: 40%%; border: 2px solid #000; white-space: normal; '
+ 'background-color: #ffd; color: #000; float: right;">'
+ '<b style="border-bottom: 1px solid #000">Log messages</b><br>'
+ '%s</pre>')
+
+ def __init__(self, app, global_conf=None, force_content_type=False,
+ print_wsgi_errors=True, replace_stdout=False):
+ # @@: global_conf should be handled separately and only for
+ # the entry point
+ self.app = app
+ self.force_content_type = force_content_type
+ if isinstance(print_wsgi_errors, basestring):
+ from paste.deploy.converters import asbool
+ print_wsgi_errors = asbool(print_wsgi_errors)
+ self.print_wsgi_errors = print_wsgi_errors
+ self.replace_stdout = replace_stdout
+ self._threaded_print_stdout = None
+
+ def __call__(self, environ, start_response):
+ global _threadedprint_installed
+ if environ.get('paste.testing'):
+ # In a testing environment this interception isn't
+ # useful:
+ return self.app(environ, start_response)
+ if (not _threadedprint_installed
+ or self._threaded_print_stdout is not sys.stdout):
+ # @@: Not strictly threadsafe
+ _threadedprint_installed = True
+ threadedprint.install(leave_stdout=not self.replace_stdout)
+ self._threaded_print_stdout = sys.stdout
+ removed = []
+ def remove_printdebug():
+ removed.append(None)
+ environ['paste.remove_printdebug'] = remove_printdebug
+ logged = StringIO()
+ listeners = [logged]
+ environ['paste.printdebug_listeners'] = listeners
+ if self.print_wsgi_errors:
+ listeners.append(environ['wsgi.errors'])
+ replacement_stdout = TeeFile(listeners)
+ threadedprint.register(replacement_stdout)
+ try:
+ status, headers, body = wsgilib.intercept_output(
+ environ, self.app)
+ if status is None:
+ # Some error occurred
+ status = '500 Server Error'
+ headers = [('Content-type', 'text/html')]
+ start_response(status, headers)
+ if not body:
+ body = 'An error occurred'
+ content_type = response.header_value(headers, 'content-type')
+ if (removed or
+ (not self.force_content_type and
+ (not content_type
+ or not content_type.startswith('text/html')))):
+ if replacement_stdout == logged:
+ # Then the prints will be lost, unless...
+ environ['wsgi.errors'].write(logged.getvalue())
+ start_response(status, headers)
+ return [body]
+ response.remove_header(headers, 'content-length')
+ body = self.add_log(body, logged.getvalue())
+ start_response(status, headers)
+ return [body]
+ finally:
+ threadedprint.deregister()
+
+ _body_re = re.compile(r'<body[^>]*>', re.I)
+ _explicit_re = re.compile(r'<pre\s*[^>]*id="paste-debug-prints".*?>',
+ re.I+re.S)
+
+ def add_log(self, html, log):
+ if not log:
+ return html
+ text = cgi.escape(log)
+ text = text.replace('\n', '<br>')
+ text = text.replace(' ', ' ')
+ match = self._explicit_re.search(html)
+ if not match:
+ text = self.log_template % text
+ match = self._body_re.search(html)
+ if not match:
+ return text + html
+ else:
+ return html[:match.end()] + text + html[match.end():]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/profile.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/profile.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/profile.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,227 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware that profiles the request and displays profiling
+information at the bottom of each page.
+"""
+
+
+import sys
+import os
+import hotshot
+import hotshot.stats
+import threading
+import cgi
+import time
+from cStringIO import StringIO
+from paste import response
+
+__all__ = ['ProfileMiddleware', 'profile_decorator']
+
+class ProfileMiddleware(object):
+
+ """
+ Middleware that profiles all requests.
+
+ All HTML pages will have profiling information appended to them.
+ The data is isolated to that single request, and does not include
+ data from previous requests.
+
+ This uses the ``hotshot`` module, which affects performance of the
+ application. It also runs in a single-threaded mode, so it is
+ only usable in development environments.
+ """
+
+ style = ('clear: both; background-color: #ff9; color: #000; '
+ 'border: 2px solid #000; padding: 5px;')
+
+ def __init__(self, app, global_conf=None,
+ log_filename='profile.log.tmp',
+ limit=40):
+ self.app = app
+ self.lock = threading.Lock()
+ self.log_filename = log_filename
+ self.limit = limit
+
+ def __call__(self, environ, start_response):
+ catch_response = []
+ body = []
+ def replace_start_response(status, headers, exc_info=None):
+ catch_response.extend([status, headers])
+ start_response(status, headers, exc_info)
+ return body.append
+ def run_app():
+ app_iter = self.app(environ, replace_start_response)
+ try:
+ body.extend(app_iter)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ self.lock.acquire()
+ try:
+ prof = hotshot.Profile(self.log_filename)
+ prof.addinfo('URL', environ.get('PATH_INFO', ''))
+ try:
+ prof.runcall(run_app)
+ finally:
+ prof.close()
+ body = ''.join(body)
+ headers = catch_response[1]
+ content_type = response.header_value(headers, 'content-type')
+ if content_type is None or not content_type.startswith('text/html'):
+ # We can't add info to non-HTML output
+ return [body]
+ stats = hotshot.stats.load(self.log_filename)
+ stats.strip_dirs()
+ stats.sort_stats('time', 'calls')
+ output = capture_output(stats.print_stats, self.limit)
+ output_callers = capture_output(
+ stats.print_callers, self.limit)
+ body += '<pre style="%s">%s\n%s</pre>' % (
+ self.style, cgi.escape(output), cgi.escape(output_callers))
+ return [body]
+ finally:
+ self.lock.release()
+
+def capture_output(func, *args, **kw):
+ # Not threadsafe! (that's okay when ProfileMiddleware uses it,
+ # though, since it synchronizes itself.)
+ out = StringIO()
+ old_stdout = sys.stdout
+ sys.stdout = out
+ try:
+ func(*args, **kw)
+ finally:
+ sys.stdout = old_stdout
+ return out.getvalue()
+
+def profile_decorator(**options):
+
+ """
+ Profile a single function call.
+
+ Used around a function, like::
+
+ @profile_decorator(options...)
+ def ...
+
+ All calls to the function will be profiled. The options are
+ all keywords, and are:
+
+ log_file:
+ The filename to log to (or ``'stdout'`` or ``'stderr'``).
+ Default: stderr.
+ display_limit:
+ Only show the top N items, default: 20.
+ sort_stats:
+ A list of string-attributes to sort on. Default
+ ``('time', 'calls')``.
+ strip_dirs:
+ Strip directories/module names from files? Default True.
+ add_info:
+ If given, this info will be added to the report (for your
+ own tracking). Default: none.
+ log_filename:
+ The temporary filename to log profiling data to. Default;
+ ``./profile_data.log.tmp``
+ no_profile:
+ If true, then don't actually profile anything. Useful for
+ conditional profiling.
+ """
+
+ if options.get('no_profile'):
+ def decorator(func):
+ return func
+ return decorator
+ def decorator(func):
+ def replacement(*args, **kw):
+ return DecoratedProfile(func, **options)(*args, **kw)
+ return replacement
+ return decorator
+
+class DecoratedProfile(object):
+
+ lock = threading.Lock()
+
+ def __init__(self, func, **options):
+ self.func = func
+ self.options = options
+
+ def __call__(self, *args, **kw):
+ self.lock.acquire()
+ try:
+ return self.profile(self.func, *args, **kw)
+ finally:
+ self.lock.release()
+
+ def profile(self, func, *args, **kw):
+ ops = self.options
+ prof_filename = ops.get('log_filename', 'profile_data.log.tmp')
+ prof = hotshot.Profile(prof_filename)
+ prof.addinfo('Function Call',
+ self.format_function(func, *args, **kw))
+ if ops.get('add_info'):
+ prof.addinfo('Extra info', ops['add_info'])
+ exc_info = None
+ try:
+ start_time = time.time()
+ try:
+ result = prof.runcall(func, *args, **kw)
+ except:
+ exc_info = sys.exc_info()
+ end_time = time.time()
+ finally:
+ prof.close()
+ stats = hotshot.stats.load(prof_filename)
+ os.unlink(prof_filename)
+ if ops.get('strip_dirs', True):
+ stats.strip_dirs()
+ stats.sort_stats(*ops.get('sort_stats', ('time', 'calls')))
+ display_limit = ops.get('display_limit', 20)
+ output = capture_output(stats.print_stats, display_limit)
+ output_callers = capture_output(
+ stats.print_callers, display_limit)
+ output_file = ops.get('log_file')
+ if output_file in (None, 'stderr'):
+ f = sys.stderr
+ elif output_file in ('-', 'stdout'):
+ f = sys.stdout
+ else:
+ f = open(output_file, 'a')
+ f.write('\n%s\n' % ('-'*60))
+ f.write('Date: %s\n' % time.strftime('%c'))
+ f.write('Function call: %s\n'
+ % self.format_function(func, *args, **kw))
+ f.write('Wall time: %0.2f seconds\n'
+ % (end_time - start_time))
+ f.write(output)
+ f.write(output_callers)
+ if output_file not in (None, '-', 'stdout', 'stderr'):
+ f.close()
+ if exc_info:
+ # We captured an exception earlier, now we re-raise it
+ raise exc_info[0], exc_info[1], exc_info[2]
+ return result
+
+ def format_function(self, func, *args, **kw):
+ args = map(repr, args)
+ args.extend(
+ ['%s=%r' % (k, v) for k, v in kw.items()])
+ return '%s(%s)' % (func.__name__, ', '.join(args))
+
+
+def make_profile_middleware(
+ app, global_conf,
+ log_filename='profile.log.tmp',
+ limit=40):
+ """
+ Wrap the application in a component that will profile each
+ request. The profiling data is then appended to the output
+ of each page.
+
+ Note that this serializes all requests (i.e., removing
+ concurrency). Therefore never use this in production.
+ """
+ limit = int(limit)
+ return ProfileMiddleware(
+ app, log_filename=log_filename, limit=limit)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/testserver.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/testserver.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/testserver.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,93 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+WSGI Test Server
+
+This builds upon paste.util.baseserver to customize it for regressions
+where using raw_interactive won't do.
+
+
+"""
+import time
+from paste.httpserver import *
+
+class WSGIRegressionServer(WSGIServer):
+ """
+ A threaded WSGIServer for use in regression testing. To use this
+ module, call serve(application, regression=True), and then call
+ server.accept() to let it handle one request. When finished, use
+ server.stop() to shutdown the server. Note that all pending requests
+ are processed before the server shuts down.
+ """
+ defaulttimeout = 10
+ def __init__ (self, *args, **kwargs):
+ WSGIServer.__init__(self, *args, **kwargs)
+ self.stopping = []
+ self.pending = []
+ self.timeout = self.defaulttimeout
+ # this is a local connection, be quick
+ self.socket.settimeout(2)
+ def serve_forever(self):
+ from threading import Thread
+ thread = Thread(target=self.serve_pending)
+ thread.start()
+ def reset_expires(self):
+ if self.timeout:
+ self.expires = time.time() + self.timeout
+ def close_request(self, *args, **kwargs):
+ WSGIServer.close_request(self, *args, **kwargs)
+ self.pending.pop()
+ self.reset_expires()
+ def serve_pending(self):
+ self.reset_expires()
+ while not self.stopping or self.pending:
+ now = time.time()
+ if now > self.expires and self.timeout:
+ # note regression test doesn't handle exceptions in
+ # threads very well; so we just print and exit
+ print "\nWARNING: WSGIRegressionServer timeout exceeded\n"
+ break
+ if self.pending:
+ self.handle_request()
+ time.sleep(.1)
+ def stop(self):
+ """ stop the server (called from tester's thread) """
+ self.stopping.append(True)
+ def accept(self, count = 1):
+ """ accept another request (called from tester's thread) """
+ assert not self.stopping
+ [self.pending.append(True) for x in range(count)]
+
+def serve(application, host=None, port=None, handler=None):
+ server = WSGIRegressionServer(application, host, port, handler)
+ print "serving on %s:%s" % server.server_address
+ server.serve_forever()
+ return server
+
+if __name__ == '__main__':
+ import urllib
+ from paste.wsgilib import dump_environ
+ server = serve(dump_environ)
+ baseuri = ("http://%s:%s" % server.server_address)
+
+ def fetch(path):
+ # tell the server to humor exactly one more request
+ server.accept(1)
+ # not needed; but this is what you do if the server
+ # may not respond in a resonable time period
+ import socket
+ socket.setdefaulttimeout(5)
+ # build a uri, fetch and return
+ return urllib.urlopen(baseuri + path).read()
+
+ assert "PATH_INFO: /foo" in fetch("/foo")
+ assert "PATH_INFO: /womble" in fetch("/womble")
+
+ # ok, let's make one more final request...
+ server.accept(1)
+ # and then schedule a stop()
+ server.stop()
+ # and then... fetch it...
+ urllib.urlopen(baseuri)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/watchthreads.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/watchthreads.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/watchthreads.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,347 @@
+"""
+Watches the key ``paste.httpserver.thread_pool`` to see how many
+threads there are and report on any wedged threads.
+"""
+import sys
+import cgi
+import time
+import traceback
+from cStringIO import StringIO
+from thread import get_ident
+from paste import httpexceptions
+from paste.request import construct_url, parse_formvars
+from paste.util.template import HTMLTemplate, bunch
+
+page_template = HTMLTemplate('''
+<html>
+ <head>
+ <style type="text/css">
+ body {
+ font-family: sans-serif;
+ }
+ table.environ tr td {
+ border-bottom: #bbb 1px solid;
+ }
+ table.environ tr td.bottom {
+ border-bottom: none;
+ }
+ table.thread {
+ border: 1px solid #000;
+ margin-bottom: 1em;
+ }
+ table.thread tr td {
+ border-bottom: #999 1px solid;
+ padding-right: 1em;
+ }
+ table.thread tr td.bottom {
+ border-bottom: none;
+ }
+ table.thread tr.this_thread td {
+ background-color: #006;
+ color: #fff;
+ }
+ a.button {
+ background-color: #ddd;
+ border: #aaa outset 2px;
+ text-decoration: none;
+ margin-top: 10px;
+ font-size: 80%;
+ color: #000;
+ }
+ a.button:hover {
+ background-color: #eee;
+ border: #bbb outset 2px;
+ }
+ a.button:active {
+ border: #bbb inset 2px;
+ }
+ </style>
+ <title>{{title}}</title>
+ </head>
+ <body>
+ <h1>{{title}}</h1>
+ {{if kill_thread_id}}
+ <div style="background-color: #060; color: #fff;
+ border: 2px solid #000;">
+ Thread {{kill_thread_id}} killed
+ </div>
+ {{endif}}
+ <div>Pool size: {{nworkers}}
+ {{if actual_workers > nworkers}}
+ + {{actual_workers-nworkers}} extra
+ {{endif}}
+ ({{nworkers_used}} used including current request)<br>
+ idle: {{len(track_threads["idle"])}},
+ busy: {{len(track_threads["busy"])}},
+ hung: {{len(track_threads["hung"])}},
+ dying: {{len(track_threads["dying"])}},
+ zombie: {{len(track_threads["zombie"])}}</div>
+
+{{for thread in threads}}
+
+<table class="thread">
+ <tr {{if thread.thread_id == this_thread_id}}class="this_thread"{{endif}}>
+ <td>
+ <b>Thread</b>
+ {{if thread.thread_id == this_thread_id}}
+ (<i>this</i> request)
+ {{endif}}</td>
+ <td>
+ <b>{{thread.thread_id}}
+ {{if allow_kill}}
+ <form action="{{script_name}}/kill" method="POST"
+ style="display: inline">
+ <input type="hidden" name="thread_id" value="{{thread.thread_id}}">
+ <input type="submit" value="kill">
+ </form>
+ {{endif}}
+ </b>
+ </td>
+ </tr>
+ <tr>
+ <td>Time processing request</td>
+ <td>{{thread.time_html|html}}</td>
+ </tr>
+ <tr>
+ <td>URI</td>
+ <td>{{if thread.uri == 'unknown'}}
+ unknown
+ {{else}}<a href="{{thread.uri}}">{{thread.uri_short}}</a>
+ {{endif}}
+ </td>
+ <tr>
+ <td colspan="2" class="bottom">
+ <a href="#" class="button" style="width: 9em; display: block"
+ onclick="
+ var el = document.getElementById('environ-{{thread.thread_id}}');
+ if (el.style.display) {
+ el.style.display = '';
+ this.innerHTML = \'▾ Hide environ\';
+ } else {
+ el.style.display = 'none';
+ this.innerHTML = \'▸ Show environ\';
+ }
+ return false
+ ">▸ Show environ</a>
+
+ <div id="environ-{{thread.thread_id}}" style="display: none">
+ {{if thread.environ:}}
+ <table class="environ">
+ {{for loop, item in looper(sorted(thread.environ.items()))}}
+ {{py:key, value=item}}
+ <tr>
+ <td {{if loop.last}}class="bottom"{{endif}}>{{key}}</td>
+ <td {{if loop.last}}class="bottom"{{endif}}>{{value}}</td>
+ </tr>
+ {{endfor}}
+ </table>
+ {{else}}
+ Thread is in process of starting
+ {{endif}}
+ </div>
+
+ {{if thread.traceback}}
+ <a href="#" class="button" style="width: 9em; display: block"
+ onclick="
+ var el = document.getElementById('traceback-{{thread.thread_id}}');
+ if (el.style.display) {
+ el.style.display = '';
+ this.innerHTML = \'▾ Hide traceback\';
+ } else {
+ el.style.display = 'none';
+ this.innerHTML = \'▸ Show traceback\';
+ }
+ return false
+ ">▸ Show traceback</a>
+
+ <div id="traceback-{{thread.thread_id}}" style="display: none">
+ <pre class="traceback">{{thread.traceback}}</pre>
+ </div>
+ {{endif}}
+
+ </td>
+ </tr>
+</table>
+
+{{endfor}}
+
+ </body>
+</html>
+''', name='watchthreads.page_template')
+
+class WatchThreads(object):
+
+ """
+ Application that watches the threads in ``paste.httpserver``,
+ showing the length each thread has been working on a request.
+
+ If allow_kill is true, then you can kill errant threads through
+ this application.
+
+ This application can expose private information (specifically in
+ the environment, like cookies), so it should be protected.
+ """
+
+ def __init__(self, allow_kill=False):
+ self.allow_kill = allow_kill
+
+ def __call__(self, environ, start_response):
+ if 'paste.httpserver.thread_pool' not in environ:
+ start_response('403 Forbidden', [('Content-type', 'text/plain')])
+ return ['You must use the threaded Paste HTTP server to use this application']
+ if environ.get('PATH_INFO') == '/kill':
+ return self.kill(environ, start_response)
+ else:
+ return self.show(environ, start_response)
+
+ def show(self, environ, start_response):
+ start_response('200 OK', [('Content-type', 'text/html')])
+ form = parse_formvars(environ)
+ if form.get('kill'):
+ kill_thread_id = form['kill']
+ else:
+ kill_thread_id = None
+ thread_pool = environ['paste.httpserver.thread_pool']
+ nworkers = thread_pool.nworkers
+ now = time.time()
+
+
+ workers = thread_pool.worker_tracker.items()
+ workers.sort(key=lambda v: v[1][0])
+ threads = []
+ for thread_id, (time_started, worker_environ) in workers:
+ thread = bunch()
+ threads.append(thread)
+ if worker_environ:
+ thread.uri = construct_url(worker_environ)
+ else:
+ thread.uri = 'unknown'
+ thread.thread_id = thread_id
+ thread.time_html = format_time(now-time_started)
+ thread.uri_short = shorten(thread.uri)
+ thread.environ = worker_environ
+ thread.traceback = traceback_thread(thread_id)
+
+ page = page_template.substitute(
+ title="Thread Pool Worker Tracker",
+ nworkers=nworkers,
+ actual_workers=len(thread_pool.workers),
+ nworkers_used=len(workers),
+ script_name=environ['SCRIPT_NAME'],
+ kill_thread_id=kill_thread_id,
+ allow_kill=self.allow_kill,
+ threads=threads,
+ this_thread_id=get_ident(),
+ track_threads=thread_pool.track_threads())
+
+ return [page]
+
+ def kill(self, environ, start_response):
+ if not self.allow_kill:
+ exc = httpexceptions.HTTPForbidden(
+ 'Killing threads has not been enabled. Shame on you '
+ 'for trying!')
+ return exc(environ, start_response)
+ vars = parse_formvars(environ)
+ thread_id = int(vars['thread_id'])
+ thread_pool = environ['paste.httpserver.thread_pool']
+ if thread_id not in thread_pool.worker_tracker:
+ exc = httpexceptions.PreconditionFailed(
+ 'You tried to kill thread %s, but it is not working on '
+ 'any requests' % thread_id)
+ return exc(environ, start_response)
+ thread_pool.kill_worker(thread_id)
+ script_name = environ['SCRIPT_NAME'] or '/'
+ exc = httpexceptions.HTTPFound(
+ headers=[('Location', script_name+'?kill=%s' % thread_id)])
+ return exc(environ, start_response)
+
+def traceback_thread(thread_id):
+ """
+ Returns a plain-text traceback of the given thread, or None if it
+ can't get a traceback.
+ """
+ if not hasattr(sys, '_current_frames'):
+ # Only 2.5 has support for this, with this special function
+ return None
+ frames = sys._current_frames()
+ if not thread_id in frames:
+ return None
+ frame = frames[thread_id]
+ out = StringIO()
+ traceback.print_stack(frame, file=out)
+ return out.getvalue()
+
+hide_keys = ['paste.httpserver.thread_pool']
+
+def format_environ(environ):
+ if environ is None:
+ return environ_template.substitute(
+ key='---',
+ value='No environment registered for this thread yet')
+ environ_rows = []
+ for key, value in sorted(environ.items()):
+ if key in hide_keys:
+ continue
+ try:
+ if key.upper() != key:
+ value = repr(value)
+ environ_rows.append(
+ environ_template.substitute(
+ key=cgi.escape(str(key)),
+ value=cgi.escape(str(value))))
+ except Exception, e:
+ environ_rows.append(
+ environ_template.substitute(
+ key=cgi.escape(str(key)),
+ value='Error in <code>repr()</code>: %s' % e))
+ return ''.join(environ_rows)
+
+def format_time(time_length):
+ if time_length >= 60*60:
+ # More than an hour
+ time_string = '%i:%02i:%02i' % (int(time_length/60/60),
+ int(time_length/60) % 60,
+ time_length % 60)
+ elif time_length >= 120:
+ time_string = '%i:%02i' % (int(time_length/60),
+ time_length % 60)
+ elif time_length > 60:
+ time_string = '%i sec' % time_length
+ elif time_length > 1:
+ time_string = '%0.1f sec' % time_length
+ else:
+ time_string = '%0.2f sec' % time_length
+ if time_length < 5:
+ return time_string
+ elif time_length < 120:
+ return '<span style="color: #900">%s</span>' % time_string
+ else:
+ return '<span style="background-color: #600; color: #fff">%s</span>' % time_string
+
+def shorten(s):
+ if len(s) > 60:
+ return s[:40]+'...'+s[-10:]
+ else:
+ return s
+
+def make_watch_threads(global_conf, allow_kill=False):
+ from paste.deploy.converters import asbool
+ return WatchThreads(allow_kill=asbool(allow_kill))
+make_watch_threads.__doc__ = WatchThreads.__doc__
+
+def make_bad_app(global_conf, pause=0):
+ pause = int(pause)
+ def bad_app(environ, start_response):
+ import thread
+ if pause:
+ time.sleep(pause)
+ else:
+ count = 0
+ while 1:
+ print "I'm alive %s (%s)" % (count, thread.get_ident())
+ time.sleep(10)
+ count += 1
+ start_response('200 OK', [('content-type', 'text/plain')])
+ return ['OK, paused %s seconds' % pause]
+ return bad_app
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/wdg_validate.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/wdg_validate.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/debug/wdg_validate.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,121 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware that tests the validity of all generated HTML using the
+`WDG HTML Validator <http://www.htmlhelp.com/tools/validator/>`_
+"""
+
+from cStringIO import StringIO
+try:
+ import subprocess
+except ImportError:
+ from paste.util import subprocess24 as subprocess
+from paste.response import header_value
+import re
+import cgi
+
+__all__ = ['WDGValidateMiddleware']
+
+class WDGValidateMiddleware(object):
+
+ """
+ Middleware that checks HTML and appends messages about the validity of
+ the HTML. Uses: http://www.htmlhelp.com/tools/validator/ -- interacts
+ with the command line client. Use the configuration ``wdg_path`` to
+ override the path (default: looks for ``validate`` in $PATH).
+
+ To install, in your web context's __init__.py::
+
+ def urlparser_wrap(environ, start_response, app):
+ return wdg_validate.WDGValidateMiddleware(app)(
+ environ, start_response)
+
+ Or in your configuration::
+
+ middleware.append('paste.wdg_validate.WDGValidateMiddleware')
+ """
+
+ _end_body_regex = re.compile(r'</body>', re.I)
+
+ def __init__(self, app, global_conf=None, wdg_path='validate'):
+ self.app = app
+ self.wdg_path = wdg_path
+
+ def __call__(self, environ, start_response):
+ output = StringIO()
+ response = []
+
+ def writer_start_response(status, headers, exc_info=None):
+ response.extend((status, headers))
+ start_response(status, headers, exc_info)
+ return output.write
+
+ app_iter = self.app(environ, writer_start_response)
+ try:
+ for s in app_iter:
+ output.write(s)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ page = output.getvalue()
+ status, headers = response
+ v = header_value(headers, 'content-type') or ''
+ if (not v.startswith('text/html')
+ and not v.startswith('text/xhtml')
+ and not v.startswith('application/xhtml')):
+ # Can't validate
+ # @@: Should validate CSS too... but using what?
+ return [page]
+ ops = []
+ if v.startswith('text/xhtml+xml'):
+ ops.append('--xml')
+ # @@: Should capture encoding too
+ html_errors = self.call_wdg_validate(
+ self.wdg_path, ops, page)
+ if html_errors:
+ page = self.add_error(page, html_errors)[0]
+ headers.remove(
+ ('Content-Length',
+ str(header_value(headers, 'content-length'))))
+ headers.append(('Content-Length', str(len(page))))
+ return [page]
+
+ def call_wdg_validate(self, wdg_path, ops, page):
+ if subprocess is None:
+ raise ValueError(
+ "This middleware requires the subprocess module from "
+ "Python 2.4")
+ proc = subprocess.Popen([wdg_path] + ops,
+ shell=False,
+ close_fds=True,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate(page)[0]
+ proc.wait()
+ return stdout
+
+ def add_error(self, html_page, html_errors):
+ add_text = ('<pre style="background-color: #ffd; color: #600; '
+ 'border: 1px solid #000;">%s</pre>'
+ % cgi.escape(html_errors))
+ match = self._end_body_regex.search(html_page)
+ if match:
+ return [html_page[:match.start()]
+ + add_text
+ + html_page[match.start():]]
+ else:
+ return [html_page + add_text]
+
+def make_wdg_validate_middleware(
+ app, global_conf, wdg_path='validate'):
+ """
+ Wraps the application in the WDG validator from
+ http://www.htmlhelp.com/tools/validator/
+
+ Validation errors are appended to the text of each page.
+ You can configure this by giving the path to the validate
+ executable (by default picked up from $PATH)
+ """
+ return WDGValidateMiddleware(
+ app, global_conf, wdg_path=wdg_path)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/errordocument.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/errordocument.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/errordocument.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,383 @@
+# (c) 2005-2006 James Gardner <james at pythonweb.org>
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware to display error documents for certain status codes
+
+The middleware in this module can be used to intercept responses with
+specified status codes and internally forward the request to an appropriate
+URL where the content can be displayed to the user as an error document.
+"""
+
+import warnings
+import sys
+from urlparse import urlparse
+from paste.recursive import ForwardRequestException, RecursiveMiddleware, RecursionLoop
+from paste.util import converters
+from paste.response import replace_header
+
+def forward(app, codes):
+ """
+ Intercepts a response with a particular status code and returns the
+ content from a specified URL instead.
+
+ The arguments are:
+
+ ``app``
+ The WSGI application or middleware chain.
+
+ ``codes``
+ A dictionary of integer status codes and the URL to be displayed
+ if the response uses that code.
+
+ For example, you might want to create a static file to display a
+ "File Not Found" message at the URL ``/error404.html`` and then use
+ ``forward`` middleware to catch all 404 status codes and display the page
+ you created. In this example ``app`` is your exisiting WSGI
+ applicaiton::
+
+ from paste.errordocument import forward
+ app = forward(app, codes={404:'/error404.html'})
+
+ """
+ for code in codes:
+ if not isinstance(code, int):
+ raise TypeError('All status codes should be type int. '
+ '%s is not valid'%repr(code))
+
+ def error_codes_mapper(code, message, environ, global_conf, codes):
+ if codes.has_key(code):
+ return codes[code]
+ else:
+ return None
+
+ #return _StatusBasedRedirect(app, error_codes_mapper, codes=codes)
+ return RecursiveMiddleware(
+ StatusBasedForward(
+ app,
+ error_codes_mapper,
+ codes=codes,
+ )
+ )
+
+class StatusKeeper(object):
+ def __init__(self, app, status, url, headers):
+ self.app = app
+ self.status = status
+ self.url = url
+ self.headers = headers
+
+ def __call__(self, environ, start_response):
+ def keep_status_start_response(status, headers, exc_info=None):
+ for header, value in headers:
+ if header.lower() == 'set-cookie':
+ self.headers.append((header, value))
+ else:
+ replace_header(self.headers, header, value)
+ return start_response(self.status, self.headers, exc_info)
+ parts = self.url.split('?')
+ environ['PATH_INFO'] = parts[0]
+ if len(parts) > 1:
+ environ['QUERY_STRING'] = parts[1]
+ else:
+ environ['QUERY_STRING'] = ''
+ #raise Exception(self.url, self.status)
+ try:
+ return self.app(environ, keep_status_start_response)
+ except RecursionLoop, e:
+ environ['wsgi.errors'].write('Recursion error getting error page: %s\n' % e)
+ keep_status_start_response('500 Server Error', [('Content-type', 'text/plain')], sys.exc_info())
+ return ['Error: %s. (Error page could not be fetched)'
+ % self.status]
+
+
+class StatusBasedForward(object):
+ """
+ Middleware that lets you test a response against a custom mapper object to
+ programatically determine whether to internally forward to another URL and
+ if so, which URL to forward to.
+
+ If you don't need the full power of this middleware you might choose to use
+ the simpler ``forward`` middleware instead.
+
+ The arguments are:
+
+ ``app``
+ The WSGI application or middleware chain.
+
+ ``mapper``
+ A callable that takes a status code as the
+ first parameter, a message as the second, and accepts optional environ,
+ global_conf and named argments afterwards. It should return a
+ URL to forward to or ``None`` if the code is not to be intercepted.
+
+ ``global_conf``
+ Optional default configuration from your config file. If ``debug`` is
+ set to ``true`` a message will be written to ``wsgi.errors`` on each
+ internal forward stating the URL forwarded to.
+
+ ``**params``
+ Optional, any other configuration and extra arguments you wish to
+ pass which will in turn be passed back to the custom mapper object.
+
+ Here is an example where a ``404 File Not Found`` status response would be
+ redirected to the URL ``/error?code=404&message=File%20Not%20Found``. This
+ could be useful for passing the status code and message into another
+ application to display an error document:
+
+ .. code-block:: python
+
+ from paste.errordocument import StatusBasedForward
+ from paste.recursive import RecursiveMiddleware
+ from urllib import urlencode
+
+ def error_mapper(code, message, environ, global_conf, kw)
+ if code in [404, 500]:
+ params = urlencode({'message':message, 'code':code})
+ url = '/error?'%(params)
+ return url
+ else:
+ return None
+
+ app = RecursiveMiddleware(
+ StatusBasedForward(app, mapper=error_mapper),
+ )
+
+ """
+
+ def __init__(self, app, mapper, global_conf=None, **params):
+ if global_conf is None:
+ global_conf = {}
+ # @@: global_conf shouldn't really come in here, only in a
+ # separate make_status_based_forward function
+ if global_conf:
+ self.debug = converters.asbool(global_conf.get('debug', False))
+ else:
+ self.debug = False
+ self.application = app
+ self.mapper = mapper
+ self.global_conf = global_conf
+ self.params = params
+
+ def __call__(self, environ, start_response):
+ url = []
+ writer = []
+
+ def change_response(status, headers, exc_info=None):
+ status_code = status.split(' ')
+ try:
+ code = int(status_code[0])
+ except (ValueError, TypeError):
+ raise Exception(
+ 'StatusBasedForward middleware '
+ 'received an invalid status code %s'%repr(status_code[0])
+ )
+ message = ' '.join(status_code[1:])
+ new_url = self.mapper(
+ code,
+ message,
+ environ,
+ self.global_conf,
+ **self.params
+ )
+ if not (new_url == None or isinstance(new_url, str)):
+ raise TypeError(
+ 'Expected the url to internally '
+ 'redirect to in the StatusBasedForward mapper'
+ 'to be a string or None, not %r' % new_url)
+ if new_url:
+ url.append([new_url, status, headers])
+ # We have to allow the app to write stuff, even though
+ # we'll ignore it:
+ return [].append
+ else:
+ return start_response(status, headers, exc_info)
+
+ app_iter = self.application(environ, change_response)
+ if url:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+
+ def factory(app):
+ return StatusKeeper(app, status=url[0][1], url=url[0][0],
+ headers=url[0][2])
+ raise ForwardRequestException(factory=factory)
+ else:
+ return app_iter
+
+def make_errordocument(app, global_conf, **kw):
+ """
+ Paste Deploy entry point to create a error document wrapper.
+
+ Use like::
+
+ [filter-app:main]
+ use = egg:Paste#errordocument
+ next = real-app
+ 500 = /lib/msg/500.html
+ 404 = /lib/msg/404.html
+ """
+ map = {}
+ for status, redir_loc in kw.items():
+ try:
+ status = int(status)
+ except ValueError:
+ raise ValueError('Bad status code: %r' % status)
+ map[status] = redir_loc
+ forwarder = forward(app, map)
+ return forwarder
+
+__pudge_all__ = [
+ 'forward',
+ 'make_errordocument',
+ 'empty_error',
+ 'make_empty_error',
+ 'StatusBasedForward',
+]
+
+
+###############################################################################
+## Deprecated
+###############################################################################
+
+def custom_forward(app, mapper, global_conf=None, **kw):
+ """
+ Deprectated; use StatusBasedForward instead.
+ """
+ warnings.warn(
+ "errordocuments.custom_forward has been deprecated; please "
+ "use errordocuments.StatusBasedForward",
+ DeprecationWarning, 2)
+ if global_conf is None:
+ global_conf = {}
+ return _StatusBasedRedirect(app, mapper, global_conf, **kw)
+
+class _StatusBasedRedirect(object):
+ """
+ Deprectated; use StatusBasedForward instead.
+ """
+ def __init__(self, app, mapper, global_conf=None, **kw):
+
+ warnings.warn(
+ "errordocuments._StatusBasedRedirect has been deprecated; please "
+ "use errordocuments.StatusBasedForward",
+ DeprecationWarning, 2)
+
+ if global_conf is None:
+ global_conf = {}
+ self.application = app
+ self.mapper = mapper
+ self.global_conf = global_conf
+ self.kw = kw
+ self.fallback_template = """
+ <html>
+ <head>
+ <title>Error %(code)s</title>
+ </html>
+ <body>
+ <h1>Error %(code)s</h1>
+ <p>%(message)s</p>
+ <hr>
+ <p>
+ Additionally an error occurred trying to produce an
+ error document. A description of the error was logged
+ to <tt>wsgi.errors</tt>.
+ </p>
+ </body>
+ </html>
+ """
+
+ def __call__(self, environ, start_response):
+ url = []
+ code_message = []
+ try:
+ def change_response(status, headers, exc_info=None):
+ new_url = None
+ parts = status.split(' ')
+ try:
+ code = int(parts[0])
+ except (ValueError, TypeError):
+ raise Exception(
+ '_StatusBasedRedirect middleware '
+ 'received an invalid status code %s'%repr(parts[0])
+ )
+ message = ' '.join(parts[1:])
+ new_url = self.mapper(
+ code,
+ message,
+ environ,
+ self.global_conf,
+ self.kw
+ )
+ if not (new_url == None or isinstance(new_url, str)):
+ raise TypeError(
+ 'Expected the url to internally '
+ 'redirect to in the _StatusBasedRedirect error_mapper'
+ 'to be a string or None, not %s'%repr(new_url)
+ )
+ if new_url:
+ url.append(new_url)
+ code_message.append([code, message])
+ return start_response(status, headers, exc_info)
+ app_iter = self.application(environ, change_response)
+ except:
+ try:
+ import sys
+ error = str(sys.exc_info()[1])
+ except:
+ error = ''
+ try:
+ code, message = code_message[0]
+ except:
+ code, message = ['', '']
+ environ['wsgi.errors'].write(
+ 'Error occurred in _StatusBasedRedirect '
+ 'intercepting the response: '+str(error)
+ )
+ return [self.fallback_template
+ % {'message': message, 'code': code}]
+ else:
+ if url:
+ url_ = url[0]
+ new_environ = {}
+ for k, v in environ.items():
+ if k != 'QUERY_STRING':
+ new_environ['QUERY_STRING'] = urlparse(url_)[4]
+ else:
+ new_environ[k] = v
+ class InvalidForward(Exception):
+ pass
+ def eat_start_response(status, headers, exc_info=None):
+ """
+ We don't want start_response to do anything since it
+ has already been called
+ """
+ if status[:3] != '200':
+ raise InvalidForward(
+ "The URL %s to internally forward "
+ "to in order to create an error document did not "
+ "return a '200' status code." % url_
+ )
+ forward = environ['paste.recursive.forward']
+ old_start_response = forward.start_response
+ forward.start_response = eat_start_response
+ try:
+ app_iter = forward(url_, new_environ)
+ except InvalidForward, e:
+ code, message = code_message[0]
+ environ['wsgi.errors'].write(
+ 'Error occurred in '
+ '_StatusBasedRedirect redirecting '
+ 'to new URL: '+str(url[0])
+ )
+ return [
+ self.fallback_template%{
+ 'message':message,
+ 'code':code,
+ }
+ ]
+ else:
+ forward.start_response = old_start_response
+ return app_iter
+ else:
+ return app_iter
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+An exception handler for interactive debugging
+"""
+from paste.evalexception.middleware import EvalException
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/evalcontext.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/evalcontext.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/evalcontext.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,68 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+from cStringIO import StringIO
+import traceback
+import threading
+import pdb
+import sys
+
+exec_lock = threading.Lock()
+
+class EvalContext(object):
+
+ """
+ Class that represents a interactive interface. It has its own
+ namespace. Use eval_context.exec_expr(expr) to run commands; the
+ output of those commands is returned, as are print statements.
+
+ This is essentially what doctest does, and is taken directly from
+ doctest.
+ """
+
+ def __init__(self, namespace, globs):
+ self.namespace = namespace
+ self.globs = globs
+
+ def exec_expr(self, s):
+ out = StringIO()
+ exec_lock.acquire()
+ save_stdout = sys.stdout
+ try:
+ debugger = _OutputRedirectingPdb(save_stdout)
+ debugger.reset()
+ pdb.set_trace = debugger.set_trace
+ sys.stdout = out
+ try:
+ code = compile(s, '<web>', "single", 0, 1)
+ exec code in self.namespace, self.globs
+ debugger.set_continue()
+ except KeyboardInterrupt:
+ raise
+ except:
+ traceback.print_exc(file=out)
+ debugger.set_continue()
+ finally:
+ sys.stdout = save_stdout
+ exec_lock.release()
+ return out.getvalue()
+
+# From doctest
+class _OutputRedirectingPdb(pdb.Pdb):
+ """
+ A specialized version of the python debugger that redirects stdout
+ to a given stream when interacting with the user. Stdout is *not*
+ redirected when traced code is executed.
+ """
+ def __init__(self, out):
+ self.__out = out
+ pdb.Pdb.__init__(self)
+
+ def trace_dispatch(self, *args):
+ # Redirect stdout to the given stream.
+ save_stdout = sys.stdout
+ sys.stdout = self.__out
+ # Call Pdb's trace dispatch method.
+ try:
+ return pdb.Pdb.trace_dispatch(self, *args)
+ finally:
+ sys.stdout = save_stdout
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/MochiKit.packed.js
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/MochiKit.packed.js (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/MochiKit.packed.js 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7829 @@
+/***
+
+ MochiKit.MochiKit 1.4.2 : PACKED VERSION
+
+ THIS FILE IS AUTOMATICALLY GENERATED. If creating patches, please
+ diff against the source tree, not this file.
+
+ See <http://mochikit.com/> for documentation, downloads, license, etc.
+
+ (c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Base");
+}
+if(typeof (MochiKit)=="undefined"){
+MochiKit={};
+}
+if(typeof (MochiKit.Base)=="undefined"){
+MochiKit.Base={};
+}
+if(typeof (MochiKit.__export__)=="undefined"){
+MochiKit.__export__=(MochiKit.__compat__||(typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined"));
+}
+MochiKit.Base.VERSION="1.4.2";
+MochiKit.Base.NAME="MochiKit.Base";
+MochiKit.Base.update=function(_1,_2){
+if(_1===null||_1===undefined){
+_1={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="undefined"&&o!==null){
+for(var k in o){
+_1[k]=o[k];
+}
+}
+}
+return _1;
+};
+MochiKit.Base.update(MochiKit.Base,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},camelize:function(_6){
+var _7=_6.split("-");
+var cc=_7[0];
+for(var i=1;i<_7.length;i++){
+cc+=_7[i].charAt(0).toUpperCase()+_7[i].substring(1);
+}
+return cc;
+},counter:function(n){
+if(arguments.length===0){
+n=1;
+}
+return function(){
+return n++;
+};
+},clone:function(_b){
+var me=arguments.callee;
+if(arguments.length==1){
+me.prototype=_b;
+return new me();
+}
+},_deps:function(_d,_e){
+if(!(_d in MochiKit)){
+MochiKit[_d]={};
+}
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit."+_d);
+}
+for(var i=0;i<_e.length;i++){
+if(typeof (dojo)!="undefined"){
+dojo.require("MochiKit."+_e[i]);
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit."+_e[i],[]);
+}
+if(!(_e[i] in MochiKit)){
+throw "MochiKit."+_d+" depends on MochiKit."+_e[i]+"!";
+}
+}
+},_flattenArray:function(res,lst){
+for(var i=0;i<lst.length;i++){
+var o=lst[i];
+if(o instanceof Array){
+arguments.callee(res,o);
+}else{
+res.push(o);
+}
+}
+return res;
+},flattenArray:function(lst){
+return MochiKit.Base._flattenArray([],lst);
+},flattenArguments:function(lst){
+var res=[];
+var m=MochiKit.Base;
+var _18=m.extend(null,arguments);
+while(_18.length){
+var o=_18.shift();
+if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
+for(var i=o.length-1;i>=0;i--){
+_18.unshift(o[i]);
+}
+}else{
+res.push(o);
+}
+}
+return res;
+},extend:function(_1b,obj,_1d){
+if(!_1d){
+_1d=0;
+}
+if(obj){
+var l=obj.length;
+if(typeof (l)!="number"){
+if(typeof (MochiKit.Iter)!="undefined"){
+obj=MochiKit.Iter.list(obj);
+l=obj.length;
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(!_1b){
+_1b=[];
+}
+for(var i=_1d;i<l;i++){
+_1b.push(obj[i]);
+}
+}
+return _1b;
+},updatetree:function(_20,obj){
+if(_20===null||_20===undefined){
+_20={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="undefined"&&o!==null){
+for(var k in o){
+var v=o[k];
+if(typeof (_20[k])=="object"&&typeof (v)=="object"){
+arguments.callee(_20[k],v);
+}else{
+_20[k]=v;
+}
+}
+}
+}
+return _20;
+},setdefault:function(_26,obj){
+if(_26===null||_26===undefined){
+_26={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+for(var k in o){
+if(!(k in _26)){
+_26[k]=o[k];
+}
+}
+}
+return _26;
+},keys:function(obj){
+var _2c=[];
+for(var _2d in obj){
+_2c.push(_2d);
+}
+return _2c;
+},values:function(obj){
+var _2f=[];
+for(var _30 in obj){
+_2f.push(obj[_30]);
+}
+return _2f;
+},items:function(obj){
+var _32=[];
+var e;
+for(var _34 in obj){
+var v;
+try{
+v=obj[_34];
+}
+catch(e){
+continue;
+}
+_32.push([_34,v]);
+}
+return _32;
+},_newNamedError:function(_36,_37,_38){
+_38.prototype=new MochiKit.Base.NamedError(_36.NAME+"."+_37);
+_36[_37]=_38;
+},operator:{truth:function(a){
+return !!a;
+},lognot:function(a){
+return !a;
+},identity:function(a){
+return a;
+},not:function(a){
+return ~a;
+},neg:function(a){
+return -a;
+},add:function(a,b){
+return a+b;
+},sub:function(a,b){
+return a-b;
+},div:function(a,b){
+return a/b;
+},mod:function(a,b){
+return a%b;
+},mul:function(a,b){
+return a*b;
+},and:function(a,b){
+return a&b;
+},or:function(a,b){
+return a|b;
+},xor:function(a,b){
+return a^b;
+},lshift:function(a,b){
+return a<<b;
+},rshift:function(a,b){
+return a>>b;
+},zrshift:function(a,b){
+return a>>>b;
+},eq:function(a,b){
+return a==b;
+},ne:function(a,b){
+return a!=b;
+},gt:function(a,b){
+return a>b;
+},ge:function(a,b){
+return a>=b;
+},lt:function(a,b){
+return a<b;
+},le:function(a,b){
+return a<=b;
+},seq:function(a,b){
+return a===b;
+},sne:function(a,b){
+return a!==b;
+},ceq:function(a,b){
+return MochiKit.Base.compare(a,b)===0;
+},cne:function(a,b){
+return MochiKit.Base.compare(a,b)!==0;
+},cgt:function(a,b){
+return MochiKit.Base.compare(a,b)==1;
+},cge:function(a,b){
+return MochiKit.Base.compare(a,b)!=-1;
+},clt:function(a,b){
+return MochiKit.Base.compare(a,b)==-1;
+},cle:function(a,b){
+return MochiKit.Base.compare(a,b)!=1;
+},logand:function(a,b){
+return a&&b;
+},logor:function(a,b){
+return a||b;
+},contains:function(a,b){
+return b in a;
+}},forwardCall:function(_76){
+return function(){
+return this[_76].apply(this,arguments);
+};
+},itemgetter:function(_77){
+return function(arg){
+return arg[_77];
+};
+},typeMatcher:function(){
+var _79={};
+for(var i=0;i<arguments.length;i++){
+var typ=arguments[i];
+_79[typ]=typ;
+}
+return function(){
+for(var i=0;i<arguments.length;i++){
+if(!(typeof (arguments[i]) in _79)){
+return false;
+}
+}
+return true;
+};
+},isNull:function(){
+for(var i=0;i<arguments.length;i++){
+if(arguments[i]!==null){
+return false;
+}
+}
+return true;
+},isUndefinedOrNull:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(!(typeof (o)=="undefined"||o===null)){
+return false;
+}
+}
+return true;
+},isEmpty:function(obj){
+return !MochiKit.Base.isNotEmpty.apply(this,arguments);
+},isNotEmpty:function(obj){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(!(o&&o.length)){
+return false;
+}
+}
+return true;
+},isArrayLike:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+var typ=typeof (o);
+if((typ!="object"&&!(typ=="function"&&typeof (o.item)=="function"))||o===null||typeof (o.length)!="number"||o.nodeType===3||o.nodeType===4){
+return false;
+}
+}
+return true;
+},isDateLike:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="object"||o===null||typeof (o.getTime)!="function"){
+return false;
+}
+}
+return true;
+},xmap:function(fn){
+if(fn===null){
+return MochiKit.Base.extend(null,arguments,1);
+}
+var _8a=[];
+for(var i=1;i<arguments.length;i++){
+_8a.push(fn(arguments[i]));
+}
+return _8a;
+},map:function(fn,lst){
+var m=MochiKit.Base;
+var itr=MochiKit.Iter;
+var _90=m.isArrayLike;
+if(arguments.length<=2){
+if(!_90(lst)){
+if(itr){
+lst=itr.list(lst);
+if(fn===null){
+return lst;
+}
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(fn===null){
+return m.extend(null,lst);
+}
+var _91=[];
+for(var i=0;i<lst.length;i++){
+_91.push(fn(lst[i]));
+}
+return _91;
+}else{
+if(fn===null){
+fn=Array;
+}
+var _93=null;
+for(i=1;i<arguments.length;i++){
+if(!_90(arguments[i])){
+if(itr){
+return itr.list(itr.imap.apply(null,arguments));
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+var l=arguments[i].length;
+if(_93===null||_93>l){
+_93=l;
+}
+}
+_91=[];
+for(i=0;i<_93;i++){
+var _95=[];
+for(var j=1;j<arguments.length;j++){
+_95.push(arguments[j][i]);
+}
+_91.push(fn.apply(this,_95));
+}
+return _91;
+}
+},xfilter:function(fn){
+var _98=[];
+if(fn===null){
+fn=MochiKit.Base.operator.truth;
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(fn(o)){
+_98.push(o);
+}
+}
+return _98;
+},filter:function(fn,lst,_9d){
+var _9e=[];
+var m=MochiKit.Base;
+if(!m.isArrayLike(lst)){
+if(MochiKit.Iter){
+lst=MochiKit.Iter.list(lst);
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(fn===null){
+fn=m.operator.truth;
+}
+if(typeof (Array.prototype.filter)=="function"){
+return Array.prototype.filter.call(lst,fn,_9d);
+}else{
+if(typeof (_9d)=="undefined"||_9d===null){
+for(var i=0;i<lst.length;i++){
+var o=lst[i];
+if(fn(o)){
+_9e.push(o);
+}
+}
+}else{
+for(i=0;i<lst.length;i++){
+o=lst[i];
+if(fn.call(_9d,o)){
+_9e.push(o);
+}
+}
+}
+}
+return _9e;
+},_wrapDumbFunction:function(_a2){
+return function(){
+switch(arguments.length){
+case 0:
+return _a2();
+case 1:
+return _a2(arguments[0]);
+case 2:
+return _a2(arguments[0],arguments[1]);
+case 3:
+return _a2(arguments[0],arguments[1],arguments[2]);
+}
+var _a3=[];
+for(var i=0;i<arguments.length;i++){
+_a3.push("arguments["+i+"]");
+}
+return eval("(func("+_a3.join(",")+"))");
+};
+},methodcaller:function(_a5){
+var _a6=MochiKit.Base.extend(null,arguments,1);
+if(typeof (_a5)=="function"){
+return function(obj){
+return _a5.apply(obj,_a6);
+};
+}else{
+return function(obj){
+return obj[_a5].apply(obj,_a6);
+};
+}
+},method:function(_a9,_aa){
+var m=MochiKit.Base;
+return m.bind.apply(this,m.extend([_aa,_a9],arguments,2));
+},compose:function(f1,f2){
+var _ae=[];
+var m=MochiKit.Base;
+if(arguments.length===0){
+throw new TypeError("compose() requires at least one argument");
+}
+for(var i=0;i<arguments.length;i++){
+var fn=arguments[i];
+if(typeof (fn)!="function"){
+throw new TypeError(m.repr(fn)+" is not a function");
+}
+_ae.push(fn);
+}
+return function(){
+var _b2=arguments;
+for(var i=_ae.length-1;i>=0;i--){
+_b2=[_ae[i].apply(this,_b2)];
+}
+return _b2[0];
+};
+},bind:function(_b4,_b5){
+if(typeof (_b4)=="string"){
+_b4=_b5[_b4];
+}
+var _b6=_b4.im_func;
+var _b7=_b4.im_preargs;
+var _b8=_b4.im_self;
+var m=MochiKit.Base;
+if(typeof (_b4)=="function"&&typeof (_b4.apply)=="undefined"){
+_b4=m._wrapDumbFunction(_b4);
+}
+if(typeof (_b6)!="function"){
+_b6=_b4;
+}
+if(typeof (_b5)!="undefined"){
+_b8=_b5;
+}
+if(typeof (_b7)=="undefined"){
+_b7=[];
+}else{
+_b7=_b7.slice();
+}
+m.extend(_b7,arguments,2);
+var _ba=function(){
+var _bb=arguments;
+var me=arguments.callee;
+if(me.im_preargs.length>0){
+_bb=m.concat(me.im_preargs,_bb);
+}
+var _bd=me.im_self;
+if(!_bd){
+_bd=this;
+}
+return me.im_func.apply(_bd,_bb);
+};
+_ba.im_self=_b8;
+_ba.im_func=_b6;
+_ba.im_preargs=_b7;
+return _ba;
+},bindLate:function(_be,_bf){
+var m=MochiKit.Base;
+if(typeof (_be)!="string"){
+return m.bind.apply(this,arguments);
+}
+var _c1=m.extend([],arguments,2);
+var _c2=function(){
+var _c3=arguments;
+var me=arguments.callee;
+if(me.im_preargs.length>0){
+_c3=m.concat(me.im_preargs,_c3);
+}
+var _c5=me.im_self;
+if(!_c5){
+_c5=this;
+}
+return _c5[me.im_func].apply(_c5,_c3);
+};
+_c2.im_self=_bf;
+_c2.im_func=_be;
+_c2.im_preargs=_c1;
+return _c2;
+},bindMethods:function(_c6){
+var _c7=MochiKit.Base.bind;
+for(var k in _c6){
+var _c9=_c6[k];
+if(typeof (_c9)=="function"){
+_c6[k]=_c7(_c9,_c6);
+}
+}
+},registerComparator:function(_ca,_cb,_cc,_cd){
+MochiKit.Base.comparatorRegistry.register(_ca,_cb,_cc,_cd);
+},_primitives:{"boolean":true,"string":true,"number":true},compare:function(a,b){
+if(a==b){
+return 0;
+}
+var _d0=(typeof (a)=="undefined"||a===null);
+var _d1=(typeof (b)=="undefined"||b===null);
+if(_d0&&_d1){
+return 0;
+}else{
+if(_d0){
+return -1;
+}else{
+if(_d1){
+return 1;
+}
+}
+}
+var m=MochiKit.Base;
+var _d3=m._primitives;
+if(!(typeof (a) in _d3&&typeof (b) in _d3)){
+try{
+return m.comparatorRegistry.match(a,b);
+}
+catch(e){
+if(e!=m.NotFound){
+throw e;
+}
+}
+}
+if(a<b){
+return -1;
+}else{
+if(a>b){
+return 1;
+}
+}
+var _d4=m.repr;
+throw new TypeError(_d4(a)+" and "+_d4(b)+" can not be compared");
+},compareDateLike:function(a,b){
+return MochiKit.Base.compare(a.getTime(),b.getTime());
+},compareArrayLike:function(a,b){
+var _d9=MochiKit.Base.compare;
+var _da=a.length;
+var _db=0;
+if(_da>b.length){
+_db=1;
+_da=b.length;
+}else{
+if(_da<b.length){
+_db=-1;
+}
+}
+for(var i=0;i<_da;i++){
+var cmp=_d9(a[i],b[i]);
+if(cmp){
+return cmp;
+}
+}
+return _db;
+},registerRepr:function(_de,_df,_e0,_e1){
+MochiKit.Base.reprRegistry.register(_de,_df,_e0,_e1);
+},repr:function(o){
+if(typeof (o)=="undefined"){
+return "undefined";
+}else{
+if(o===null){
+return "null";
+}
+}
+try{
+if(typeof (o.__repr__)=="function"){
+return o.__repr__();
+}else{
+if(typeof (o.repr)=="function"&&o.repr!=arguments.callee){
+return o.repr();
+}
+}
+return MochiKit.Base.reprRegistry.match(o);
+}
+catch(e){
+if(typeof (o.NAME)=="string"&&(o.toString==Function.prototype.toString||o.toString==Object.prototype.toString)){
+return o.NAME;
+}
+}
+try{
+var _e3=(o+"");
+}
+catch(e){
+return "["+typeof (o)+"]";
+}
+if(typeof (o)=="function"){
+_e3=_e3.replace(/^\s+/,"").replace(/\s+/g," ");
+_e3=_e3.replace(/,(\S)/,", $1");
+var idx=_e3.indexOf("{");
+if(idx!=-1){
+_e3=_e3.substr(0,idx)+"{...}";
+}
+}
+return _e3;
+},reprArrayLike:function(o){
+var m=MochiKit.Base;
+return "["+m.map(m.repr,o).join(", ")+"]";
+},reprString:function(o){
+return ("\""+o.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\v]/g,"\\v").replace(/[\r]/g,"\\r");
+},reprNumber:function(o){
+return o+"";
+},registerJSON:function(_e9,_ea,_eb,_ec){
+MochiKit.Base.jsonRegistry.register(_e9,_ea,_eb,_ec);
+},evalJSON:function(){
+return eval("("+MochiKit.Base._filterJSON(arguments[0])+")");
+},_filterJSON:function(s){
+var m=s.match(/^\s*\/\*(.*)\*\/\s*$/);
+if(m){
+return m[1];
+}
+return s;
+},serializeJSON:function(o){
+var _f0=typeof (o);
+if(_f0=="number"||_f0=="boolean"){
+return o+"";
+}else{
+if(o===null){
+return "null";
+}else{
+if(_f0=="string"){
+var res="";
+for(var i=0;i<o.length;i++){
+var c=o.charAt(i);
+if(c=="\""){
+res+="\\\"";
+}else{
+if(c=="\\"){
+res+="\\\\";
+}else{
+if(c=="\b"){
+res+="\\b";
+}else{
+if(c=="\f"){
+res+="\\f";
+}else{
+if(c=="\n"){
+res+="\\n";
+}else{
+if(c=="\r"){
+res+="\\r";
+}else{
+if(c=="\t"){
+res+="\\t";
+}else{
+if(o.charCodeAt(i)<=31){
+var hex=o.charCodeAt(i).toString(16);
+if(hex.length<2){
+hex="0"+hex;
+}
+res+="\\u00"+hex.toUpperCase();
+}else{
+res+=c;
+}
+}
+}
+}
+}
+}
+}
+}
+}
+return "\""+res+"\"";
+}
+}
+}
+var me=arguments.callee;
+var _f6;
+if(typeof (o.__json__)=="function"){
+_f6=o.__json__();
+if(o!==_f6){
+return me(_f6);
+}
+}
+if(typeof (o.json)=="function"){
+_f6=o.json();
+if(o!==_f6){
+return me(_f6);
+}
+}
+if(_f0!="function"&&typeof (o.length)=="number"){
+var res=[];
+for(var i=0;i<o.length;i++){
+var val=me(o[i]);
+if(typeof (val)!="string"){
+continue;
+}
+res.push(val);
+}
+return "["+res.join(", ")+"]";
+}
+var m=MochiKit.Base;
+try{
+_f6=m.jsonRegistry.match(o);
+if(o!==_f6){
+return me(_f6);
+}
+}
+catch(e){
+if(e!=m.NotFound){
+throw e;
+}
+}
+if(_f0=="undefined"){
+throw new TypeError("undefined can not be serialized as JSON");
+}
+if(_f0=="function"){
+return null;
+}
+res=[];
+for(var k in o){
+var _fa;
+if(typeof (k)=="number"){
+_fa="\""+k+"\"";
+}else{
+if(typeof (k)=="string"){
+_fa=me(k);
+}else{
+continue;
+}
+}
+val=me(o[k]);
+if(typeof (val)!="string"){
+continue;
+}
+res.push(_fa+":"+val);
+}
+return "{"+res.join(", ")+"}";
+},objEqual:function(a,b){
+return (MochiKit.Base.compare(a,b)===0);
+},arrayEqual:function(_fd,arr){
+if(_fd.length!=arr.length){
+return false;
+}
+return (MochiKit.Base.compare(_fd,arr)===0);
+},concat:function(){
+var _ff=[];
+var _100=MochiKit.Base.extend;
+for(var i=0;i<arguments.length;i++){
+_100(_ff,arguments[i]);
+}
+return _ff;
+},keyComparator:function(key){
+var m=MochiKit.Base;
+var _104=m.compare;
+if(arguments.length==1){
+return function(a,b){
+return _104(a[key],b[key]);
+};
+}
+var _107=m.extend(null,arguments);
+return function(a,b){
+var rval=0;
+for(var i=0;(rval===0)&&(i<_107.length);i++){
+var key=_107[i];
+rval=_104(a[key],b[key]);
+}
+return rval;
+};
+},reverseKeyComparator:function(key){
+var _10e=MochiKit.Base.keyComparator.apply(this,arguments);
+return function(a,b){
+return _10e(b,a);
+};
+},partial:function(func){
+var m=MochiKit.Base;
+return m.bind.apply(this,m.extend([func,undefined],arguments,1));
+},listMinMax:function(_113,lst){
+if(lst.length===0){
+return null;
+}
+var cur=lst[0];
+var _116=MochiKit.Base.compare;
+for(var i=1;i<lst.length;i++){
+var o=lst[i];
+if(_116(o,cur)==_113){
+cur=o;
+}
+}
+return cur;
+},objMax:function(){
+return MochiKit.Base.listMinMax(1,arguments);
+},objMin:function(){
+return MochiKit.Base.listMinMax(-1,arguments);
+},findIdentical:function(lst,_11a,_11b,end){
+if(typeof (end)=="undefined"||end===null){
+end=lst.length;
+}
+if(typeof (_11b)=="undefined"||_11b===null){
+_11b=0;
+}
+for(var i=_11b;i<end;i++){
+if(lst[i]===_11a){
+return i;
+}
+}
+return -1;
+},mean:function(){
+var sum=0;
+var m=MochiKit.Base;
+var args=m.extend(null,arguments);
+var _121=args.length;
+while(args.length){
+var o=args.shift();
+if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
+_121+=o.length-1;
+for(var i=o.length-1;i>=0;i--){
+sum+=o[i];
+}
+}else{
+sum+=o;
+}
+}
+if(_121<=0){
+throw new TypeError("mean() requires at least one argument");
+}
+return sum/_121;
+},median:function(){
+var data=MochiKit.Base.flattenArguments(arguments);
+if(data.length===0){
+throw new TypeError("median() requires at least one argument");
+}
+data.sort(compare);
+if(data.length%2==0){
+var _125=data.length/2;
+return (data[_125]+data[_125-1])/2;
+}else{
+return data[(data.length-1)/2];
+}
+},findValue:function(lst,_127,_128,end){
+if(typeof (end)=="undefined"||end===null){
+end=lst.length;
+}
+if(typeof (_128)=="undefined"||_128===null){
+_128=0;
+}
+var cmp=MochiKit.Base.compare;
+for(var i=_128;i<end;i++){
+if(cmp(lst[i],_127)===0){
+return i;
+}
+}
+return -1;
+},nodeWalk:function(node,_12d){
+var _12e=[node];
+var _12f=MochiKit.Base.extend;
+while(_12e.length){
+var res=_12d(_12e.shift());
+if(res){
+_12f(_12e,res);
+}
+}
+},nameFunctions:function(_131){
+var base=_131.NAME;
+if(typeof (base)=="undefined"){
+base="";
+}else{
+base=base+".";
+}
+for(var name in _131){
+var o=_131[name];
+if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
+try{
+o.NAME=base+name;
+}
+catch(e){
+}
+}
+}
+},queryString:function(_135,_136){
+if(typeof (MochiKit.DOM)!="undefined"&&arguments.length==1&&(typeof (_135)=="string"||(typeof (_135.nodeType)!="undefined"&&_135.nodeType>0))){
+var kv=MochiKit.DOM.formContents(_135);
+_135=kv[0];
+_136=kv[1];
+}else{
+if(arguments.length==1){
+if(typeof (_135.length)=="number"&&_135.length==2){
+return arguments.callee(_135[0],_135[1]);
+}
+var o=_135;
+_135=[];
+_136=[];
+for(var k in o){
+var v=o[k];
+if(typeof (v)=="function"){
+continue;
+}else{
+if(MochiKit.Base.isArrayLike(v)){
+for(var i=0;i<v.length;i++){
+_135.push(k);
+_136.push(v[i]);
+}
+}else{
+_135.push(k);
+_136.push(v);
+}
+}
+}
+}
+}
+var rval=[];
+var len=Math.min(_135.length,_136.length);
+var _13e=MochiKit.Base.urlEncode;
+for(var i=0;i<len;i++){
+v=_136[i];
+if(typeof (v)!="undefined"&&v!==null){
+rval.push(_13e(_135[i])+"="+_13e(v));
+}
+}
+return rval.join("&");
+},parseQueryString:function(_13f,_140){
+var qstr=(_13f.charAt(0)=="?")?_13f.substring(1):_13f;
+var _142=qstr.replace(/\+/g,"%20").split(/\&\;|\&\#38\;|\&|\&/);
+var o={};
+var _144;
+if(typeof (decodeURIComponent)!="undefined"){
+_144=decodeURIComponent;
+}else{
+_144=unescape;
+}
+if(_140){
+for(var i=0;i<_142.length;i++){
+var pair=_142[i].split("=");
+var name=_144(pair.shift());
+if(!name){
+continue;
+}
+var arr=o[name];
+if(!(arr instanceof Array)){
+arr=[];
+o[name]=arr;
+}
+arr.push(_144(pair.join("=")));
+}
+}else{
+for(i=0;i<_142.length;i++){
+pair=_142[i].split("=");
+var name=pair.shift();
+if(!name){
+continue;
+}
+o[_144(name)]=_144(pair.join("="));
+}
+}
+return o;
+}});
+MochiKit.Base.AdapterRegistry=function(){
+this.pairs=[];
+};
+MochiKit.Base.AdapterRegistry.prototype={register:function(name,_14a,wrap,_14c){
+if(_14c){
+this.pairs.unshift([name,_14a,wrap]);
+}else{
+this.pairs.push([name,_14a,wrap]);
+}
+},match:function(){
+for(var i=0;i<this.pairs.length;i++){
+var pair=this.pairs[i];
+if(pair[1].apply(this,arguments)){
+return pair[2].apply(this,arguments);
+}
+}
+throw MochiKit.Base.NotFound;
+},unregister:function(name){
+for(var i=0;i<this.pairs.length;i++){
+var pair=this.pairs[i];
+if(pair[0]==name){
+this.pairs.splice(i,1);
+return true;
+}
+}
+return false;
+}};
+MochiKit.Base.EXPORT=["flattenArray","noop","camelize","counter","clone","extend","update","updatetree","setdefault","keys","values","items","NamedError","operator","forwardCall","itemgetter","typeMatcher","isCallable","isUndefined","isUndefinedOrNull","isNull","isEmpty","isNotEmpty","isArrayLike","isDateLike","xmap","map","xfilter","filter","methodcaller","compose","bind","bindLate","bindMethods","NotFound","AdapterRegistry","registerComparator","compare","registerRepr","repr","objEqual","arrayEqual","concat","keyComparator","reverseKeyComparator","partial","merge","listMinMax","listMax","listMin","objMax","objMin","nodeWalk","zip","urlEncode","queryString","serializeJSON","registerJSON","evalJSON","parseQueryString","findValue","findIdentical","flattenArguments","method","average","mean","median"];
+MochiKit.Base.EXPORT_OK=["nameFunctions","comparatorRegistry","reprRegistry","jsonRegistry","compareDateLike","compareArrayLike","reprArrayLike","reprString","reprNumber"];
+MochiKit.Base._exportSymbols=function(_152,_153){
+if(!MochiKit.__export__){
+return;
+}
+var all=_153.EXPORT_TAGS[":all"];
+for(var i=0;i<all.length;i++){
+_152[all[i]]=_153[all[i]];
+}
+};
+MochiKit.Base.__new__=function(){
+var m=this;
+m.noop=m.operator.identity;
+m.forward=m.forwardCall;
+m.find=m.findValue;
+if(typeof (encodeURIComponent)!="undefined"){
+m.urlEncode=function(_157){
+return encodeURIComponent(_157).replace(/\'/g,"%27");
+};
+}else{
+m.urlEncode=function(_158){
+return escape(_158).replace(/\+/g,"%2B").replace(/\"/g,"%22").rval.replace(/\'/g,"%27");
+};
+}
+m.NamedError=function(name){
+this.message=name;
+this.name=name;
+};
+m.NamedError.prototype=new Error();
+m.update(m.NamedError.prototype,{repr:function(){
+if(this.message&&this.message!=this.name){
+return this.name+"("+m.repr(this.message)+")";
+}else{
+return this.name+"()";
+}
+},toString:m.forwardCall("repr")});
+m.NotFound=new m.NamedError("MochiKit.Base.NotFound");
+m.listMax=m.partial(m.listMinMax,1);
+m.listMin=m.partial(m.listMinMax,-1);
+m.isCallable=m.typeMatcher("function");
+m.isUndefined=m.typeMatcher("undefined");
+m.merge=m.partial(m.update,null);
+m.zip=m.partial(m.map,null);
+m.average=m.mean;
+m.comparatorRegistry=new m.AdapterRegistry();
+m.registerComparator("dateLike",m.isDateLike,m.compareDateLike);
+m.registerComparator("arrayLike",m.isArrayLike,m.compareArrayLike);
+m.reprRegistry=new m.AdapterRegistry();
+m.registerRepr("arrayLike",m.isArrayLike,m.reprArrayLike);
+m.registerRepr("string",m.typeMatcher("string"),m.reprString);
+m.registerRepr("numbers",m.typeMatcher("number","boolean"),m.reprNumber);
+m.jsonRegistry=new m.AdapterRegistry();
+var all=m.concat(m.EXPORT,m.EXPORT_OK);
+m.EXPORT_TAGS={":common":m.concat(m.EXPORT_OK),":all":all};
+m.nameFunctions(this);
+};
+MochiKit.Base.__new__();
+if(MochiKit.__export__){
+compare=MochiKit.Base.compare;
+compose=MochiKit.Base.compose;
+serializeJSON=MochiKit.Base.serializeJSON;
+mean=MochiKit.Base.mean;
+median=MochiKit.Base.median;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Base);
+MochiKit.Base._deps("Iter",["Base"]);
+MochiKit.Iter.NAME="MochiKit.Iter";
+MochiKit.Iter.VERSION="1.4.2";
+MochiKit.Base.update(MochiKit.Iter,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},registerIteratorFactory:function(name,_15c,_15d,_15e){
+MochiKit.Iter.iteratorRegistry.register(name,_15c,_15d,_15e);
+},isIterable:function(o){
+return o!=null&&(typeof (o.next)=="function"||typeof (o.iter)=="function");
+},iter:function(_160,_161){
+var self=MochiKit.Iter;
+if(arguments.length==2){
+return self.takewhile(function(a){
+return a!=_161;
+},_160);
+}
+if(typeof (_160.next)=="function"){
+return _160;
+}else{
+if(typeof (_160.iter)=="function"){
+return _160.iter();
+}
+}
+try{
+return self.iteratorRegistry.match(_160);
+}
+catch(e){
+var m=MochiKit.Base;
+if(e==m.NotFound){
+e=new TypeError(typeof (_160)+": "+m.repr(_160)+" is not iterable");
+}
+throw e;
+}
+},count:function(n){
+if(!n){
+n=0;
+}
+var m=MochiKit.Base;
+return {repr:function(){
+return "count("+n+")";
+},toString:m.forwardCall("repr"),next:m.counter(n)};
+},cycle:function(p){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+var lst=[];
+var _16b=self.iter(p);
+return {repr:function(){
+return "cycle(...)";
+},toString:m.forwardCall("repr"),next:function(){
+try{
+var rval=_16b.next();
+lst.push(rval);
+return rval;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+if(lst.length===0){
+this.next=function(){
+throw self.StopIteration;
+};
+}else{
+var i=-1;
+this.next=function(){
+i=(i+1)%lst.length;
+return lst[i];
+};
+}
+return this.next();
+}
+}};
+},repeat:function(elem,n){
+var m=MochiKit.Base;
+if(typeof (n)=="undefined"){
+return {repr:function(){
+return "repeat("+m.repr(elem)+")";
+},toString:m.forwardCall("repr"),next:function(){
+return elem;
+}};
+}
+return {repr:function(){
+return "repeat("+m.repr(elem)+", "+n+")";
+},toString:m.forwardCall("repr"),next:function(){
+if(n<=0){
+throw MochiKit.Iter.StopIteration;
+}
+n-=1;
+return elem;
+}};
+},next:function(_171){
+return _171.next();
+},izip:function(p,q){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+var next=self.next;
+var _177=m.map(self.iter,arguments);
+return {repr:function(){
+return "izip(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return m.map(next,_177);
+}};
+},ifilter:function(pred,seq){
+var m=MochiKit.Base;
+seq=MochiKit.Iter.iter(seq);
+if(pred===null){
+pred=m.operator.truth;
+}
+return {repr:function(){
+return "ifilter(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(true){
+var rval=seq.next();
+if(pred(rval)){
+return rval;
+}
+}
+return undefined;
+}};
+},ifilterfalse:function(pred,seq){
+var m=MochiKit.Base;
+seq=MochiKit.Iter.iter(seq);
+if(pred===null){
+pred=m.operator.truth;
+}
+return {repr:function(){
+return "ifilterfalse(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(true){
+var rval=seq.next();
+if(!pred(rval)){
+return rval;
+}
+}
+return undefined;
+}};
+},islice:function(seq){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+seq=self.iter(seq);
+var _183=0;
+var stop=0;
+var step=1;
+var i=-1;
+if(arguments.length==2){
+stop=arguments[1];
+}else{
+if(arguments.length==3){
+_183=arguments[1];
+stop=arguments[2];
+}else{
+_183=arguments[1];
+stop=arguments[2];
+step=arguments[3];
+}
+}
+return {repr:function(){
+return "islice("+["...",_183,stop,step].join(", ")+")";
+},toString:m.forwardCall("repr"),next:function(){
+var rval;
+while(i<_183){
+rval=seq.next();
+i++;
+}
+if(_183>=stop){
+throw self.StopIteration;
+}
+_183+=step;
+return rval;
+}};
+},imap:function(fun,p,q){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+var _18d=m.map(self.iter,m.extend(null,arguments,1));
+var map=m.map;
+var next=self.next;
+return {repr:function(){
+return "imap(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return fun.apply(this,map(next,_18d));
+}};
+},applymap:function(fun,seq,self){
+seq=MochiKit.Iter.iter(seq);
+var m=MochiKit.Base;
+return {repr:function(){
+return "applymap(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return fun.apply(self,seq.next());
+}};
+},chain:function(p,q){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+if(arguments.length==1){
+return self.iter(arguments[0]);
+}
+var _198=m.map(self.iter,arguments);
+return {repr:function(){
+return "chain(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(_198.length>1){
+try{
+var _199=_198[0].next();
+return _199;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+_198.shift();
+var _199=_198[0].next();
+return _199;
+}
+}
+if(_198.length==1){
+var arg=_198.shift();
+this.next=m.bind("next",arg);
+return this.next();
+}
+throw self.StopIteration;
+}};
+},takewhile:function(pred,seq){
+var self=MochiKit.Iter;
+seq=self.iter(seq);
+return {repr:function(){
+return "takewhile(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+var rval=seq.next();
+if(!pred(rval)){
+this.next=function(){
+throw self.StopIteration;
+};
+this.next();
+}
+return rval;
+}};
+},dropwhile:function(pred,seq){
+seq=MochiKit.Iter.iter(seq);
+var m=MochiKit.Base;
+var bind=m.bind;
+return {"repr":function(){
+return "dropwhile(...)";
+},"toString":m.forwardCall("repr"),"next":function(){
+while(true){
+var rval=seq.next();
+if(!pred(rval)){
+break;
+}
+}
+this.next=bind("next",seq);
+return rval;
+}};
+},_tee:function(_1a4,sync,_1a6){
+sync.pos[_1a4]=-1;
+var m=MochiKit.Base;
+var _1a8=m.listMin;
+return {repr:function(){
+return "tee("+_1a4+", ...)";
+},toString:m.forwardCall("repr"),next:function(){
+var rval;
+var i=sync.pos[_1a4];
+if(i==sync.max){
+rval=_1a6.next();
+sync.deque.push(rval);
+sync.max+=1;
+sync.pos[_1a4]+=1;
+}else{
+rval=sync.deque[i-sync.min];
+sync.pos[_1a4]+=1;
+if(i==sync.min&&_1a8(sync.pos)!=sync.min){
+sync.min+=1;
+sync.deque.shift();
+}
+}
+return rval;
+}};
+},tee:function(_1ab,n){
+var rval=[];
+var sync={"pos":[],"deque":[],"max":-1,"min":-1};
+if(arguments.length==1||typeof (n)=="undefined"||n===null){
+n=2;
+}
+var self=MochiKit.Iter;
+_1ab=self.iter(_1ab);
+var _tee=self._tee;
+for(var i=0;i<n;i++){
+rval.push(_tee(i,sync,_1ab));
+}
+return rval;
+},list:function(_1b2){
+var rval;
+if(_1b2 instanceof Array){
+return _1b2.slice();
+}
+if(typeof (_1b2)=="function"&&!(_1b2 instanceof Function)&&typeof (_1b2.length)=="number"){
+rval=[];
+for(var i=0;i<_1b2.length;i++){
+rval.push(_1b2[i]);
+}
+return rval;
+}
+var self=MochiKit.Iter;
+_1b2=self.iter(_1b2);
+var rval=[];
+var _1b6;
+try{
+while(true){
+_1b6=_1b2.next();
+rval.push(_1b6);
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return rval;
+}
+return undefined;
+},reduce:function(fn,_1b8,_1b9){
+var i=0;
+var x=_1b9;
+var self=MochiKit.Iter;
+_1b8=self.iter(_1b8);
+if(arguments.length<3){
+try{
+x=_1b8.next();
+}
+catch(e){
+if(e==self.StopIteration){
+e=new TypeError("reduce() of empty sequence with no initial value");
+}
+throw e;
+}
+i++;
+}
+try{
+while(true){
+x=fn(x,_1b8.next());
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+return x;
+},range:function(){
+var _1bd=0;
+var stop=0;
+var step=1;
+if(arguments.length==1){
+stop=arguments[0];
+}else{
+if(arguments.length==2){
+_1bd=arguments[0];
+stop=arguments[1];
+}else{
+if(arguments.length==3){
+_1bd=arguments[0];
+stop=arguments[1];
+step=arguments[2];
+}else{
+throw new TypeError("range() takes 1, 2, or 3 arguments!");
+}
+}
+}
+if(step===0){
+throw new TypeError("range() step must not be 0");
+}
+return {next:function(){
+if((step>0&&_1bd>=stop)||(step<0&&_1bd<=stop)){
+throw MochiKit.Iter.StopIteration;
+}
+var rval=_1bd;
+_1bd+=step;
+return rval;
+},repr:function(){
+return "range("+[_1bd,stop,step].join(", ")+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+},sum:function(_1c1,_1c2){
+if(typeof (_1c2)=="undefined"||_1c2===null){
+_1c2=0;
+}
+var x=_1c2;
+var self=MochiKit.Iter;
+_1c1=self.iter(_1c1);
+try{
+while(true){
+x+=_1c1.next();
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+return x;
+},exhaust:function(_1c5){
+var self=MochiKit.Iter;
+_1c5=self.iter(_1c5);
+try{
+while(true){
+_1c5.next();
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+},forEach:function(_1c7,func,obj){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(arguments.length>2){
+func=m.bind(func,obj);
+}
+if(m.isArrayLike(_1c7)&&!self.isIterable(_1c7)){
+try{
+for(var i=0;i<_1c7.length;i++){
+func(_1c7[i]);
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+}else{
+self.exhaust(self.imap(func,_1c7));
+}
+},every:function(_1cd,func){
+var self=MochiKit.Iter;
+try{
+self.ifilterfalse(func,_1cd).next();
+return false;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return true;
+}
+},sorted:function(_1d0,cmp){
+var rval=MochiKit.Iter.list(_1d0);
+if(arguments.length==1){
+cmp=MochiKit.Base.compare;
+}
+rval.sort(cmp);
+return rval;
+},reversed:function(_1d3){
+var rval=MochiKit.Iter.list(_1d3);
+rval.reverse();
+return rval;
+},some:function(_1d5,func){
+var self=MochiKit.Iter;
+try{
+self.ifilter(func,_1d5).next();
+return true;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return false;
+}
+},iextend:function(lst,_1d9){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(m.isArrayLike(_1d9)&&!self.isIterable(_1d9)){
+for(var i=0;i<_1d9.length;i++){
+lst.push(_1d9[i]);
+}
+}else{
+_1d9=self.iter(_1d9);
+try{
+while(true){
+lst.push(_1d9.next());
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+}
+return lst;
+},groupby:function(_1dd,_1de){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(arguments.length<2){
+_1de=m.operator.identity;
+}
+_1dd=self.iter(_1dd);
+var pk=undefined;
+var k=undefined;
+var v;
+function fetch(){
+v=_1dd.next();
+k=_1de(v);
+}
+function eat(){
+var ret=v;
+v=undefined;
+return ret;
+}
+var _1e5=true;
+var _1e6=m.compare;
+return {repr:function(){
+return "groupby(...)";
+},next:function(){
+while(_1e6(k,pk)===0){
+fetch();
+if(_1e5){
+_1e5=false;
+break;
+}
+}
+pk=k;
+return [k,{next:function(){
+if(v==undefined){
+fetch();
+}
+if(_1e6(k,pk)!==0){
+throw self.StopIteration;
+}
+return eat();
+}}];
+}};
+},groupby_as_array:function(_1e7,_1e8){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(arguments.length<2){
+_1e8=m.operator.identity;
+}
+_1e7=self.iter(_1e7);
+var _1eb=[];
+var _1ec=true;
+var _1ed;
+var _1ee=m.compare;
+while(true){
+try{
+var _1ef=_1e7.next();
+var key=_1e8(_1ef);
+}
+catch(e){
+if(e==self.StopIteration){
+break;
+}
+throw e;
+}
+if(_1ec||_1ee(key,_1ed)!==0){
+var _1f1=[];
+_1eb.push([key,_1f1]);
+}
+_1f1.push(_1ef);
+_1ec=false;
+_1ed=key;
+}
+return _1eb;
+},arrayLikeIter:function(_1f2){
+var i=0;
+return {repr:function(){
+return "arrayLikeIter(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+if(i>=_1f2.length){
+throw MochiKit.Iter.StopIteration;
+}
+return _1f2[i++];
+}};
+},hasIterateNext:function(_1f4){
+return (_1f4&&typeof (_1f4.iterateNext)=="function");
+},iterateNextIter:function(_1f5){
+return {repr:function(){
+return "iterateNextIter(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+var rval=_1f5.iterateNext();
+if(rval===null||rval===undefined){
+throw MochiKit.Iter.StopIteration;
+}
+return rval;
+}};
+}});
+MochiKit.Iter.EXPORT_OK=["iteratorRegistry","arrayLikeIter","hasIterateNext","iterateNextIter"];
+MochiKit.Iter.EXPORT=["StopIteration","registerIteratorFactory","iter","count","cycle","repeat","next","izip","ifilter","ifilterfalse","islice","imap","applymap","chain","takewhile","dropwhile","tee","list","reduce","range","sum","exhaust","forEach","every","sorted","reversed","some","iextend","groupby","groupby_as_array"];
+MochiKit.Iter.__new__=function(){
+var m=MochiKit.Base;
+if(typeof (StopIteration)!="undefined"){
+this.StopIteration=StopIteration;
+}else{
+this.StopIteration=new m.NamedError("StopIteration");
+}
+this.iteratorRegistry=new m.AdapterRegistry();
+this.registerIteratorFactory("arrayLike",m.isArrayLike,this.arrayLikeIter);
+this.registerIteratorFactory("iterateNext",this.hasIterateNext,this.iterateNextIter);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Iter.__new__();
+if(MochiKit.__export__){
+reduce=MochiKit.Iter.reduce;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Iter);
+MochiKit.Base._deps("Logging",["Base"]);
+MochiKit.Logging.NAME="MochiKit.Logging";
+MochiKit.Logging.VERSION="1.4.2";
+MochiKit.Logging.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Logging.toString=function(){
+return this.__repr__();
+};
+MochiKit.Logging.EXPORT=["LogLevel","LogMessage","Logger","alertListener","logger","log","logError","logDebug","logFatal","logWarning"];
+MochiKit.Logging.EXPORT_OK=["logLevelAtLeast","isLogMessage","compareLogMessage"];
+MochiKit.Logging.LogMessage=function(num,_1f9,info){
+this.num=num;
+this.level=_1f9;
+this.info=info;
+this.timestamp=new Date();
+};
+MochiKit.Logging.LogMessage.prototype={repr:function(){
+var m=MochiKit.Base;
+return "LogMessage("+m.map(m.repr,[this.num,this.level,this.info]).join(", ")+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+MochiKit.Base.update(MochiKit.Logging,{logLevelAtLeast:function(_1fc){
+var self=MochiKit.Logging;
+if(typeof (_1fc)=="string"){
+_1fc=self.LogLevel[_1fc];
+}
+return function(msg){
+var _1ff=msg.level;
+if(typeof (_1ff)=="string"){
+_1ff=self.LogLevel[_1ff];
+}
+return _1ff>=_1fc;
+};
+},isLogMessage:function(){
+var _200=MochiKit.Logging.LogMessage;
+for(var i=0;i<arguments.length;i++){
+if(!(arguments[i] instanceof _200)){
+return false;
+}
+}
+return true;
+},compareLogMessage:function(a,b){
+return MochiKit.Base.compare([a.level,a.info],[b.level,b.info]);
+},alertListener:function(msg){
+alert("num: "+msg.num+"\nlevel: "+msg.level+"\ninfo: "+msg.info.join(" "));
+}});
+MochiKit.Logging.Logger=function(_205){
+this.counter=0;
+if(typeof (_205)=="undefined"||_205===null){
+_205=-1;
+}
+this.maxSize=_205;
+this._messages=[];
+this.listeners={};
+this.useNativeConsole=false;
+};
+MochiKit.Logging.Logger.prototype={clear:function(){
+this._messages.splice(0,this._messages.length);
+},logToConsole:function(msg){
+if(typeof (window)!="undefined"&&window.console&&window.console.log){
+window.console.log(msg.replace(/%/g,"\uff05"));
+}else{
+if(typeof (opera)!="undefined"&&opera.postError){
+opera.postError(msg);
+}else{
+if(typeof (printfire)=="function"){
+printfire(msg);
+}else{
+if(typeof (Debug)!="undefined"&&Debug.writeln){
+Debug.writeln(msg);
+}else{
+if(typeof (debug)!="undefined"&&debug.trace){
+debug.trace(msg);
+}
+}
+}
+}
+}
+},dispatchListeners:function(msg){
+for(var k in this.listeners){
+var pair=this.listeners[k];
+if(pair.ident!=k||(pair[0]&&!pair[0](msg))){
+continue;
+}
+pair[1](msg);
+}
+},addListener:function(_20a,_20b,_20c){
+if(typeof (_20b)=="string"){
+_20b=MochiKit.Logging.logLevelAtLeast(_20b);
+}
+var _20d=[_20b,_20c];
+_20d.ident=_20a;
+this.listeners[_20a]=_20d;
+},removeListener:function(_20e){
+delete this.listeners[_20e];
+},baseLog:function(_20f,_210){
+if(typeof (_20f)=="number"){
+if(_20f>=MochiKit.Logging.LogLevel.FATAL){
+_20f="FATAL";
+}else{
+if(_20f>=MochiKit.Logging.LogLevel.ERROR){
+_20f="ERROR";
+}else{
+if(_20f>=MochiKit.Logging.LogLevel.WARNING){
+_20f="WARNING";
+}else{
+if(_20f>=MochiKit.Logging.LogLevel.INFO){
+_20f="INFO";
+}else{
+_20f="DEBUG";
+}
+}
+}
+}
+}
+var msg=new MochiKit.Logging.LogMessage(this.counter,_20f,MochiKit.Base.extend(null,arguments,1));
+this._messages.push(msg);
+this.dispatchListeners(msg);
+if(this.useNativeConsole){
+this.logToConsole(msg.level+": "+msg.info.join(" "));
+}
+this.counter+=1;
+while(this.maxSize>=0&&this._messages.length>this.maxSize){
+this._messages.shift();
+}
+},getMessages:function(_212){
+var _213=0;
+if(!(typeof (_212)=="undefined"||_212===null)){
+_213=Math.max(0,this._messages.length-_212);
+}
+return this._messages.slice(_213);
+},getMessageText:function(_214){
+if(typeof (_214)=="undefined"||_214===null){
+_214=30;
+}
+var _215=this.getMessages(_214);
+if(_215.length){
+var lst=map(function(m){
+return "\n ["+m.num+"] "+m.level+": "+m.info.join(" ");
+},_215);
+lst.unshift("LAST "+_215.length+" MESSAGES:");
+return lst.join("");
+}
+return "";
+},debuggingBookmarklet:function(_218){
+if(typeof (MochiKit.LoggingPane)=="undefined"){
+alert(this.getMessageText());
+}else{
+MochiKit.LoggingPane.createLoggingPane(_218||false);
+}
+}};
+MochiKit.Logging.__new__=function(){
+this.LogLevel={ERROR:40,FATAL:50,WARNING:30,INFO:20,DEBUG:10};
+var m=MochiKit.Base;
+m.registerComparator("LogMessage",this.isLogMessage,this.compareLogMessage);
+var _21a=m.partial;
+var _21b=this.Logger;
+var _21c=_21b.prototype.baseLog;
+m.update(this.Logger.prototype,{debug:_21a(_21c,"DEBUG"),log:_21a(_21c,"INFO"),error:_21a(_21c,"ERROR"),fatal:_21a(_21c,"FATAL"),warning:_21a(_21c,"WARNING")});
+var self=this;
+var _21e=function(name){
+return function(){
+self.logger[name].apply(self.logger,arguments);
+};
+};
+this.log=_21e("log");
+this.logError=_21e("error");
+this.logDebug=_21e("debug");
+this.logFatal=_21e("fatal");
+this.logWarning=_21e("warning");
+this.logger=new _21b();
+this.logger.useNativeConsole=true;
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+if(typeof (printfire)=="undefined"&&typeof (document)!="undefined"&&document.createEvent&&typeof (dispatchEvent)!="undefined"){
+printfire=function(){
+printfire.args=arguments;
+var ev=document.createEvent("Events");
+ev.initEvent("printfire",false,true);
+dispatchEvent(ev);
+};
+}
+MochiKit.Logging.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Logging);
+MochiKit.Base._deps("DateTime",["Base"]);
+MochiKit.DateTime.NAME="MochiKit.DateTime";
+MochiKit.DateTime.VERSION="1.4.2";
+MochiKit.DateTime.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.DateTime.toString=function(){
+return this.__repr__();
+};
+MochiKit.DateTime.isoDate=function(str){
+str=str+"";
+if(typeof (str)!="string"||str.length===0){
+return null;
+}
+var iso=str.split("-");
+if(iso.length===0){
+return null;
+}
+var date=new Date(iso[0],iso[1]-1,iso[2]);
+date.setFullYear(iso[0]);
+date.setMonth(iso[1]-1);
+date.setDate(iso[2]);
+return date;
+};
+MochiKit.DateTime._isoRegexp=/(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
+MochiKit.DateTime.isoTimestamp=function(str){
+str=str+"";
+if(typeof (str)!="string"||str.length===0){
+return null;
+}
+var res=str.match(MochiKit.DateTime._isoRegexp);
+if(typeof (res)=="undefined"||res===null){
+return null;
+}
+var year,_227,day,hour,min,sec,msec;
+year=parseInt(res[1],10);
+if(typeof (res[2])=="undefined"||res[2]===""){
+return new Date(year);
+}
+_227=parseInt(res[2],10)-1;
+day=parseInt(res[3],10);
+if(typeof (res[4])=="undefined"||res[4]===""){
+return new Date(year,_227,day);
+}
+hour=parseInt(res[4],10);
+min=parseInt(res[5],10);
+sec=(typeof (res[6])!="undefined"&&res[6]!=="")?parseInt(res[6],10):0;
+if(typeof (res[7])!="undefined"&&res[7]!==""){
+msec=Math.round(1000*parseFloat("0."+res[7]));
+}else{
+msec=0;
+}
+if((typeof (res[8])=="undefined"||res[8]==="")&&(typeof (res[9])=="undefined"||res[9]==="")){
+return new Date(year,_227,day,hour,min,sec,msec);
+}
+var ofs;
+if(typeof (res[9])!="undefined"&&res[9]!==""){
+ofs=parseInt(res[10],10)*3600000;
+if(typeof (res[11])!="undefined"&&res[11]!==""){
+ofs+=parseInt(res[11],10)*60000;
+}
+if(res[9]=="-"){
+ofs=-ofs;
+}
+}else{
+ofs=0;
+}
+return new Date(Date.UTC(year,_227,day,hour,min,sec,msec)-ofs);
+};
+MochiKit.DateTime.toISOTime=function(date,_22f){
+if(typeof (date)=="undefined"||date===null){
+return null;
+}
+var hh=date.getHours();
+var mm=date.getMinutes();
+var ss=date.getSeconds();
+var lst=[((_22f&&(hh<10))?"0"+hh:hh),((mm<10)?"0"+mm:mm),((ss<10)?"0"+ss:ss)];
+return lst.join(":");
+};
+MochiKit.DateTime.toISOTimestamp=function(date,_235){
+if(typeof (date)=="undefined"||date===null){
+return null;
+}
+var sep=_235?"T":" ";
+var foot=_235?"Z":"";
+if(_235){
+date=new Date(date.getTime()+(date.getTimezoneOffset()*60000));
+}
+return MochiKit.DateTime.toISODate(date)+sep+MochiKit.DateTime.toISOTime(date,_235)+foot;
+};
+MochiKit.DateTime.toISODate=function(date){
+if(typeof (date)=="undefined"||date===null){
+return null;
+}
+var _239=MochiKit.DateTime._padTwo;
+var _23a=MochiKit.DateTime._padFour;
+return [_23a(date.getFullYear()),_239(date.getMonth()+1),_239(date.getDate())].join("-");
+};
+MochiKit.DateTime.americanDate=function(d){
+d=d+"";
+if(typeof (d)!="string"||d.length===0){
+return null;
+}
+var a=d.split("/");
+return new Date(a[2],a[0]-1,a[1]);
+};
+MochiKit.DateTime._padTwo=function(n){
+return (n>9)?n:"0"+n;
+};
+MochiKit.DateTime._padFour=function(n){
+switch(n.toString().length){
+case 1:
+return "000"+n;
+break;
+case 2:
+return "00"+n;
+break;
+case 3:
+return "0"+n;
+break;
+case 4:
+default:
+return n;
+}
+};
+MochiKit.DateTime.toPaddedAmericanDate=function(d){
+if(typeof (d)=="undefined"||d===null){
+return null;
+}
+var _240=MochiKit.DateTime._padTwo;
+return [_240(d.getMonth()+1),_240(d.getDate()),d.getFullYear()].join("/");
+};
+MochiKit.DateTime.toAmericanDate=function(d){
+if(typeof (d)=="undefined"||d===null){
+return null;
+}
+return [d.getMonth()+1,d.getDate(),d.getFullYear()].join("/");
+};
+MochiKit.DateTime.EXPORT=["isoDate","isoTimestamp","toISOTime","toISOTimestamp","toISODate","americanDate","toPaddedAmericanDate","toAmericanDate"];
+MochiKit.DateTime.EXPORT_OK=[];
+MochiKit.DateTime.EXPORT_TAGS={":common":MochiKit.DateTime.EXPORT,":all":MochiKit.DateTime.EXPORT};
+MochiKit.DateTime.__new__=function(){
+var base=this.NAME+".";
+for(var k in this){
+var o=this[k];
+if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
+try{
+o.NAME=base+k;
+}
+catch(e){
+}
+}
+}
+};
+MochiKit.DateTime.__new__();
+if(typeof (MochiKit.Base)!="undefined"){
+MochiKit.Base._exportSymbols(this,MochiKit.DateTime);
+}else{
+(function(_245,_246){
+if((typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined")||(MochiKit.__export__===false)){
+var all=_246.EXPORT_TAGS[":all"];
+for(var i=0;i<all.length;i++){
+_245[all[i]]=_246[all[i]];
+}
+}
+})(this,MochiKit.DateTime);
+}
+MochiKit.Base._deps("Format",["Base"]);
+MochiKit.Format.NAME="MochiKit.Format";
+MochiKit.Format.VERSION="1.4.2";
+MochiKit.Format.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Format.toString=function(){
+return this.__repr__();
+};
+MochiKit.Format._numberFormatter=function(_249,_24a,_24b,_24c,_24d,_24e,_24f,_250,_251){
+return function(num){
+num=parseFloat(num);
+if(typeof (num)=="undefined"||num===null||isNaN(num)){
+return _249;
+}
+var _253=_24a;
+var _254=_24b;
+if(num<0){
+num=-num;
+}else{
+_253=_253.replace(/-/,"");
+}
+var me=arguments.callee;
+var fmt=MochiKit.Format.formatLocale(_24c);
+if(_24d){
+num=num*100;
+_254=fmt.percent+_254;
+}
+num=MochiKit.Format.roundToFixed(num,_24e);
+var _257=num.split(/\./);
+var _258=_257[0];
+var frac=(_257.length==1)?"":_257[1];
+var res="";
+while(_258.length<_24f){
+_258="0"+_258;
+}
+if(_250){
+while(_258.length>_250){
+var i=_258.length-_250;
+res=fmt.separator+_258.substring(i,_258.length)+res;
+_258=_258.substring(0,i);
+}
+}
+res=_258+res;
+if(_24e>0){
+while(frac.length<_251){
+frac=frac+"0";
+}
+res=res+fmt.decimal+frac;
+}
+return _253+res+_254;
+};
+};
+MochiKit.Format.numberFormatter=function(_25c,_25d,_25e){
+if(typeof (_25d)=="undefined"){
+_25d="";
+}
+var _25f=_25c.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
+if(!_25f){
+throw TypeError("Invalid pattern");
+}
+var _260=_25c.substr(0,_25f.index);
+var _261=_25c.substr(_25f.index+_25f[0].length);
+if(_260.search(/-/)==-1){
+_260=_260+"-";
+}
+var _262=_25f[1];
+var frac=(typeof (_25f[2])=="string"&&_25f[2]!="")?_25f[2]:"";
+var _264=(typeof (_25f[3])=="string"&&_25f[3]!="");
+var tmp=_262.split(/,/);
+var _266;
+if(typeof (_25e)=="undefined"){
+_25e="default";
+}
+if(tmp.length==1){
+_266=null;
+}else{
+_266=tmp[1].length;
+}
+var _267=_262.length-_262.replace(/0/g,"").length;
+var _268=frac.length-frac.replace(/0/g,"").length;
+var _269=frac.length;
+var rval=MochiKit.Format._numberFormatter(_25d,_260,_261,_25e,_264,_269,_267,_266,_268);
+var m=MochiKit.Base;
+if(m){
+var fn=arguments.callee;
+var args=m.concat(arguments);
+rval.repr=function(){
+return [self.NAME,"(",map(m.repr,args).join(", "),")"].join("");
+};
+}
+return rval;
+};
+MochiKit.Format.formatLocale=function(_26e){
+if(typeof (_26e)=="undefined"||_26e===null){
+_26e="default";
+}
+if(typeof (_26e)=="string"){
+var rval=MochiKit.Format.LOCALE[_26e];
+if(typeof (rval)=="string"){
+rval=arguments.callee(rval);
+MochiKit.Format.LOCALE[_26e]=rval;
+}
+return rval;
+}else{
+return _26e;
+}
+};
+MochiKit.Format.twoDigitAverage=function(_270,_271){
+if(_271){
+var res=_270/_271;
+if(!isNaN(res)){
+return MochiKit.Format.twoDigitFloat(res);
+}
+}
+return "0";
+};
+MochiKit.Format.twoDigitFloat=function(_273){
+var res=roundToFixed(_273,2);
+if(res.indexOf(".00")>0){
+return res.substring(0,res.length-3);
+}else{
+if(res.charAt(res.length-1)=="0"){
+return res.substring(0,res.length-1);
+}else{
+return res;
+}
+}
+};
+MochiKit.Format.lstrip=function(str,_276){
+str=str+"";
+if(typeof (str)!="string"){
+return null;
+}
+if(!_276){
+return str.replace(/^\s+/,"");
+}else{
+return str.replace(new RegExp("^["+_276+"]+"),"");
+}
+};
+MochiKit.Format.rstrip=function(str,_278){
+str=str+"";
+if(typeof (str)!="string"){
+return null;
+}
+if(!_278){
+return str.replace(/\s+$/,"");
+}else{
+return str.replace(new RegExp("["+_278+"]+$"),"");
+}
+};
+MochiKit.Format.strip=function(str,_27a){
+var self=MochiKit.Format;
+return self.rstrip(self.lstrip(str,_27a),_27a);
+};
+MochiKit.Format.truncToFixed=function(_27c,_27d){
+var res=Math.floor(_27c).toFixed(0);
+if(_27c<0){
+res=Math.ceil(_27c).toFixed(0);
+if(res.charAt(0)!="-"&&_27d>0){
+res="-"+res;
+}
+}
+if(res.indexOf("e")<0&&_27d>0){
+var tail=_27c.toString();
+if(tail.indexOf("e")>0){
+tail=".";
+}else{
+if(tail.indexOf(".")<0){
+tail=".";
+}else{
+tail=tail.substring(tail.indexOf("."));
+}
+}
+if(tail.length-1>_27d){
+tail=tail.substring(0,_27d+1);
+}
+while(tail.length-1<_27d){
+tail+="0";
+}
+res+=tail;
+}
+return res;
+};
+MochiKit.Format.roundToFixed=function(_280,_281){
+var _282=Math.abs(_280)+0.5*Math.pow(10,-_281);
+var res=MochiKit.Format.truncToFixed(_282,_281);
+if(_280<0){
+res="-"+res;
+}
+return res;
+};
+MochiKit.Format.percentFormat=function(_284){
+return MochiKit.Format.twoDigitFloat(100*_284)+"%";
+};
+MochiKit.Format.EXPORT=["truncToFixed","roundToFixed","numberFormatter","formatLocale","twoDigitAverage","twoDigitFloat","percentFormat","lstrip","rstrip","strip"];
+MochiKit.Format.LOCALE={en_US:{separator:",",decimal:".",percent:"%"},de_DE:{separator:".",decimal:",",percent:"%"},pt_BR:{separator:".",decimal:",",percent:"%"},fr_FR:{separator:" ",decimal:",",percent:"%"},"default":"en_US"};
+MochiKit.Format.EXPORT_OK=[];
+MochiKit.Format.EXPORT_TAGS={":all":MochiKit.Format.EXPORT,":common":MochiKit.Format.EXPORT};
+MochiKit.Format.__new__=function(){
+var base=this.NAME+".";
+var k,v,o;
+for(k in this.LOCALE){
+o=this.LOCALE[k];
+if(typeof (o)=="object"){
+o.repr=function(){
+return this.NAME;
+};
+o.NAME=base+"LOCALE."+k;
+}
+}
+for(k in this){
+o=this[k];
+if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
+try{
+o.NAME=base+k;
+}
+catch(e){
+}
+}
+}
+};
+MochiKit.Format.__new__();
+if(typeof (MochiKit.Base)!="undefined"){
+MochiKit.Base._exportSymbols(this,MochiKit.Format);
+}else{
+(function(_289,_28a){
+if((typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined")||(MochiKit.__export__===false)){
+var all=_28a.EXPORT_TAGS[":all"];
+for(var i=0;i<all.length;i++){
+_289[all[i]]=_28a[all[i]];
+}
+}
+})(this,MochiKit.Format);
+}
+MochiKit.Base._deps("Async",["Base"]);
+MochiKit.Async.NAME="MochiKit.Async";
+MochiKit.Async.VERSION="1.4.2";
+MochiKit.Async.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Async.toString=function(){
+return this.__repr__();
+};
+MochiKit.Async.Deferred=function(_28d){
+this.chain=[];
+this.id=this._nextId();
+this.fired=-1;
+this.paused=0;
+this.results=[null,null];
+this.canceller=_28d;
+this.silentlyCancelled=false;
+this.chained=false;
+};
+MochiKit.Async.Deferred.prototype={repr:function(){
+var _28e;
+if(this.fired==-1){
+_28e="unfired";
+}else{
+if(this.fired===0){
+_28e="success";
+}else{
+_28e="error";
+}
+}
+return "Deferred("+this.id+", "+_28e+")";
+},toString:MochiKit.Base.forwardCall("repr"),_nextId:MochiKit.Base.counter(),cancel:function(){
+var self=MochiKit.Async;
+if(this.fired==-1){
+if(this.canceller){
+this.canceller(this);
+}else{
+this.silentlyCancelled=true;
+}
+if(this.fired==-1){
+this.errback(new self.CancelledError(this));
+}
+}else{
+if((this.fired===0)&&(this.results[0] instanceof self.Deferred)){
+this.results[0].cancel();
+}
+}
+},_resback:function(res){
+this.fired=((res instanceof Error)?1:0);
+this.results[this.fired]=res;
+this._fire();
+},_check:function(){
+if(this.fired!=-1){
+if(!this.silentlyCancelled){
+throw new MochiKit.Async.AlreadyCalledError(this);
+}
+this.silentlyCancelled=false;
+return;
+}
+},callback:function(res){
+this._check();
+if(res instanceof MochiKit.Async.Deferred){
+throw new Error("Deferred instances can only be chained if they are the result of a callback");
+}
+this._resback(res);
+},errback:function(res){
+this._check();
+var self=MochiKit.Async;
+if(res instanceof self.Deferred){
+throw new Error("Deferred instances can only be chained if they are the result of a callback");
+}
+if(!(res instanceof Error)){
+res=new self.GenericError(res);
+}
+this._resback(res);
+},addBoth:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(fn,fn);
+},addCallback:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(fn,null);
+},addErrback:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(null,fn);
+},addCallbacks:function(cb,eb){
+if(this.chained){
+throw new Error("Chained Deferreds can not be re-used");
+}
+this.chain.push([cb,eb]);
+if(this.fired>=0){
+this._fire();
+}
+return this;
+},_fire:function(){
+var _299=this.chain;
+var _29a=this.fired;
+var res=this.results[_29a];
+var self=this;
+var cb=null;
+while(_299.length>0&&this.paused===0){
+var pair=_299.shift();
+var f=pair[_29a];
+if(f===null){
+continue;
+}
+try{
+res=f(res);
+_29a=((res instanceof Error)?1:0);
+if(res instanceof MochiKit.Async.Deferred){
+cb=function(res){
+self._resback(res);
+self.paused--;
+if((self.paused===0)&&(self.fired>=0)){
+self._fire();
+}
+};
+this.paused++;
+}
+}
+catch(err){
+_29a=1;
+if(!(err instanceof Error)){
+err=new MochiKit.Async.GenericError(err);
+}
+res=err;
+}
+}
+this.fired=_29a;
+this.results[_29a]=res;
+if(cb&&this.paused){
+res.addBoth(cb);
+res.chained=true;
+}
+}};
+MochiKit.Base.update(MochiKit.Async,{evalJSONRequest:function(req){
+return MochiKit.Base.evalJSON(req.responseText);
+},succeed:function(_2a2){
+var d=new MochiKit.Async.Deferred();
+d.callback.apply(d,arguments);
+return d;
+},fail:function(_2a4){
+var d=new MochiKit.Async.Deferred();
+d.errback.apply(d,arguments);
+return d;
+},getXMLHttpRequest:function(){
+var self=arguments.callee;
+if(!self.XMLHttpRequest){
+var _2a7=[function(){
+return new XMLHttpRequest();
+},function(){
+return new ActiveXObject("Msxml2.XMLHTTP");
+},function(){
+return new ActiveXObject("Microsoft.XMLHTTP");
+},function(){
+return new ActiveXObject("Msxml2.XMLHTTP.4.0");
+},function(){
+throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
+}];
+for(var i=0;i<_2a7.length;i++){
+var func=_2a7[i];
+try{
+self.XMLHttpRequest=func;
+return func();
+}
+catch(e){
+}
+}
+}
+return self.XMLHttpRequest();
+},_xhr_onreadystatechange:function(d){
+var m=MochiKit.Base;
+if(this.readyState==4){
+try{
+this.onreadystatechange=null;
+}
+catch(e){
+try{
+this.onreadystatechange=m.noop;
+}
+catch(e){
+}
+}
+var _2ac=null;
+try{
+_2ac=this.status;
+if(!_2ac&&m.isNotEmpty(this.responseText)){
+_2ac=304;
+}
+}
+catch(e){
+}
+if(_2ac==200||_2ac==201||_2ac==204||_2ac==304||_2ac==1223){
+d.callback(this);
+}else{
+var err=new MochiKit.Async.XMLHttpRequestError(this,"Request failed");
+if(err.number){
+d.errback(err);
+}else{
+d.errback(err);
+}
+}
+}
+},_xhr_canceller:function(req){
+try{
+req.onreadystatechange=null;
+}
+catch(e){
+try{
+req.onreadystatechange=MochiKit.Base.noop;
+}
+catch(e){
+}
+}
+req.abort();
+},sendXMLHttpRequest:function(req,_2b0){
+if(typeof (_2b0)=="undefined"||_2b0===null){
+_2b0="";
+}
+var m=MochiKit.Base;
+var self=MochiKit.Async;
+var d=new self.Deferred(m.partial(self._xhr_canceller,req));
+try{
+req.onreadystatechange=m.bind(self._xhr_onreadystatechange,req,d);
+req.send(_2b0);
+}
+catch(e){
+try{
+req.onreadystatechange=null;
+}
+catch(ignore){
+}
+d.errback(e);
+}
+return d;
+},doXHR:function(url,opts){
+var self=MochiKit.Async;
+return self.callLater(0,self._doXHR,url,opts);
+},_doXHR:function(url,opts){
+var m=MochiKit.Base;
+opts=m.update({method:"GET",sendContent:""},opts);
+var self=MochiKit.Async;
+var req=self.getXMLHttpRequest();
+if(opts.queryString){
+var qs=m.queryString(opts.queryString);
+if(qs){
+url+="?"+qs;
+}
+}
+if("username" in opts){
+req.open(opts.method,url,true,opts.username,opts.password);
+}else{
+req.open(opts.method,url,true);
+}
+if(req.overrideMimeType&&opts.mimeType){
+req.overrideMimeType(opts.mimeType);
+}
+req.setRequestHeader("X-Requested-With","XMLHttpRequest");
+if(opts.headers){
+var _2bd=opts.headers;
+if(!m.isArrayLike(_2bd)){
+_2bd=m.items(_2bd);
+}
+for(var i=0;i<_2bd.length;i++){
+var _2bf=_2bd[i];
+var name=_2bf[0];
+var _2c1=_2bf[1];
+req.setRequestHeader(name,_2c1);
+}
+}
+return self.sendXMLHttpRequest(req,opts.sendContent);
+},_buildURL:function(url){
+if(arguments.length>1){
+var m=MochiKit.Base;
+var qs=m.queryString.apply(null,m.extend(null,arguments,1));
+if(qs){
+return url+"?"+qs;
+}
+}
+return url;
+},doSimpleXMLHttpRequest:function(url){
+var self=MochiKit.Async;
+url=self._buildURL.apply(self,arguments);
+return self.doXHR(url);
+},loadJSONDoc:function(url){
+var self=MochiKit.Async;
+url=self._buildURL.apply(self,arguments);
+var d=self.doXHR(url,{"mimeType":"text/plain","headers":[["Accept","application/json"]]});
+d=d.addCallback(self.evalJSONRequest);
+return d;
+},wait:function(_2ca,_2cb){
+var d=new MochiKit.Async.Deferred();
+var m=MochiKit.Base;
+if(typeof (_2cb)!="undefined"){
+d.addCallback(function(){
+return _2cb;
+});
+}
+var _2ce=setTimeout(m.bind("callback",d),Math.floor(_2ca*1000));
+d.canceller=function(){
+try{
+clearTimeout(_2ce);
+}
+catch(e){
+}
+};
+return d;
+},callLater:function(_2cf,func){
+var m=MochiKit.Base;
+var _2d2=m.partial.apply(m,m.extend(null,arguments,1));
+return MochiKit.Async.wait(_2cf).addCallback(function(res){
+return _2d2();
+});
+}});
+MochiKit.Async.DeferredLock=function(){
+this.waiting=[];
+this.locked=false;
+this.id=this._nextId();
+};
+MochiKit.Async.DeferredLock.prototype={__class__:MochiKit.Async.DeferredLock,acquire:function(){
+var d=new MochiKit.Async.Deferred();
+if(this.locked){
+this.waiting.push(d);
+}else{
+this.locked=true;
+d.callback(this);
+}
+return d;
+},release:function(){
+if(!this.locked){
+throw TypeError("Tried to release an unlocked DeferredLock");
+}
+this.locked=false;
+if(this.waiting.length>0){
+this.locked=true;
+this.waiting.shift().callback(this);
+}
+},_nextId:MochiKit.Base.counter(),repr:function(){
+var _2d5;
+if(this.locked){
+_2d5="locked, "+this.waiting.length+" waiting";
+}else{
+_2d5="unlocked";
+}
+return "DeferredLock("+this.id+", "+_2d5+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+MochiKit.Async.DeferredList=function(list,_2d7,_2d8,_2d9,_2da){
+MochiKit.Async.Deferred.apply(this,[_2da]);
+this.list=list;
+var _2db=[];
+this.resultList=_2db;
+this.finishedCount=0;
+this.fireOnOneCallback=_2d7;
+this.fireOnOneErrback=_2d8;
+this.consumeErrors=_2d9;
+var cb=MochiKit.Base.bind(this._cbDeferred,this);
+for(var i=0;i<list.length;i++){
+var d=list[i];
+_2db.push(undefined);
+d.addCallback(cb,i,true);
+d.addErrback(cb,i,false);
+}
+if(list.length===0&&!_2d7){
+this.callback(this.resultList);
+}
+};
+MochiKit.Async.DeferredList.prototype=new MochiKit.Async.Deferred();
+MochiKit.Async.DeferredList.prototype._cbDeferred=function(_2df,_2e0,_2e1){
+this.resultList[_2df]=[_2e0,_2e1];
+this.finishedCount+=1;
+if(this.fired==-1){
+if(_2e0&&this.fireOnOneCallback){
+this.callback([_2df,_2e1]);
+}else{
+if(!_2e0&&this.fireOnOneErrback){
+this.errback(_2e1);
+}else{
+if(this.finishedCount==this.list.length){
+this.callback(this.resultList);
+}
+}
+}
+}
+if(!_2e0&&this.consumeErrors){
+_2e1=null;
+}
+return _2e1;
+};
+MochiKit.Async.gatherResults=function(_2e2){
+var d=new MochiKit.Async.DeferredList(_2e2,false,true,false);
+d.addCallback(function(_2e4){
+var ret=[];
+for(var i=0;i<_2e4.length;i++){
+ret.push(_2e4[i][1]);
+}
+return ret;
+});
+return d;
+};
+MochiKit.Async.maybeDeferred=function(func){
+var self=MochiKit.Async;
+var _2e9;
+try{
+var r=func.apply(null,MochiKit.Base.extend([],arguments,1));
+if(r instanceof self.Deferred){
+_2e9=r;
+}else{
+if(r instanceof Error){
+_2e9=self.fail(r);
+}else{
+_2e9=self.succeed(r);
+}
+}
+}
+catch(e){
+_2e9=self.fail(e);
+}
+return _2e9;
+};
+MochiKit.Async.EXPORT=["AlreadyCalledError","CancelledError","BrowserComplianceError","GenericError","XMLHttpRequestError","Deferred","succeed","fail","getXMLHttpRequest","doSimpleXMLHttpRequest","loadJSONDoc","wait","callLater","sendXMLHttpRequest","DeferredLock","DeferredList","gatherResults","maybeDeferred","doXHR"];
+MochiKit.Async.EXPORT_OK=["evalJSONRequest"];
+MochiKit.Async.__new__=function(){
+var m=MochiKit.Base;
+var ne=m.partial(m._newNamedError,this);
+ne("AlreadyCalledError",function(_2ed){
+this.deferred=_2ed;
+});
+ne("CancelledError",function(_2ee){
+this.deferred=_2ee;
+});
+ne("BrowserComplianceError",function(msg){
+this.message=msg;
+});
+ne("GenericError",function(msg){
+this.message=msg;
+});
+ne("XMLHttpRequestError",function(req,msg){
+this.req=req;
+this.message=msg;
+try{
+this.number=req.status;
+}
+catch(e){
+}
+});
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Async.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Async);
+MochiKit.Base._deps("DOM",["Base"]);
+MochiKit.DOM.NAME="MochiKit.DOM";
+MochiKit.DOM.VERSION="1.4.2";
+MochiKit.DOM.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.DOM.toString=function(){
+return this.__repr__();
+};
+MochiKit.DOM.EXPORT=["removeEmptyTextNodes","formContents","currentWindow","currentDocument","withWindow","withDocument","registerDOMConverter","coerceToDOM","createDOM","createDOMFunc","isChildNode","getNodeAttribute","removeNodeAttribute","setNodeAttribute","updateNodeAttributes","appendChildNodes","insertSiblingNodesAfter","insertSiblingNodesBefore","replaceChildNodes","removeElement","swapDOM","BUTTON","TT","PRE","H1","H2","H3","H4","H5","H6","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","DL","DT","DD","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG","getElement","$","getElementsByTagAndClassName","addToCallStack","addLoadEvent","focusOnLoad","setElementClass","toggleElementClass","addElementClass","removeElementClass","swapElementClass","hasElementClass","computedStyle","escapeHTML","toHTML","emitHTML","scrapeText","getFirstParentByTagAndClassName","getFirstElementBy
TagAndClassName"];
+MochiKit.DOM.EXPORT_OK=["domConverters"];
+MochiKit.DOM.DEPRECATED=[["computedStyle","MochiKit.Style.getStyle","1.4"],["elementDimensions","MochiKit.Style.getElementDimensions","1.4"],["elementPosition","MochiKit.Style.getElementPosition","1.4"],["getViewportDimensions","MochiKit.Style.getViewportDimensions","1.4"],["hideElement","MochiKit.Style.hideElement","1.4"],["makeClipping","MochiKit.Style.makeClipping","1.4.1"],["makePositioned","MochiKit.Style.makePositioned","1.4.1"],["setElementDimensions","MochiKit.Style.setElementDimensions","1.4"],["setElementPosition","MochiKit.Style.setElementPosition","1.4"],["setDisplayForElement","MochiKit.Style.setDisplayForElement","1.4"],["setOpacity","MochiKit.Style.setOpacity","1.4"],["showElement","MochiKit.Style.showElement","1.4"],["undoClipping","MochiKit.Style.undoClipping","1.4.1"],["undoPositioned","MochiKit.Style.undoPositioned","1.4.1"],["Coordinates","MochiKit.Style.Coordinates","1.4"],["Dimensions","MochiKit.Style.Dimensions","1.4"]];
+MochiKit.Base.update(MochiKit.DOM,{currentWindow:function(){
+return MochiKit.DOM._window;
+},currentDocument:function(){
+return MochiKit.DOM._document;
+},withWindow:function(win,func){
+var self=MochiKit.DOM;
+var _2f6=self._document;
+var _2f7=self._window;
+var rval;
+try{
+self._window=win;
+self._document=win.document;
+rval=func();
+}
+catch(e){
+self._window=_2f7;
+self._document=_2f6;
+throw e;
+}
+self._window=_2f7;
+self._document=_2f6;
+return rval;
+},formContents:function(elem){
+var _2fa=[];
+var _2fb=[];
+var m=MochiKit.Base;
+var self=MochiKit.DOM;
+if(typeof (elem)=="undefined"||elem===null){
+elem=self._document.body;
+}else{
+elem=self.getElement(elem);
+}
+m.nodeWalk(elem,function(elem){
+var name=elem.name;
+if(m.isNotEmpty(name)){
+var _300=elem.tagName.toUpperCase();
+if(_300==="INPUT"&&(elem.type=="radio"||elem.type=="checkbox")&&!elem.checked){
+return null;
+}
+if(_300==="SELECT"){
+if(elem.type=="select-one"){
+if(elem.selectedIndex>=0){
+var opt=elem.options[elem.selectedIndex];
+var v=opt.value;
+if(!v){
+var h=opt.outerHTML;
+if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
+v=opt.text;
+}
+}
+_2fa.push(name);
+_2fb.push(v);
+return null;
+}
+_2fa.push(name);
+_2fb.push("");
+return null;
+}else{
+var opts=elem.options;
+if(!opts.length){
+_2fa.push(name);
+_2fb.push("");
+return null;
+}
+for(var i=0;i<opts.length;i++){
+var opt=opts[i];
+if(!opt.selected){
+continue;
+}
+var v=opt.value;
+if(!v){
+var h=opt.outerHTML;
+if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
+v=opt.text;
+}
+}
+_2fa.push(name);
+_2fb.push(v);
+}
+return null;
+}
+}
+if(_300==="FORM"||_300==="P"||_300==="SPAN"||_300==="DIV"){
+return elem.childNodes;
+}
+_2fa.push(name);
+_2fb.push(elem.value||"");
+return null;
+}
+return elem.childNodes;
+});
+return [_2fa,_2fb];
+},withDocument:function(doc,func){
+var self=MochiKit.DOM;
+var _309=self._document;
+var rval;
+try{
+self._document=doc;
+rval=func();
+}
+catch(e){
+self._document=_309;
+throw e;
+}
+self._document=_309;
+return rval;
+},registerDOMConverter:function(name,_30c,wrap,_30e){
+MochiKit.DOM.domConverters.register(name,_30c,wrap,_30e);
+},coerceToDOM:function(node,ctx){
+var m=MochiKit.Base;
+var im=MochiKit.Iter;
+var self=MochiKit.DOM;
+if(im){
+var iter=im.iter;
+var _315=im.repeat;
+}
+var map=m.map;
+var _317=self.domConverters;
+var _318=arguments.callee;
+var _319=m.NotFound;
+while(true){
+if(typeof (node)=="undefined"||node===null){
+return null;
+}
+if(typeof (node)=="function"&&typeof (node.length)=="number"&&!(node instanceof Function)){
+node=im?im.list(node):m.extend(null,node);
+}
+if(typeof (node.nodeType)!="undefined"&&node.nodeType>0){
+return node;
+}
+if(typeof (node)=="number"||typeof (node)=="boolean"){
+node=node.toString();
+}
+if(typeof (node)=="string"){
+return self._document.createTextNode(node);
+}
+if(typeof (node.__dom__)=="function"){
+node=node.__dom__(ctx);
+continue;
+}
+if(typeof (node.dom)=="function"){
+node=node.dom(ctx);
+continue;
+}
+if(typeof (node)=="function"){
+node=node.apply(ctx,[ctx]);
+continue;
+}
+if(im){
+var _31a=null;
+try{
+_31a=iter(node);
+}
+catch(e){
+}
+if(_31a){
+return map(_318,_31a,_315(ctx));
+}
+}else{
+if(m.isArrayLike(node)){
+var func=function(n){
+return _318(n,ctx);
+};
+return map(func,node);
+}
+}
+try{
+node=_317.match(node,ctx);
+continue;
+}
+catch(e){
+if(e!=_319){
+throw e;
+}
+}
+return self._document.createTextNode(node.toString());
+}
+return undefined;
+},isChildNode:function(node,_31e){
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+node=self.getElement(node);
+}
+if(typeof (_31e)=="string"){
+_31e=self.getElement(_31e);
+}
+if(typeof (node)=="undefined"||node===null){
+return false;
+}
+while(node!=null&&node!==self._document){
+if(node===_31e){
+return true;
+}
+node=node.parentNode;
+}
+return false;
+},setNodeAttribute:function(node,attr,_322){
+var o={};
+o[attr]=_322;
+try{
+return MochiKit.DOM.updateNodeAttributes(node,o);
+}
+catch(e){
+}
+return null;
+},getNodeAttribute:function(node,attr){
+var self=MochiKit.DOM;
+var _327=self.attributeArray.renames[attr];
+var _328=self.attributeArray.ignoreAttr[attr];
+node=self.getElement(node);
+try{
+if(_327){
+return node[_327];
+}
+var _329=node.getAttribute(attr);
+if(_329!=_328){
+return _329;
+}
+}
+catch(e){
+}
+return null;
+},removeNodeAttribute:function(node,attr){
+var self=MochiKit.DOM;
+var _32d=self.attributeArray.renames[attr];
+node=self.getElement(node);
+try{
+if(_32d){
+return node[_32d];
+}
+return node.removeAttribute(attr);
+}
+catch(e){
+}
+return null;
+},updateNodeAttributes:function(node,_32f){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+if(_32f){
+var _332=MochiKit.Base.updatetree;
+if(self.attributeArray.compliant){
+for(var k in _32f){
+var v=_32f[k];
+if(typeof (v)=="object"&&typeof (elem[k])=="object"){
+if(k=="style"&&MochiKit.Style){
+MochiKit.Style.setStyle(elem,v);
+}else{
+_332(elem[k],v);
+}
+}else{
+if(k.substring(0,2)=="on"){
+if(typeof (v)=="string"){
+v=new Function(v);
+}
+elem[k]=v;
+}else{
+elem.setAttribute(k,v);
+}
+}
+if(typeof (elem[k])=="string"&&elem[k]!=v){
+elem[k]=v;
+}
+}
+}else{
+var _335=self.attributeArray.renames;
+for(var k in _32f){
+v=_32f[k];
+var _336=_335[k];
+if(k=="style"&&typeof (v)=="string"){
+elem.style.cssText=v;
+}else{
+if(typeof (_336)=="string"){
+elem[_336]=v;
+}else{
+if(typeof (elem[k])=="object"&&typeof (v)=="object"){
+if(k=="style"&&MochiKit.Style){
+MochiKit.Style.setStyle(elem,v);
+}else{
+_332(elem[k],v);
+}
+}else{
+if(k.substring(0,2)=="on"){
+if(typeof (v)=="string"){
+v=new Function(v);
+}
+elem[k]=v;
+}else{
+elem.setAttribute(k,v);
+}
+}
+}
+}
+if(typeof (elem[k])=="string"&&elem[k]!=v){
+elem[k]=v;
+}
+}
+}
+}
+return elem;
+},appendChildNodes:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _33a=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+var _33b=MochiKit.Base.concat;
+while(_33a.length){
+var n=_33a.shift();
+if(typeof (n)=="undefined"||n===null){
+}else{
+if(typeof (n.nodeType)=="number"){
+elem.appendChild(n);
+}else{
+_33a=_33b(n,_33a);
+}
+}
+}
+return elem;
+},insertSiblingNodesBefore:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _340=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+var _341=elem.parentNode;
+var _342=MochiKit.Base.concat;
+while(_340.length){
+var n=_340.shift();
+if(typeof (n)=="undefined"||n===null){
+}else{
+if(typeof (n.nodeType)=="number"){
+_341.insertBefore(n,elem);
+}else{
+_340=_342(n,_340);
+}
+}
+}
+return _341;
+},insertSiblingNodesAfter:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _347=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+if(elem.nextSibling){
+return self.insertSiblingNodesBefore(elem.nextSibling,_347);
+}else{
+return self.appendChildNodes(elem.parentNode,_347);
+}
+},replaceChildNodes:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+arguments[0]=elem;
+}
+var _34b;
+while((_34b=elem.firstChild)){
+elem.removeChild(_34b);
+}
+if(arguments.length<2){
+return elem;
+}else{
+return self.appendChildNodes.apply(this,arguments);
+}
+},createDOM:function(name,_34d){
+var elem;
+var self=MochiKit.DOM;
+var m=MochiKit.Base;
+if(typeof (_34d)=="string"||typeof (_34d)=="number"){
+var args=m.extend([name,null],arguments,1);
+return arguments.callee.apply(this,args);
+}
+if(typeof (name)=="string"){
+var _352=self._xhtml;
+if(_34d&&!self.attributeArray.compliant){
+var _353="";
+if("name" in _34d){
+_353+=" name=\""+self.escapeHTML(_34d.name)+"\"";
+}
+if(name=="input"&&"type" in _34d){
+_353+=" type=\""+self.escapeHTML(_34d.type)+"\"";
+}
+if(_353){
+name="<"+name+_353+">";
+_352=false;
+}
+}
+var d=self._document;
+if(_352&&d===document){
+elem=d.createElementNS("http://www.w3.org/1999/xhtml",name);
+}else{
+elem=d.createElement(name);
+}
+}else{
+elem=name;
+}
+if(_34d){
+self.updateNodeAttributes(elem,_34d);
+}
+if(arguments.length<=2){
+return elem;
+}else{
+var args=m.extend([elem],arguments,2);
+return self.appendChildNodes.apply(this,args);
+}
+},createDOMFunc:function(){
+var m=MochiKit.Base;
+return m.partial.apply(this,m.extend([MochiKit.DOM.createDOM],arguments));
+},removeElement:function(elem){
+var self=MochiKit.DOM;
+var e=self.coerceToDOM(self.getElement(elem));
+e.parentNode.removeChild(e);
+return e;
+},swapDOM:function(dest,src){
+var self=MochiKit.DOM;
+dest=self.getElement(dest);
+var _35c=dest.parentNode;
+if(src){
+src=self.coerceToDOM(self.getElement(src),_35c);
+_35c.replaceChild(src,dest);
+}else{
+_35c.removeChild(dest);
+}
+return src;
+},getElement:function(id){
+var self=MochiKit.DOM;
+if(arguments.length==1){
+return ((typeof (id)=="string")?self._document.getElementById(id):id);
+}else{
+return MochiKit.Base.map(self.getElement,arguments);
+}
+},getElementsByTagAndClassName:function(_35f,_360,_361){
+var self=MochiKit.DOM;
+if(typeof (_35f)=="undefined"||_35f===null){
+_35f="*";
+}
+if(typeof (_361)=="undefined"||_361===null){
+_361=self._document;
+}
+_361=self.getElement(_361);
+if(_361==null){
+return [];
+}
+var _363=(_361.getElementsByTagName(_35f)||self._document.all);
+if(typeof (_360)=="undefined"||_360===null){
+return MochiKit.Base.extend(null,_363);
+}
+var _364=[];
+for(var i=0;i<_363.length;i++){
+var _366=_363[i];
+var cls=_366.className;
+if(typeof (cls)!="string"){
+cls=_366.getAttribute("class");
+}
+if(typeof (cls)=="string"){
+var _368=cls.split(" ");
+for(var j=0;j<_368.length;j++){
+if(_368[j]==_360){
+_364.push(_366);
+break;
+}
+}
+}
+}
+return _364;
+},_newCallStack:function(path,once){
+var rval=function(){
+var _36d=arguments.callee.callStack;
+for(var i=0;i<_36d.length;i++){
+if(_36d[i].apply(this,arguments)===false){
+break;
+}
+}
+if(once){
+try{
+this[path]=null;
+}
+catch(e){
+}
+}
+};
+rval.callStack=[];
+return rval;
+},addToCallStack:function(_36f,path,func,once){
+var self=MochiKit.DOM;
+var _374=_36f[path];
+var _375=_374;
+if(!(typeof (_374)=="function"&&typeof (_374.callStack)=="object"&&_374.callStack!==null)){
+_375=self._newCallStack(path,once);
+if(typeof (_374)=="function"){
+_375.callStack.push(_374);
+}
+_36f[path]=_375;
+}
+_375.callStack.push(func);
+},addLoadEvent:function(func){
+var self=MochiKit.DOM;
+self.addToCallStack(self._window,"onload",func,true);
+},focusOnLoad:function(_378){
+var self=MochiKit.DOM;
+self.addLoadEvent(function(){
+_378=self.getElement(_378);
+if(_378){
+_378.focus();
+}
+});
+},setElementClass:function(_37a,_37b){
+var self=MochiKit.DOM;
+var obj=self.getElement(_37a);
+if(self.attributeArray.compliant){
+obj.setAttribute("class",_37b);
+}else{
+obj.setAttribute("className",_37b);
+}
+},toggleElementClass:function(_37e){
+var self=MochiKit.DOM;
+for(var i=1;i<arguments.length;i++){
+var obj=self.getElement(arguments[i]);
+if(!self.addElementClass(obj,_37e)){
+self.removeElementClass(obj,_37e);
+}
+}
+},addElementClass:function(_382,_383){
+var self=MochiKit.DOM;
+var obj=self.getElement(_382);
+var cls=obj.className;
+if(typeof (cls)!="string"){
+cls=obj.getAttribute("class");
+}
+if(typeof (cls)!="string"||cls.length===0){
+self.setElementClass(obj,_383);
+return true;
+}
+if(cls==_383){
+return false;
+}
+var _387=cls.split(" ");
+for(var i=0;i<_387.length;i++){
+if(_387[i]==_383){
+return false;
+}
+}
+self.setElementClass(obj,cls+" "+_383);
+return true;
+},removeElementClass:function(_389,_38a){
+var self=MochiKit.DOM;
+var obj=self.getElement(_389);
+var cls=obj.className;
+if(typeof (cls)!="string"){
+cls=obj.getAttribute("class");
+}
+if(typeof (cls)!="string"||cls.length===0){
+return false;
+}
+if(cls==_38a){
+self.setElementClass(obj,"");
+return true;
+}
+var _38e=cls.split(" ");
+for(var i=0;i<_38e.length;i++){
+if(_38e[i]==_38a){
+_38e.splice(i,1);
+self.setElementClass(obj,_38e.join(" "));
+return true;
+}
+}
+return false;
+},swapElementClass:function(_390,_391,_392){
+var obj=MochiKit.DOM.getElement(_390);
+var res=MochiKit.DOM.removeElementClass(obj,_391);
+if(res){
+MochiKit.DOM.addElementClass(obj,_392);
+}
+return res;
+},hasElementClass:function(_395,_396){
+var obj=MochiKit.DOM.getElement(_395);
+if(obj==null){
+return false;
+}
+var cls=obj.className;
+if(typeof (cls)!="string"){
+cls=obj.getAttribute("class");
+}
+if(typeof (cls)!="string"){
+return false;
+}
+var _399=cls.split(" ");
+for(var i=1;i<arguments.length;i++){
+var good=false;
+for(var j=0;j<_399.length;j++){
+if(_399[j]==arguments[i]){
+good=true;
+break;
+}
+}
+if(!good){
+return false;
+}
+}
+return true;
+},escapeHTML:function(s){
+return s.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">");
+},toHTML:function(dom){
+return MochiKit.DOM.emitHTML(dom).join("");
+},emitHTML:function(dom,lst){
+if(typeof (lst)=="undefined"||lst===null){
+lst=[];
+}
+var _3a1=[dom];
+var self=MochiKit.DOM;
+var _3a3=self.escapeHTML;
+var _3a4=self.attributeArray;
+while(_3a1.length){
+dom=_3a1.pop();
+if(typeof (dom)=="string"){
+lst.push(dom);
+}else{
+if(dom.nodeType==1){
+lst.push("<"+dom.tagName.toLowerCase());
+var _3a5=[];
+var _3a6=_3a4(dom);
+for(var i=0;i<_3a6.length;i++){
+var a=_3a6[i];
+_3a5.push([" ",a.name,"=\"",_3a3(a.value),"\""]);
+}
+_3a5.sort();
+for(i=0;i<_3a5.length;i++){
+var _3a9=_3a5[i];
+for(var j=0;j<_3a9.length;j++){
+lst.push(_3a9[j]);
+}
+}
+if(dom.hasChildNodes()){
+lst.push(">");
+_3a1.push("</"+dom.tagName.toLowerCase()+">");
+var _3ab=dom.childNodes;
+for(i=_3ab.length-1;i>=0;i--){
+_3a1.push(_3ab[i]);
+}
+}else{
+lst.push("/>");
+}
+}else{
+if(dom.nodeType==3){
+lst.push(_3a3(dom.nodeValue));
+}
+}
+}
+}
+return lst;
+},scrapeText:function(node,_3ad){
+var rval=[];
+(function(node){
+var cn=node.childNodes;
+if(cn){
+for(var i=0;i<cn.length;i++){
+arguments.callee.call(this,cn[i]);
+}
+}
+var _3b2=node.nodeValue;
+if(typeof (_3b2)=="string"){
+rval.push(_3b2);
+}
+})(MochiKit.DOM.getElement(node));
+if(_3ad){
+return rval;
+}else{
+return rval.join("");
+}
+},removeEmptyTextNodes:function(_3b3){
+_3b3=MochiKit.DOM.getElement(_3b3);
+for(var i=0;i<_3b3.childNodes.length;i++){
+var node=_3b3.childNodes[i];
+if(node.nodeType==3&&!/\S/.test(node.nodeValue)){
+node.parentNode.removeChild(node);
+}
+}
+},getFirstElementByTagAndClassName:function(_3b6,_3b7,_3b8){
+var self=MochiKit.DOM;
+if(typeof (_3b6)=="undefined"||_3b6===null){
+_3b6="*";
+}
+if(typeof (_3b8)=="undefined"||_3b8===null){
+_3b8=self._document;
+}
+_3b8=self.getElement(_3b8);
+if(_3b8==null){
+return null;
+}
+var _3ba=(_3b8.getElementsByTagName(_3b6)||self._document.all);
+if(_3ba.length<=0){
+return null;
+}else{
+if(typeof (_3b7)=="undefined"||_3b7===null){
+return _3ba[0];
+}
+}
+for(var i=0;i<_3ba.length;i++){
+var _3bc=_3ba[i];
+var cls=_3bc.className;
+if(typeof (cls)!="string"){
+cls=_3bc.getAttribute("class");
+}
+if(typeof (cls)=="string"){
+var _3be=cls.split(" ");
+for(var j=0;j<_3be.length;j++){
+if(_3be[j]==_3b7){
+return _3bc;
+}
+}
+}
+}
+return null;
+},getFirstParentByTagAndClassName:function(elem,_3c1,_3c2){
+var self=MochiKit.DOM;
+elem=self.getElement(elem);
+if(typeof (_3c1)=="undefined"||_3c1===null){
+_3c1="*";
+}else{
+_3c1=_3c1.toUpperCase();
+}
+if(typeof (_3c2)=="undefined"||_3c2===null){
+_3c2=null;
+}
+if(elem){
+elem=elem.parentNode;
+}
+while(elem&&elem.tagName){
+var _3c4=elem.tagName.toUpperCase();
+if((_3c1==="*"||_3c1==_3c4)&&(_3c2===null||self.hasElementClass(elem,_3c2))){
+return elem;
+}
+elem=elem.parentNode;
+}
+return null;
+},__new__:function(win){
+var m=MochiKit.Base;
+if(typeof (document)!="undefined"){
+this._document=document;
+var _3c7="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+this._xhtml=(document.documentElement&&document.createElementNS&&document.documentElement.namespaceURI===_3c7);
+}else{
+if(MochiKit.MockDOM){
+this._document=MochiKit.MockDOM.document;
+}
+}
+this._window=win;
+this.domConverters=new m.AdapterRegistry();
+var _3c8=this._document.createElement("span");
+var _3c9;
+if(_3c8&&_3c8.attributes&&_3c8.attributes.length>0){
+var _3ca=m.filter;
+_3c9=function(node){
+return _3ca(_3c9.ignoreAttrFilter,node.attributes);
+};
+_3c9.ignoreAttr={};
+var _3cc=_3c8.attributes;
+var _3cd=_3c9.ignoreAttr;
+for(var i=0;i<_3cc.length;i++){
+var a=_3cc[i];
+_3cd[a.name]=a.value;
+}
+_3c9.ignoreAttrFilter=function(a){
+return (_3c9.ignoreAttr[a.name]!=a.value);
+};
+_3c9.compliant=false;
+_3c9.renames={"class":"className","checked":"defaultChecked","usemap":"useMap","for":"htmlFor","readonly":"readOnly","colspan":"colSpan","bgcolor":"bgColor","cellspacing":"cellSpacing","cellpadding":"cellPadding"};
+}else{
+_3c9=function(node){
+return node.attributes;
+};
+_3c9.compliant=true;
+_3c9.ignoreAttr={};
+_3c9.renames={};
+}
+this.attributeArray=_3c9;
+var _3d2=function(_3d3,arr){
+var _3d5=arr[0];
+var _3d6=arr[1];
+var _3d7=_3d6.split(".")[1];
+var str="";
+str+="if (!MochiKit."+_3d7+") { throw new Error(\"";
+str+="This function has been deprecated and depends on MochiKit.";
+str+=_3d7+".\");}";
+str+="return "+_3d6+".apply(this, arguments);";
+MochiKit[_3d3][_3d5]=new Function(str);
+};
+for(var i=0;i<MochiKit.DOM.DEPRECATED.length;i++){
+_3d2("DOM",MochiKit.DOM.DEPRECATED[i]);
+}
+var _3d9=this.createDOMFunc;
+this.UL=_3d9("ul");
+this.OL=_3d9("ol");
+this.LI=_3d9("li");
+this.DL=_3d9("dl");
+this.DT=_3d9("dt");
+this.DD=_3d9("dd");
+this.TD=_3d9("td");
+this.TR=_3d9("tr");
+this.TBODY=_3d9("tbody");
+this.THEAD=_3d9("thead");
+this.TFOOT=_3d9("tfoot");
+this.TABLE=_3d9("table");
+this.TH=_3d9("th");
+this.INPUT=_3d9("input");
+this.SPAN=_3d9("span");
+this.A=_3d9("a");
+this.DIV=_3d9("div");
+this.IMG=_3d9("img");
+this.BUTTON=_3d9("button");
+this.TT=_3d9("tt");
+this.PRE=_3d9("pre");
+this.H1=_3d9("h1");
+this.H2=_3d9("h2");
+this.H3=_3d9("h3");
+this.H4=_3d9("h4");
+this.H5=_3d9("h5");
+this.H6=_3d9("h6");
+this.BR=_3d9("br");
+this.HR=_3d9("hr");
+this.LABEL=_3d9("label");
+this.TEXTAREA=_3d9("textarea");
+this.FORM=_3d9("form");
+this.P=_3d9("p");
+this.SELECT=_3d9("select");
+this.OPTION=_3d9("option");
+this.OPTGROUP=_3d9("optgroup");
+this.LEGEND=_3d9("legend");
+this.FIELDSET=_3d9("fieldset");
+this.STRONG=_3d9("strong");
+this.CANVAS=_3d9("canvas");
+this.$=this.getElement;
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+}});
+MochiKit.DOM.__new__(((typeof (window)=="undefined")?this:window));
+if(MochiKit.__export__){
+withWindow=MochiKit.DOM.withWindow;
+withDocument=MochiKit.DOM.withDocument;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.DOM);
+MochiKit.Base._deps("Selector",["Base","DOM","Iter"]);
+MochiKit.Selector.NAME="MochiKit.Selector";
+MochiKit.Selector.VERSION="1.4.2";
+MochiKit.Selector.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Selector.toString=function(){
+return this.__repr__();
+};
+MochiKit.Selector.EXPORT=["Selector","findChildElements","findDocElements","$$"];
+MochiKit.Selector.EXPORT_OK=[];
+MochiKit.Selector.Selector=function(_3da){
+this.params={classNames:[],pseudoClassNames:[]};
+this.expression=_3da.toString().replace(/(^\s+|\s+$)/g,"");
+this.parseExpression();
+this.compileMatcher();
+};
+MochiKit.Selector.Selector.prototype={__class__:MochiKit.Selector.Selector,parseExpression:function(){
+function abort(_3db){
+throw "Parse error in selector: "+_3db;
+}
+if(this.expression==""){
+abort("empty expression");
+}
+var repr=MochiKit.Base.repr;
+var _3dd=this.params;
+var expr=this.expression;
+var _3df,_3e0,_3e1,rest;
+while(_3df=expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)){
+_3dd.attributes=_3dd.attributes||[];
+_3dd.attributes.push({name:_3df[2],operator:_3df[3],value:_3df[4]||_3df[5]||""});
+expr=_3df[1];
+}
+if(expr=="*"){
+return this.params.wildcard=true;
+}
+while(_3df=expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)){
+_3e0=_3df[1];
+_3e1=_3df[2];
+rest=_3df[3];
+switch(_3e0){
+case "#":
+_3dd.id=_3e1;
+break;
+case ".":
+_3dd.classNames.push(_3e1);
+break;
+case ":":
+_3dd.pseudoClassNames.push(_3e1);
+break;
+case "":
+case undefined:
+_3dd.tagName=_3e1.toUpperCase();
+break;
+default:
+abort(repr(expr));
+}
+expr=rest;
+}
+if(expr.length>0){
+abort(repr(expr));
+}
+},buildMatchExpression:function(){
+var repr=MochiKit.Base.repr;
+var _3e4=this.params;
+var _3e5=[];
+var _3e6,i;
+function childElements(_3e8){
+return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, "+_3e8+".childNodes)";
+}
+if(_3e4.wildcard){
+_3e5.push("true");
+}
+if(_3e6=_3e4.id){
+_3e5.push("element.id == "+repr(_3e6));
+}
+if(_3e6=_3e4.tagName){
+_3e5.push("element.tagName.toUpperCase() == "+repr(_3e6));
+}
+if((_3e6=_3e4.classNames).length>0){
+for(i=0;i<_3e6.length;i++){
+_3e5.push("MochiKit.DOM.hasElementClass(element, "+repr(_3e6[i])+")");
+}
+}
+if((_3e6=_3e4.pseudoClassNames).length>0){
+for(i=0;i<_3e6.length;i++){
+var _3e9=_3e6[i].match(/^([^(]+)(?:\((.*)\))?$/);
+var _3ea=_3e9[1];
+var _3eb=_3e9[2];
+switch(_3ea){
+case "root":
+_3e5.push("element.nodeType == 9 || element === element.ownerDocument.documentElement");
+break;
+case "nth-child":
+case "nth-last-child":
+case "nth-of-type":
+case "nth-last-of-type":
+_3e9=_3eb.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/);
+if(!_3e9){
+throw "Invalid argument to pseudo element nth-child: "+_3eb;
+}
+var a,b;
+if(_3e9[0]=="odd"){
+a=2;
+b=1;
+}else{
+if(_3e9[0]=="even"){
+a=2;
+b=0;
+}else{
+a=_3e9[2]&&parseInt(_3e9)||null;
+b=parseInt(_3e9[3]);
+}
+}
+_3e5.push("this.nthChild(element,"+a+","+b+","+!!_3ea.match("^nth-last")+","+!!_3ea.match("of-type$")+")");
+break;
+case "first-child":
+_3e5.push("this.nthChild(element, null, 1)");
+break;
+case "last-child":
+_3e5.push("this.nthChild(element, null, 1, true)");
+break;
+case "first-of-type":
+_3e5.push("this.nthChild(element, null, 1, false, true)");
+break;
+case "last-of-type":
+_3e5.push("this.nthChild(element, null, 1, true, true)");
+break;
+case "only-child":
+_3e5.push(childElements("element.parentNode")+".length == 1");
+break;
+case "only-of-type":
+_3e5.push("MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, "+childElements("element.parentNode")+").length == 1");
+break;
+case "empty":
+_3e5.push("element.childNodes.length == 0");
+break;
+case "enabled":
+_3e5.push("(this.isUIElement(element) && element.disabled === false)");
+break;
+case "disabled":
+_3e5.push("(this.isUIElement(element) && element.disabled === true)");
+break;
+case "checked":
+_3e5.push("(this.isUIElement(element) && element.checked === true)");
+break;
+case "not":
+var _3ee=new MochiKit.Selector.Selector(_3eb);
+_3e5.push("!( "+_3ee.buildMatchExpression()+")");
+break;
+}
+}
+}
+if(_3e6=_3e4.attributes){
+MochiKit.Base.map(function(_3ef){
+var _3f0="MochiKit.DOM.getNodeAttribute(element, "+repr(_3ef.name)+")";
+var _3f1=function(_3f2){
+return _3f0+".split("+repr(_3f2)+")";
+};
+_3e5.push(_3f0+" != null");
+switch(_3ef.operator){
+case "=":
+_3e5.push(_3f0+" == "+repr(_3ef.value));
+break;
+case "~=":
+_3e5.push("MochiKit.Base.findValue("+_3f1(" ")+", "+repr(_3ef.value)+") > -1");
+break;
+case "^=":
+_3e5.push(_3f0+".substring(0, "+_3ef.value.length+") == "+repr(_3ef.value));
+break;
+case "$=":
+_3e5.push(_3f0+".substring("+_3f0+".length - "+_3ef.value.length+") == "+repr(_3ef.value));
+break;
+case "*=":
+_3e5.push(_3f0+".match("+repr(_3ef.value)+")");
+break;
+case "|=":
+_3e5.push(_3f1("-")+"[0].toUpperCase() == "+repr(_3ef.value.toUpperCase()));
+break;
+case "!=":
+_3e5.push(_3f0+" != "+repr(_3ef.value));
+break;
+case "":
+case undefined:
+break;
+default:
+throw "Unknown operator "+_3ef.operator+" in selector";
+}
+},_3e6);
+}
+return _3e5.join(" && ");
+},compileMatcher:function(){
+var code="return (!element.tagName) ? false : "+this.buildMatchExpression()+";";
+this.match=new Function("element",code);
+},nthChild:function(_3f4,a,b,_3f7,_3f8){
+var _3f9=MochiKit.Base.filter(function(node){
+return node.nodeType==1;
+},_3f4.parentNode.childNodes);
+if(_3f8){
+_3f9=MochiKit.Base.filter(function(node){
+return node.tagName==_3f4.tagName;
+},_3f9);
+}
+if(_3f7){
+_3f9=MochiKit.Iter.reversed(_3f9);
+}
+if(a){
+var _3fc=MochiKit.Base.findIdentical(_3f9,_3f4);
+return ((_3fc+1-b)/a)%1==0;
+}else{
+return b==MochiKit.Base.findIdentical(_3f9,_3f4)+1;
+}
+},isUIElement:function(_3fd){
+return MochiKit.Base.findValue(["input","button","select","option","textarea","object"],_3fd.tagName.toLowerCase())>-1;
+},findElements:function(_3fe,axis){
+var _400;
+if(axis==undefined){
+axis="";
+}
+function inScope(_401,_402){
+if(axis==""){
+return MochiKit.DOM.isChildNode(_401,_402);
+}else{
+if(axis==">"){
+return _401.parentNode===_402;
+}else{
+if(axis=="+"){
+return _401===nextSiblingElement(_402);
+}else{
+if(axis=="~"){
+var _403=_402;
+while(_403=nextSiblingElement(_403)){
+if(_401===_403){
+return true;
+}
+}
+return false;
+}else{
+throw "Invalid axis: "+axis;
+}
+}
+}
+}
+}
+if(_400=MochiKit.DOM.getElement(this.params.id)){
+if(this.match(_400)){
+if(!_3fe||inScope(_400,_3fe)){
+return [_400];
+}
+}
+}
+function nextSiblingElement(node){
+node=node.nextSibling;
+while(node&&node.nodeType!=1){
+node=node.nextSibling;
+}
+return node;
+}
+if(axis==""){
+_3fe=(_3fe||MochiKit.DOM.currentDocument()).getElementsByTagName(this.params.tagName||"*");
+}else{
+if(axis==">"){
+if(!_3fe){
+throw "> combinator not allowed without preceeding expression";
+}
+_3fe=MochiKit.Base.filter(function(node){
+return node.nodeType==1;
+},_3fe.childNodes);
+}else{
+if(axis=="+"){
+if(!_3fe){
+throw "+ combinator not allowed without preceeding expression";
+}
+_3fe=nextSiblingElement(_3fe)&&[nextSiblingElement(_3fe)];
+}else{
+if(axis=="~"){
+if(!_3fe){
+throw "~ combinator not allowed without preceeding expression";
+}
+var _406=[];
+while(nextSiblingElement(_3fe)){
+_3fe=nextSiblingElement(_3fe);
+_406.push(_3fe);
+}
+_3fe=_406;
+}
+}
+}
+}
+if(!_3fe){
+return [];
+}
+var _407=MochiKit.Base.filter(MochiKit.Base.bind(function(_408){
+return this.match(_408);
+},this),_3fe);
+return _407;
+},repr:function(){
+return "Selector("+this.expression+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+MochiKit.Base.update(MochiKit.Selector,{findChildElements:function(_409,_40a){
+var uniq=function(arr){
+var res=[];
+for(var i=0;i<arr.length;i++){
+if(MochiKit.Base.findIdentical(res,arr[i])<0){
+res.push(arr[i]);
+}
+}
+return res;
+};
+return MochiKit.Base.flattenArray(MochiKit.Base.map(function(_40f){
+var _410="";
+var _411=function(_412,expr){
+if(match=expr.match(/^[>+~]$/)){
+_410=match[0];
+return _412;
+}else{
+var _414=new MochiKit.Selector.Selector(expr);
+var _415=MochiKit.Iter.reduce(function(_416,_417){
+return MochiKit.Base.extend(_416,_414.findElements(_417||_409,_410));
+},_412,[]);
+_410="";
+return _415;
+}
+};
+var _418=_40f.replace(/(^\s+|\s+$)/g,"").split(/\s+/);
+return uniq(MochiKit.Iter.reduce(_411,_418,[null]));
+},_40a));
+},findDocElements:function(){
+return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(),arguments);
+},__new__:function(){
+var m=MochiKit.Base;
+this.$$=this.findDocElements;
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+}});
+MochiKit.Selector.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Selector);
+MochiKit.Base._deps("Style",["Base","DOM"]);
+MochiKit.Style.NAME="MochiKit.Style";
+MochiKit.Style.VERSION="1.4.2";
+MochiKit.Style.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Style.toString=function(){
+return this.__repr__();
+};
+MochiKit.Style.EXPORT_OK=[];
+MochiKit.Style.EXPORT=["setStyle","setOpacity","getStyle","getElementDimensions","elementDimensions","setElementDimensions","getElementPosition","elementPosition","setElementPosition","makePositioned","undoPositioned","makeClipping","undoClipping","setDisplayForElement","hideElement","showElement","getViewportDimensions","getViewportPosition","Dimensions","Coordinates"];
+MochiKit.Style.Dimensions=function(w,h){
+this.w=w;
+this.h=h;
+};
+MochiKit.Style.Dimensions.prototype.__repr__=function(){
+var repr=MochiKit.Base.repr;
+return "{w: "+repr(this.w)+", h: "+repr(this.h)+"}";
+};
+MochiKit.Style.Dimensions.prototype.toString=function(){
+return this.__repr__();
+};
+MochiKit.Style.Coordinates=function(x,y){
+this.x=x;
+this.y=y;
+};
+MochiKit.Style.Coordinates.prototype.__repr__=function(){
+var repr=MochiKit.Base.repr;
+return "{x: "+repr(this.x)+", y: "+repr(this.y)+"}";
+};
+MochiKit.Style.Coordinates.prototype.toString=function(){
+return this.__repr__();
+};
+MochiKit.Base.update(MochiKit.Style,{getStyle:function(elem,_421){
+var dom=MochiKit.DOM;
+var d=dom._document;
+elem=dom.getElement(elem);
+_421=MochiKit.Base.camelize(_421);
+if(!elem||elem==d){
+return undefined;
+}
+if(_421=="opacity"&&typeof (elem.filters)!="undefined"){
+var _424=(MochiKit.Style.getStyle(elem,"filter")||"").match(/alpha\(opacity=(.*)\)/);
+if(_424&&_424[1]){
+return parseFloat(_424[1])/100;
+}
+return 1;
+}
+if(_421=="float"||_421=="cssFloat"||_421=="styleFloat"){
+if(elem.style["float"]){
+return elem.style["float"];
+}else{
+if(elem.style.cssFloat){
+return elem.style.cssFloat;
+}else{
+if(elem.style.styleFloat){
+return elem.style.styleFloat;
+}else{
+return "none";
+}
+}
+}
+}
+var _425=elem.style?elem.style[_421]:null;
+if(!_425){
+if(d.defaultView&&d.defaultView.getComputedStyle){
+var css=d.defaultView.getComputedStyle(elem,null);
+_421=_421.replace(/([A-Z])/g,"-$1").toLowerCase();
+_425=css?css.getPropertyValue(_421):null;
+}else{
+if(elem.currentStyle){
+_425=elem.currentStyle[_421];
+if(/^\d/.test(_425)&&!/px$/.test(_425)&&_421!="fontWeight"){
+var left=elem.style.left;
+var _428=elem.runtimeStyle.left;
+elem.runtimeStyle.left=elem.currentStyle.left;
+elem.style.left=_425||0;
+_425=elem.style.pixelLeft+"px";
+elem.style.left=left;
+elem.runtimeStyle.left=_428;
+}
+}
+}
+}
+if(_421=="opacity"){
+_425=parseFloat(_425);
+}
+if(/Opera/.test(navigator.userAgent)&&(MochiKit.Base.findValue(["left","top","right","bottom"],_421)!=-1)){
+if(MochiKit.Style.getStyle(elem,"position")=="static"){
+_425="auto";
+}
+}
+return _425=="auto"?null:_425;
+},setStyle:function(elem,_42a){
+elem=MochiKit.DOM.getElement(elem);
+for(var name in _42a){
+switch(name){
+case "opacity":
+MochiKit.Style.setOpacity(elem,_42a[name]);
+break;
+case "float":
+case "cssFloat":
+case "styleFloat":
+if(typeof (elem.style["float"])!="undefined"){
+elem.style["float"]=_42a[name];
+}else{
+if(typeof (elem.style.cssFloat)!="undefined"){
+elem.style.cssFloat=_42a[name];
+}else{
+elem.style.styleFloat=_42a[name];
+}
+}
+break;
+default:
+elem.style[MochiKit.Base.camelize(name)]=_42a[name];
+}
+}
+},setOpacity:function(elem,o){
+elem=MochiKit.DOM.getElement(elem);
+var self=MochiKit.Style;
+if(o==1){
+var _42f=/Gecko/.test(navigator.userAgent)&&!(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
+elem.style["opacity"]=_42f?0.999999:1;
+if(/MSIE/.test(navigator.userAgent)){
+elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"");
+}
+}else{
+if(o<0.00001){
+o=0;
+}
+elem.style["opacity"]=o;
+if(/MSIE/.test(navigator.userAgent)){
+elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"")+"alpha(opacity="+o*100+")";
+}
+}
+},getElementPosition:function(elem,_431){
+var self=MochiKit.Style;
+var dom=MochiKit.DOM;
+elem=dom.getElement(elem);
+if(!elem||(!(elem.x&&elem.y)&&(!elem.parentNode===null||self.getStyle(elem,"display")=="none"))){
+return undefined;
+}
+var c=new self.Coordinates(0,0);
+var box=null;
+var _436=null;
+var d=MochiKit.DOM._document;
+var de=d.documentElement;
+var b=d.body;
+if(!elem.parentNode&&elem.x&&elem.y){
+c.x+=elem.x||0;
+c.y+=elem.y||0;
+}else{
+if(elem.getBoundingClientRect){
+box=elem.getBoundingClientRect();
+c.x+=box.left+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
+c.y+=box.top+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
+}else{
+if(elem.offsetParent){
+c.x+=elem.offsetLeft;
+c.y+=elem.offsetTop;
+_436=elem.offsetParent;
+if(_436!=elem){
+while(_436){
+c.x+=parseInt(_436.style.borderLeftWidth)||0;
+c.y+=parseInt(_436.style.borderTopWidth)||0;
+c.x+=_436.offsetLeft;
+c.y+=_436.offsetTop;
+_436=_436.offsetParent;
+}
+}
+var ua=navigator.userAgent.toLowerCase();
+if((typeof (opera)!="undefined"&&parseFloat(opera.version())<9)||(ua.indexOf("AppleWebKit")!=-1&&self.getStyle(elem,"position")=="absolute")){
+c.x-=b.offsetLeft;
+c.y-=b.offsetTop;
+}
+if(elem.parentNode){
+_436=elem.parentNode;
+}else{
+_436=null;
+}
+while(_436){
+var _43b=_436.tagName.toUpperCase();
+if(_43b==="BODY"||_43b==="HTML"){
+break;
+}
+var disp=self.getStyle(_436,"display");
+if(disp.search(/^inline|table-row.*$/i)){
+c.x-=_436.scrollLeft;
+c.y-=_436.scrollTop;
+}
+if(_436.parentNode){
+_436=_436.parentNode;
+}else{
+_436=null;
+}
+}
+}
+}
+}
+if(typeof (_431)!="undefined"){
+_431=arguments.callee(_431);
+if(_431){
+c.x-=(_431.x||0);
+c.y-=(_431.y||0);
+}
+}
+return c;
+},setElementPosition:function(elem,_43e,_43f){
+elem=MochiKit.DOM.getElement(elem);
+if(typeof (_43f)=="undefined"){
+_43f="px";
+}
+var _440={};
+var _441=MochiKit.Base.isUndefinedOrNull;
+if(!_441(_43e.x)){
+_440["left"]=_43e.x+_43f;
+}
+if(!_441(_43e.y)){
+_440["top"]=_43e.y+_43f;
+}
+MochiKit.DOM.updateNodeAttributes(elem,{"style":_440});
+},makePositioned:function(_442){
+_442=MochiKit.DOM.getElement(_442);
+var pos=MochiKit.Style.getStyle(_442,"position");
+if(pos=="static"||!pos){
+_442.style.position="relative";
+if(/Opera/.test(navigator.userAgent)){
+_442.style.top=0;
+_442.style.left=0;
+}
+}
+},undoPositioned:function(_444){
+_444=MochiKit.DOM.getElement(_444);
+if(_444.style.position=="relative"){
+_444.style.position=_444.style.top=_444.style.left=_444.style.bottom=_444.style.right="";
+}
+},makeClipping:function(_445){
+_445=MochiKit.DOM.getElement(_445);
+var s=_445.style;
+var _447={"overflow":s.overflow,"overflow-x":s.overflowX,"overflow-y":s.overflowY};
+if((MochiKit.Style.getStyle(_445,"overflow")||"visible")!="hidden"){
+_445.style.overflow="hidden";
+_445.style.overflowX="hidden";
+_445.style.overflowY="hidden";
+}
+return _447;
+},undoClipping:function(_448,_449){
+_448=MochiKit.DOM.getElement(_448);
+if(typeof (_449)=="string"){
+_448.style.overflow=_449;
+}else{
+if(_449!=null){
+_448.style.overflow=_449["overflow"];
+_448.style.overflowX=_449["overflow-x"];
+_448.style.overflowY=_449["overflow-y"];
+}
+}
+},getElementDimensions:function(elem,_44b){
+var self=MochiKit.Style;
+var dom=MochiKit.DOM;
+if(typeof (elem.w)=="number"||typeof (elem.h)=="number"){
+return new self.Dimensions(elem.w||0,elem.h||0);
+}
+elem=dom.getElement(elem);
+if(!elem){
+return undefined;
+}
+var disp=self.getStyle(elem,"display");
+if(disp=="none"||disp==""||typeof (disp)=="undefined"){
+var s=elem.style;
+var _450=s.visibility;
+var _451=s.position;
+var _452=s.display;
+s.visibility="hidden";
+s.position="absolute";
+s.display=self._getDefaultDisplay(elem);
+var _453=elem.offsetWidth;
+var _454=elem.offsetHeight;
+s.display=_452;
+s.position=_451;
+s.visibility=_450;
+}else{
+_453=elem.offsetWidth||0;
+_454=elem.offsetHeight||0;
+}
+if(_44b){
+var _455="colSpan" in elem&&"rowSpan" in elem;
+var _456=(_455&&elem.parentNode&&self.getStyle(elem.parentNode,"borderCollapse")=="collapse");
+if(_456){
+if(/MSIE/.test(navigator.userAgent)){
+var _457=elem.previousSibling?0.5:1;
+var _458=elem.nextSibling?0.5:1;
+}else{
+var _457=0.5;
+var _458=0.5;
+}
+}else{
+var _457=1;
+var _458=1;
+}
+_453-=Math.round((parseFloat(self.getStyle(elem,"paddingLeft"))||0)+(parseFloat(self.getStyle(elem,"paddingRight"))||0)+_457*(parseFloat(self.getStyle(elem,"borderLeftWidth"))||0)+_458*(parseFloat(self.getStyle(elem,"borderRightWidth"))||0));
+if(_455){
+if(/Gecko|Opera/.test(navigator.userAgent)&&!/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent)){
+var _459=0;
+}else{
+if(/MSIE/.test(navigator.userAgent)){
+var _459=1;
+}else{
+var _459=_456?0.5:1;
+}
+}
+}else{
+var _459=1;
+}
+_454-=Math.round((parseFloat(self.getStyle(elem,"paddingTop"))||0)+(parseFloat(self.getStyle(elem,"paddingBottom"))||0)+_459*((parseFloat(self.getStyle(elem,"borderTopWidth"))||0)+(parseFloat(self.getStyle(elem,"borderBottomWidth"))||0)));
+}
+return new self.Dimensions(_453,_454);
+},setElementDimensions:function(elem,_45b,_45c){
+elem=MochiKit.DOM.getElement(elem);
+if(typeof (_45c)=="undefined"){
+_45c="px";
+}
+var _45d={};
+var _45e=MochiKit.Base.isUndefinedOrNull;
+if(!_45e(_45b.w)){
+_45d["width"]=_45b.w+_45c;
+}
+if(!_45e(_45b.h)){
+_45d["height"]=_45b.h+_45c;
+}
+MochiKit.DOM.updateNodeAttributes(elem,{"style":_45d});
+},_getDefaultDisplay:function(elem){
+var self=MochiKit.Style;
+var dom=MochiKit.DOM;
+elem=dom.getElement(elem);
+if(!elem){
+return undefined;
+}
+var _462=elem.tagName.toUpperCase();
+return self._defaultDisplay[_462]||"block";
+},setDisplayForElement:function(_463,_464){
+var _465=MochiKit.Base.extend(null,arguments,1);
+var _466=MochiKit.DOM.getElement;
+for(var i=0;i<_465.length;i++){
+_464=_466(_465[i]);
+if(_464){
+_464.style.display=_463;
+}
+}
+},getViewportDimensions:function(){
+var d=new MochiKit.Style.Dimensions();
+var w=MochiKit.DOM._window;
+var b=MochiKit.DOM._document.body;
+if(w.innerWidth){
+d.w=w.innerWidth;
+d.h=w.innerHeight;
+}else{
+if(b&&b.parentElement&&b.parentElement.clientWidth){
+d.w=b.parentElement.clientWidth;
+d.h=b.parentElement.clientHeight;
+}else{
+if(b&&b.clientWidth){
+d.w=b.clientWidth;
+d.h=b.clientHeight;
+}
+}
+}
+return d;
+},getViewportPosition:function(){
+var c=new MochiKit.Style.Coordinates(0,0);
+var d=MochiKit.DOM._document;
+var de=d.documentElement;
+var db=d.body;
+if(de&&(de.scrollTop||de.scrollLeft)){
+c.x=de.scrollLeft;
+c.y=de.scrollTop;
+}else{
+if(db){
+c.x=db.scrollLeft;
+c.y=db.scrollTop;
+}
+}
+return c;
+},__new__:function(){
+var m=MochiKit.Base;
+var _470=["A","ABBR","ACRONYM","B","BASEFONT","BDO","BIG","BR","CITE","CODE","DFN","EM","FONT","I","IMG","KBD","LABEL","Q","S","SAMP","SMALL","SPAN","STRIKE","STRONG","SUB","SUP","TEXTAREA","TT","U","VAR"];
+this._defaultDisplay={"TABLE":"table","THEAD":"table-header-group","TBODY":"table-row-group","TFOOT":"table-footer-group","COLGROUP":"table-column-group","COL":"table-column","TR":"table-row","TD":"table-cell","TH":"table-cell","CAPTION":"table-caption","LI":"list-item","INPUT":"inline-block","SELECT":"inline-block"};
+if(/MSIE/.test(navigator.userAgent)){
+for(var k in this._defaultDisplay){
+var v=this._defaultDisplay[k];
+if(v.indexOf("table")==0){
+this._defaultDisplay[k]="block";
+}
+}
+}
+for(var i=0;i<_470.length;i++){
+this._defaultDisplay[_470[i]]="inline";
+}
+this.elementPosition=this.getElementPosition;
+this.elementDimensions=this.getElementDimensions;
+this.hideElement=m.partial(this.setDisplayForElement,"none");
+this.showElement=m.partial(this.setDisplayForElement,"block");
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+}});
+MochiKit.Style.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Style);
+MochiKit.Base._deps("LoggingPane",["Base","Logging"]);
+MochiKit.LoggingPane.NAME="MochiKit.LoggingPane";
+MochiKit.LoggingPane.VERSION="1.4.2";
+MochiKit.LoggingPane.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.LoggingPane.toString=function(){
+return this.__repr__();
+};
+MochiKit.LoggingPane.createLoggingPane=function(_474){
+var m=MochiKit.LoggingPane;
+_474=!(!_474);
+if(m._loggingPane&&m._loggingPane.inline!=_474){
+m._loggingPane.closePane();
+m._loggingPane=null;
+}
+if(!m._loggingPane||m._loggingPane.closed){
+m._loggingPane=new m.LoggingPane(_474,MochiKit.Logging.logger);
+}
+return m._loggingPane;
+};
+MochiKit.LoggingPane.LoggingPane=function(_476,_477){
+if(typeof (_477)=="undefined"||_477===null){
+_477=MochiKit.Logging.logger;
+}
+this.logger=_477;
+var _478=MochiKit.Base.update;
+var _479=MochiKit.Base.updatetree;
+var bind=MochiKit.Base.bind;
+var _47b=MochiKit.Base.clone;
+var win=window;
+var uid="_MochiKit_LoggingPane";
+if(typeof (MochiKit.DOM)!="undefined"){
+win=MochiKit.DOM.currentWindow();
+}
+if(!_476){
+var url=win.location.href.split("?")[0].replace(/[#:\/.><&%-]/g,"_");
+var name=uid+"_"+url;
+var nwin=win.open("",name,"dependent,resizable,height=200");
+if(!nwin){
+alert("Not able to open debugging window due to pop-up blocking.");
+return undefined;
+}
+nwin.document.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" "+"\"http://www.w3.org/TR/html4/loose.dtd\">"+"<html><head><title>[MochiKit.LoggingPane]</title></head>"+"<body></body></html>");
+nwin.document.close();
+nwin.document.title+=" "+win.document.title;
+win=nwin;
+}
+var doc=win.document;
+this.doc=doc;
+var _482=doc.getElementById(uid);
+var _483=!!_482;
+if(_482&&typeof (_482.loggingPane)!="undefined"){
+_482.loggingPane.logger=this.logger;
+_482.loggingPane.buildAndApplyFilter();
+return _482.loggingPane;
+}
+if(_483){
+var _484;
+while((_484=_482.firstChild)){
+_482.removeChild(_484);
+}
+}else{
+_482=doc.createElement("div");
+_482.id=uid;
+}
+_482.loggingPane=this;
+var _485=doc.createElement("input");
+var _486=doc.createElement("input");
+var _487=doc.createElement("button");
+var _488=doc.createElement("button");
+var _489=doc.createElement("button");
+var _48a=doc.createElement("button");
+var _48b=doc.createElement("div");
+var _48c=doc.createElement("div");
+var _48d=uid+"_Listener";
+this.colorTable=_47b(this.colorTable);
+var _48e=[];
+var _48f=null;
+var _490=function(msg){
+var _492=msg.level;
+if(typeof (_492)=="number"){
+_492=MochiKit.Logging.LogLevel[_492];
+}
+return _492;
+};
+var _493=function(msg){
+return msg.info.join(" ");
+};
+var _495=bind(function(msg){
+var _497=_490(msg);
+var text=_493(msg);
+var c=this.colorTable[_497];
+var p=doc.createElement("span");
+p.className="MochiKit-LogMessage MochiKit-LogLevel-"+_497;
+p.style.cssText="margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: "+c;
+p.appendChild(doc.createTextNode(_497+": "+text));
+_48c.appendChild(p);
+_48c.appendChild(doc.createElement("br"));
+if(_48b.offsetHeight>_48b.scrollHeight){
+_48b.scrollTop=0;
+}else{
+_48b.scrollTop=_48b.scrollHeight;
+}
+},this);
+var _49b=function(msg){
+_48e[_48e.length]=msg;
+_495(msg);
+};
+var _49d=function(){
+var _49e,_49f;
+try{
+_49e=new RegExp(_485.value);
+_49f=new RegExp(_486.value);
+}
+catch(e){
+logDebug("Error in filter regex: "+e.message);
+return null;
+}
+return function(msg){
+return (_49e.test(_490(msg))&&_49f.test(_493(msg)));
+};
+};
+var _4a1=function(){
+while(_48c.firstChild){
+_48c.removeChild(_48c.firstChild);
+}
+};
+var _4a2=function(){
+_48e=[];
+_4a1();
+};
+var _4a3=bind(function(){
+if(this.closed){
+return;
+}
+this.closed=true;
+if(MochiKit.LoggingPane._loggingPane==this){
+MochiKit.LoggingPane._loggingPane=null;
+}
+this.logger.removeListener(_48d);
+try{
+try{
+_482.loggingPane=null;
+}
+catch(e){
+logFatal("Bookmarklet was closed incorrectly.");
+}
+if(_476){
+_482.parentNode.removeChild(_482);
+}else{
+this.win.close();
+}
+}
+catch(e){
+}
+},this);
+var _4a4=function(){
+_4a1();
+for(var i=0;i<_48e.length;i++){
+var msg=_48e[i];
+if(_48f===null||_48f(msg)){
+_495(msg);
+}
+}
+};
+this.buildAndApplyFilter=function(){
+_48f=_49d();
+_4a4();
+this.logger.removeListener(_48d);
+this.logger.addListener(_48d,_48f,_49b);
+};
+var _4a7=bind(function(){
+_48e=this.logger.getMessages();
+_4a4();
+},this);
+var _4a8=bind(function(_4a9){
+_4a9=_4a9||window.event;
+key=_4a9.which||_4a9.keyCode;
+if(key==13){
+this.buildAndApplyFilter();
+}
+},this);
+var _4aa="display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: "+this.logFont;
+if(_476){
+_4aa+="; height: 10em; border-top: 2px solid black";
+}else{
+_4aa+="; height: 100%;";
+}
+_482.style.cssText=_4aa;
+if(!_483){
+doc.body.appendChild(_482);
+}
+_4aa={"cssText":"width: 33%; display: inline; font: "+this.logFont};
+_479(_485,{"value":"FATAL|ERROR|WARNING|INFO|DEBUG","onkeypress":_4a8,"style":_4aa});
+_482.appendChild(_485);
+_479(_486,{"value":".*","onkeypress":_4a8,"style":_4aa});
+_482.appendChild(_486);
+_4aa="width: 8%; display:inline; font: "+this.logFont;
+_487.appendChild(doc.createTextNode("Filter"));
+_487.onclick=bind("buildAndApplyFilter",this);
+_487.style.cssText=_4aa;
+_482.appendChild(_487);
+_488.appendChild(doc.createTextNode("Load"));
+_488.onclick=_4a7;
+_488.style.cssText=_4aa;
+_482.appendChild(_488);
+_489.appendChild(doc.createTextNode("Clear"));
+_489.onclick=_4a2;
+_489.style.cssText=_4aa;
+_482.appendChild(_489);
+_48a.appendChild(doc.createTextNode("Close"));
+_48a.onclick=_4a3;
+_48a.style.cssText=_4aa;
+_482.appendChild(_48a);
+_48b.style.cssText="overflow: auto; width: 100%";
+_48c.style.cssText="width: 100%; height: "+(_476?"8em":"100%");
+_48b.appendChild(_48c);
+_482.appendChild(_48b);
+this.buildAndApplyFilter();
+_4a7();
+if(_476){
+this.win=undefined;
+}else{
+this.win=win;
+}
+this.inline=_476;
+this.closePane=_4a3;
+this.closed=false;
+return this;
+};
+MochiKit.LoggingPane.LoggingPane.prototype={"logFont":"8pt Verdana,sans-serif","colorTable":{"ERROR":"red","FATAL":"darkred","WARNING":"blue","INFO":"black","DEBUG":"green"}};
+MochiKit.LoggingPane.EXPORT_OK=["LoggingPane"];
+MochiKit.LoggingPane.EXPORT=["createLoggingPane"];
+MochiKit.LoggingPane.__new__=function(){
+this.EXPORT_TAGS={":common":this.EXPORT,":all":MochiKit.Base.concat(this.EXPORT,this.EXPORT_OK)};
+MochiKit.Base.nameFunctions(this);
+MochiKit.LoggingPane._loggingPane=null;
+};
+MochiKit.LoggingPane.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.LoggingPane);
+MochiKit.Base._deps("Color",["Base","DOM","Style"]);
+MochiKit.Color.NAME="MochiKit.Color";
+MochiKit.Color.VERSION="1.4.2";
+MochiKit.Color.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Color.toString=function(){
+return this.__repr__();
+};
+MochiKit.Color.Color=function(red,_4ac,blue,_4ae){
+if(typeof (_4ae)=="undefined"||_4ae===null){
+_4ae=1;
+}
+this.rgb={r:red,g:_4ac,b:blue,a:_4ae};
+};
+MochiKit.Color.Color.prototype={__class__:MochiKit.Color.Color,colorWithAlpha:function(_4af){
+var rgb=this.rgb;
+var m=MochiKit.Color;
+return m.Color.fromRGB(rgb.r,rgb.g,rgb.b,_4af);
+},colorWithHue:function(hue){
+var hsl=this.asHSL();
+hsl.h=hue;
+var m=MochiKit.Color;
+return m.Color.fromHSL(hsl);
+},colorWithSaturation:function(_4b5){
+var hsl=this.asHSL();
+hsl.s=_4b5;
+var m=MochiKit.Color;
+return m.Color.fromHSL(hsl);
+},colorWithLightness:function(_4b8){
+var hsl=this.asHSL();
+hsl.l=_4b8;
+var m=MochiKit.Color;
+return m.Color.fromHSL(hsl);
+},darkerColorWithLevel:function(_4bb){
+var hsl=this.asHSL();
+hsl.l=Math.max(hsl.l-_4bb,0);
+var m=MochiKit.Color;
+return m.Color.fromHSL(hsl);
+},lighterColorWithLevel:function(_4be){
+var hsl=this.asHSL();
+hsl.l=Math.min(hsl.l+_4be,1);
+var m=MochiKit.Color;
+return m.Color.fromHSL(hsl);
+},blendedColor:function(_4c1,_4c2){
+if(typeof (_4c2)=="undefined"||_4c2===null){
+_4c2=0.5;
+}
+var sf=1-_4c2;
+var s=this.rgb;
+var d=_4c1.rgb;
+var df=_4c2;
+return MochiKit.Color.Color.fromRGB((s.r*sf)+(d.r*df),(s.g*sf)+(d.g*df),(s.b*sf)+(d.b*df),(s.a*sf)+(d.a*df));
+},compareRGB:function(_4c7){
+var a=this.asRGB();
+var b=_4c7.asRGB();
+return MochiKit.Base.compare([a.r,a.g,a.b,a.a],[b.r,b.g,b.b,b.a]);
+},isLight:function(){
+return this.asHSL().b>0.5;
+},isDark:function(){
+return (!this.isLight());
+},toHSLString:function(){
+var c=this.asHSL();
+var ccc=MochiKit.Color.clampColorComponent;
+var rval=this._hslString;
+if(!rval){
+var mid=(ccc(c.h,360).toFixed(0)+","+ccc(c.s,100).toPrecision(4)+"%"+","+ccc(c.l,100).toPrecision(4)+"%");
+var a=c.a;
+if(a>=1){
+a=1;
+rval="hsl("+mid+")";
+}else{
+if(a<=0){
+a=0;
+}
+rval="hsla("+mid+","+a+")";
+}
+this._hslString=rval;
+}
+return rval;
+},toRGBString:function(){
+var c=this.rgb;
+var ccc=MochiKit.Color.clampColorComponent;
+var rval=this._rgbString;
+if(!rval){
+var mid=(ccc(c.r,255).toFixed(0)+","+ccc(c.g,255).toFixed(0)+","+ccc(c.b,255).toFixed(0));
+if(c.a!=1){
+rval="rgba("+mid+","+c.a+")";
+}else{
+rval="rgb("+mid+")";
+}
+this._rgbString=rval;
+}
+return rval;
+},asRGB:function(){
+return MochiKit.Base.clone(this.rgb);
+},toHexString:function(){
+var m=MochiKit.Color;
+var c=this.rgb;
+var ccc=MochiKit.Color.clampColorComponent;
+var rval=this._hexString;
+if(!rval){
+rval=("#"+m.toColorPart(ccc(c.r,255))+m.toColorPart(ccc(c.g,255))+m.toColorPart(ccc(c.b,255)));
+this._hexString=rval;
+}
+return rval;
+},asHSV:function(){
+var hsv=this.hsv;
+var c=this.rgb;
+if(typeof (hsv)=="undefined"||hsv===null){
+hsv=MochiKit.Color.rgbToHSV(this.rgb);
+this.hsv=hsv;
+}
+return MochiKit.Base.clone(hsv);
+},asHSL:function(){
+var hsl=this.hsl;
+var c=this.rgb;
+if(typeof (hsl)=="undefined"||hsl===null){
+hsl=MochiKit.Color.rgbToHSL(this.rgb);
+this.hsl=hsl;
+}
+return MochiKit.Base.clone(hsl);
+},toString:function(){
+return this.toRGBString();
+},repr:function(){
+var c=this.rgb;
+var col=[c.r,c.g,c.b,c.a];
+return this.__class__.NAME+"("+col.join(", ")+")";
+}};
+MochiKit.Base.update(MochiKit.Color.Color,{fromRGB:function(red,_4de,blue,_4e0){
+var _4e1=MochiKit.Color.Color;
+if(arguments.length==1){
+var rgb=red;
+red=rgb.r;
+_4de=rgb.g;
+blue=rgb.b;
+if(typeof (rgb.a)=="undefined"){
+_4e0=undefined;
+}else{
+_4e0=rgb.a;
+}
+}
+return new _4e1(red,_4de,blue,_4e0);
+},fromHSL:function(hue,_4e4,_4e5,_4e6){
+var m=MochiKit.Color;
+return m.Color.fromRGB(m.hslToRGB.apply(m,arguments));
+},fromHSV:function(hue,_4e9,_4ea,_4eb){
+var m=MochiKit.Color;
+return m.Color.fromRGB(m.hsvToRGB.apply(m,arguments));
+},fromName:function(name){
+var _4ee=MochiKit.Color.Color;
+if(name.charAt(0)=="\""){
+name=name.substr(1,name.length-2);
+}
+var _4ef=_4ee._namedColors[name.toLowerCase()];
+if(typeof (_4ef)=="string"){
+return _4ee.fromHexString(_4ef);
+}else{
+if(name=="transparent"){
+return _4ee.transparentColor();
+}
+}
+return null;
+},fromString:function(_4f0){
+var self=MochiKit.Color.Color;
+var _4f2=_4f0.substr(0,3);
+if(_4f2=="rgb"){
+return self.fromRGBString(_4f0);
+}else{
+if(_4f2=="hsl"){
+return self.fromHSLString(_4f0);
+}else{
+if(_4f0.charAt(0)=="#"){
+return self.fromHexString(_4f0);
+}
+}
+}
+return self.fromName(_4f0);
+},fromHexString:function(_4f3){
+if(_4f3.charAt(0)=="#"){
+_4f3=_4f3.substring(1);
+}
+var _4f4=[];
+var i,hex;
+if(_4f3.length==3){
+for(i=0;i<3;i++){
+hex=_4f3.substr(i,1);
+_4f4.push(parseInt(hex+hex,16)/255);
+}
+}else{
+for(i=0;i<6;i+=2){
+hex=_4f3.substr(i,2);
+_4f4.push(parseInt(hex,16)/255);
+}
+}
+var _4f7=MochiKit.Color.Color;
+return _4f7.fromRGB.apply(_4f7,_4f4);
+},_fromColorString:function(pre,_4f9,_4fa,_4fb){
+if(_4fb.indexOf(pre)===0){
+_4fb=_4fb.substring(_4fb.indexOf("(",3)+1,_4fb.length-1);
+}
+var _4fc=_4fb.split(/\s*,\s*/);
+var _4fd=[];
+for(var i=0;i<_4fc.length;i++){
+var c=_4fc[i];
+var val;
+var _501=c.substring(c.length-3);
+if(c.charAt(c.length-1)=="%"){
+val=0.01*parseFloat(c.substring(0,c.length-1));
+}else{
+if(_501=="deg"){
+val=parseFloat(c)/360;
+}else{
+if(_501=="rad"){
+val=parseFloat(c)/(Math.PI*2);
+}else{
+val=_4fa[i]*parseFloat(c);
+}
+}
+}
+_4fd.push(val);
+}
+return this[_4f9].apply(this,_4fd);
+},fromComputedStyle:function(elem,_503){
+var d=MochiKit.DOM;
+var cls=MochiKit.Color.Color;
+for(elem=d.getElement(elem);elem;elem=elem.parentNode){
+var _506=MochiKit.Style.getStyle.apply(d,arguments);
+if(!_506){
+continue;
+}
+var _507=cls.fromString(_506);
+if(!_507){
+break;
+}
+if(_507.asRGB().a>0){
+return _507;
+}
+}
+return null;
+},fromBackground:function(elem){
+var cls=MochiKit.Color.Color;
+return cls.fromComputedStyle(elem,"backgroundColor","background-color")||cls.whiteColor();
+},fromText:function(elem){
+var cls=MochiKit.Color.Color;
+return cls.fromComputedStyle(elem,"color","color")||cls.blackColor();
+},namedColors:function(){
+return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
+}});
+MochiKit.Base.update(MochiKit.Color,{clampColorComponent:function(v,_50d){
+v*=_50d;
+if(v<0){
+return 0;
+}else{
+if(v>_50d){
+return _50d;
+}else{
+return v;
+}
+}
+},_hslValue:function(n1,n2,hue){
+if(hue>6){
+hue-=6;
+}else{
+if(hue<0){
+hue+=6;
+}
+}
+var val;
+if(hue<1){
+val=n1+(n2-n1)*hue;
+}else{
+if(hue<3){
+val=n2;
+}else{
+if(hue<4){
+val=n1+(n2-n1)*(4-hue);
+}else{
+val=n1;
+}
+}
+}
+return val;
+},hsvToRGB:function(hue,_513,_514,_515){
+if(arguments.length==1){
+var hsv=hue;
+hue=hsv.h;
+_513=hsv.s;
+_514=hsv.v;
+_515=hsv.a;
+}
+var red;
+var _518;
+var blue;
+if(_513===0){
+red=_514;
+_518=_514;
+blue=_514;
+}else{
+var i=Math.floor(hue*6);
+var f=(hue*6)-i;
+var p=_514*(1-_513);
+var q=_514*(1-(_513*f));
+var t=_514*(1-(_513*(1-f)));
+switch(i){
+case 1:
+red=q;
+_518=_514;
+blue=p;
+break;
+case 2:
+red=p;
+_518=_514;
+blue=t;
+break;
+case 3:
+red=p;
+_518=q;
+blue=_514;
+break;
+case 4:
+red=t;
+_518=p;
+blue=_514;
+break;
+case 5:
+red=_514;
+_518=p;
+blue=q;
+break;
+case 6:
+case 0:
+red=_514;
+_518=t;
+blue=p;
+break;
+}
+}
+return {r:red,g:_518,b:blue,a:_515};
+},hslToRGB:function(hue,_520,_521,_522){
+if(arguments.length==1){
+var hsl=hue;
+hue=hsl.h;
+_520=hsl.s;
+_521=hsl.l;
+_522=hsl.a;
+}
+var red;
+var _525;
+var blue;
+if(_520===0){
+red=_521;
+_525=_521;
+blue=_521;
+}else{
+var m2;
+if(_521<=0.5){
+m2=_521*(1+_520);
+}else{
+m2=_521+_520-(_521*_520);
+}
+var m1=(2*_521)-m2;
+var f=MochiKit.Color._hslValue;
+var h6=hue*6;
+red=f(m1,m2,h6+2);
+_525=f(m1,m2,h6);
+blue=f(m1,m2,h6-2);
+}
+return {r:red,g:_525,b:blue,a:_522};
+},rgbToHSV:function(red,_52c,blue,_52e){
+if(arguments.length==1){
+var rgb=red;
+red=rgb.r;
+_52c=rgb.g;
+blue=rgb.b;
+_52e=rgb.a;
+}
+var max=Math.max(Math.max(red,_52c),blue);
+var min=Math.min(Math.min(red,_52c),blue);
+var hue;
+var _533;
+var _534=max;
+if(min==max){
+hue=0;
+_533=0;
+}else{
+var _535=(max-min);
+_533=_535/max;
+if(red==max){
+hue=(_52c-blue)/_535;
+}else{
+if(_52c==max){
+hue=2+((blue-red)/_535);
+}else{
+hue=4+((red-_52c)/_535);
+}
+}
+hue/=6;
+if(hue<0){
+hue+=1;
+}
+if(hue>1){
+hue-=1;
+}
+}
+return {h:hue,s:_533,v:_534,a:_52e};
+},rgbToHSL:function(red,_537,blue,_539){
+if(arguments.length==1){
+var rgb=red;
+red=rgb.r;
+_537=rgb.g;
+blue=rgb.b;
+_539=rgb.a;
+}
+var max=Math.max(red,Math.max(_537,blue));
+var min=Math.min(red,Math.min(_537,blue));
+var hue;
+var _53e;
+var _53f=(max+min)/2;
+var _540=max-min;
+if(_540===0){
+hue=0;
+_53e=0;
+}else{
+if(_53f<=0.5){
+_53e=_540/(max+min);
+}else{
+_53e=_540/(2-max-min);
+}
+if(red==max){
+hue=(_537-blue)/_540;
+}else{
+if(_537==max){
+hue=2+((blue-red)/_540);
+}else{
+hue=4+((red-_537)/_540);
+}
+}
+hue/=6;
+if(hue<0){
+hue+=1;
+}
+if(hue>1){
+hue-=1;
+}
+}
+return {h:hue,s:_53e,l:_53f,a:_539};
+},toColorPart:function(num){
+num=Math.round(num);
+var _542=num.toString(16);
+if(num<16){
+return "0"+_542;
+}
+return _542;
+},__new__:function(){
+var m=MochiKit.Base;
+this.Color.fromRGBString=m.bind(this.Color._fromColorString,this.Color,"rgb","fromRGB",[1/255,1/255,1/255,1]);
+this.Color.fromHSLString=m.bind(this.Color._fromColorString,this.Color,"hsl","fromHSL",[1/360,0.01,0.01,1]);
+var _544=1/3;
+var _545={black:[0,0,0],blue:[0,0,1],brown:[0.6,0.4,0.2],cyan:[0,1,1],darkGray:[_544,_544,_544],gray:[0.5,0.5,0.5],green:[0,1,0],lightGray:[2*_544,2*_544,2*_544],magenta:[1,0,1],orange:[1,0.5,0],purple:[0.5,0,0.5],red:[1,0,0],transparent:[0,0,0,0],white:[1,1,1],yellow:[1,1,0]};
+var _546=function(name,r,g,b,a){
+var rval=this.fromRGB(r,g,b,a);
+this[name]=function(){
+return rval;
+};
+return rval;
+};
+for(var k in _545){
+var name=k+"Color";
+var _54f=m.concat([_546,this.Color,name],_545[k]);
+this.Color[name]=m.bind.apply(null,_54f);
+}
+var _550=function(){
+for(var i=0;i<arguments.length;i++){
+if(!(arguments[i] instanceof MochiKit.Color.Color)){
+return false;
+}
+}
+return true;
+};
+var _552=function(a,b){
+return a.compareRGB(b);
+};
+m.nameFunctions(this);
+m.registerComparator(this.Color.NAME,_550,_552);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+}});
+MochiKit.Color.EXPORT=["Color"];
+MochiKit.Color.EXPORT_OK=["clampColorComponent","rgbToHSL","hslToRGB","rgbToHSV","hsvToRGB","toColorPart"];
+MochiKit.Color.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Color);
+MochiKit.Color.Color._namedColors={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen
:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",
mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};
+MochiKit.Base._deps("Signal",["Base","DOM","Style"]);
+MochiKit.Signal.NAME="MochiKit.Signal";
+MochiKit.Signal.VERSION="1.4.2";
+MochiKit.Signal._observers=[];
+MochiKit.Signal.Event=function(src,e){
+this._event=e||window.event;
+this._src=src;
+};
+MochiKit.Base.update(MochiKit.Signal.Event.prototype,{__repr__:function(){
+var repr=MochiKit.Base.repr;
+var str="{event(): "+repr(this.event())+", src(): "+repr(this.src())+", type(): "+repr(this.type())+", target(): "+repr(this.target());
+if(this.type()&&this.type().indexOf("key")===0||this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu"){
+str+=", modifier(): "+"{alt: "+repr(this.modifier().alt)+", ctrl: "+repr(this.modifier().ctrl)+", meta: "+repr(this.modifier().meta)+", shift: "+repr(this.modifier().shift)+", any: "+repr(this.modifier().any)+"}";
+}
+if(this.type()&&this.type().indexOf("key")===0){
+str+=", key(): {code: "+repr(this.key().code)+", string: "+repr(this.key().string)+"}";
+}
+if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
+str+=", mouse(): {page: "+repr(this.mouse().page)+", client: "+repr(this.mouse().client);
+if(this.type()!="mousemove"&&this.type()!="mousewheel"){
+str+=", button: {left: "+repr(this.mouse().button.left)+", middle: "+repr(this.mouse().button.middle)+", right: "+repr(this.mouse().button.right)+"}";
+}
+if(this.type()=="mousewheel"){
+str+=", wheel: "+repr(this.mouse().wheel);
+}
+str+="}";
+}
+if(this.type()=="mouseover"||this.type()=="mouseout"||this.type()=="mouseenter"||this.type()=="mouseleave"){
+str+=", relatedTarget(): "+repr(this.relatedTarget());
+}
+str+="}";
+return str;
+},toString:function(){
+return this.__repr__();
+},src:function(){
+return this._src;
+},event:function(){
+return this._event;
+},type:function(){
+if(this._event.type==="DOMMouseScroll"){
+return "mousewheel";
+}else{
+return this._event.type||undefined;
+}
+},target:function(){
+return this._event.target||this._event.srcElement;
+},_relatedTarget:null,relatedTarget:function(){
+if(this._relatedTarget!==null){
+return this._relatedTarget;
+}
+var elem=null;
+if(this.type()=="mouseover"||this.type()=="mouseenter"){
+elem=(this._event.relatedTarget||this._event.fromElement);
+}else{
+if(this.type()=="mouseout"||this.type()=="mouseleave"){
+elem=(this._event.relatedTarget||this._event.toElement);
+}
+}
+try{
+if(elem!==null&&elem.nodeType!==null){
+this._relatedTarget=elem;
+return elem;
+}
+}
+catch(ignore){
+}
+return undefined;
+},_modifier:null,modifier:function(){
+if(this._modifier!==null){
+return this._modifier;
+}
+var m={};
+m.alt=this._event.altKey;
+m.ctrl=this._event.ctrlKey;
+m.meta=this._event.metaKey||false;
+m.shift=this._event.shiftKey;
+m.any=m.alt||m.ctrl||m.shift||m.meta;
+this._modifier=m;
+return m;
+},_key:null,key:function(){
+if(this._key!==null){
+return this._key;
+}
+var k={};
+if(this.type()&&this.type().indexOf("key")===0){
+if(this.type()=="keydown"||this.type()=="keyup"){
+k.code=this._event.keyCode;
+k.string=(MochiKit.Signal._specialKeys[k.code]||"KEY_UNKNOWN");
+this._key=k;
+return k;
+}else{
+if(this.type()=="keypress"){
+k.code=0;
+k.string="";
+if(typeof (this._event.charCode)!="undefined"&&this._event.charCode!==0&&!MochiKit.Signal._specialMacKeys[this._event.charCode]){
+k.code=this._event.charCode;
+k.string=String.fromCharCode(k.code);
+}else{
+if(this._event.keyCode&&typeof (this._event.charCode)=="undefined"){
+k.code=this._event.keyCode;
+k.string=String.fromCharCode(k.code);
+}
+}
+this._key=k;
+return k;
+}
+}
+}
+return undefined;
+},_mouse:null,mouse:function(){
+if(this._mouse!==null){
+return this._mouse;
+}
+var m={};
+var e=this._event;
+if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
+m.client=new MochiKit.Style.Coordinates(0,0);
+if(e.clientX||e.clientY){
+m.client.x=(!e.clientX||e.clientX<0)?0:e.clientX;
+m.client.y=(!e.clientY||e.clientY<0)?0:e.clientY;
+}
+m.page=new MochiKit.Style.Coordinates(0,0);
+if(e.pageX||e.pageY){
+m.page.x=(!e.pageX||e.pageX<0)?0:e.pageX;
+m.page.y=(!e.pageY||e.pageY<0)?0:e.pageY;
+}else{
+var de=MochiKit.DOM._document.documentElement;
+var b=MochiKit.DOM._document.body;
+m.page.x=e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
+m.page.y=e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
+}
+if(this.type()!="mousemove"&&this.type()!="mousewheel"){
+m.button={};
+m.button.left=false;
+m.button.right=false;
+m.button.middle=false;
+if(e.which){
+m.button.left=(e.which==1);
+m.button.middle=(e.which==2);
+m.button.right=(e.which==3);
+}else{
+m.button.left=!!(e.button&1);
+m.button.right=!!(e.button&2);
+m.button.middle=!!(e.button&4);
+}
+}
+if(this.type()=="mousewheel"){
+m.wheel=new MochiKit.Style.Coordinates(0,0);
+if(e.wheelDeltaX||e.wheelDeltaY){
+m.wheel.x=e.wheelDeltaX/-40||0;
+m.wheel.y=e.wheelDeltaY/-40||0;
+}else{
+if(e.wheelDelta){
+m.wheel.y=e.wheelDelta/-40;
+}else{
+m.wheel.y=e.detail||0;
+}
+}
+}
+this._mouse=m;
+return m;
+}
+return undefined;
+},stop:function(){
+this.stopPropagation();
+this.preventDefault();
+},stopPropagation:function(){
+if(this._event.stopPropagation){
+this._event.stopPropagation();
+}else{
+this._event.cancelBubble=true;
+}
+},preventDefault:function(){
+if(this._event.preventDefault){
+this._event.preventDefault();
+}else{
+if(this._confirmUnload===null){
+this._event.returnValue=false;
+}
+}
+},_confirmUnload:null,confirmUnload:function(msg){
+if(this.type()=="beforeunload"){
+this._confirmUnload=msg;
+this._event.returnValue=msg;
+}
+}});
+MochiKit.Signal._specialMacKeys={3:"KEY_ENTER",63289:"KEY_NUM_PAD_CLEAR",63276:"KEY_PAGE_UP",63277:"KEY_PAGE_DOWN",63275:"KEY_END",63273:"KEY_HOME",63234:"KEY_ARROW_LEFT",63232:"KEY_ARROW_UP",63235:"KEY_ARROW_RIGHT",63233:"KEY_ARROW_DOWN",63302:"KEY_INSERT",63272:"KEY_DELETE"};
+(function(){
+var _561=MochiKit.Signal._specialMacKeys;
+for(i=63236;i<=63242;i++){
+_561[i]="KEY_F"+(i-63236+1);
+}
+})();
+MochiKit.Signal._specialKeys={8:"KEY_BACKSPACE",9:"KEY_TAB",12:"KEY_NUM_PAD_CLEAR",13:"KEY_ENTER",16:"KEY_SHIFT",17:"KEY_CTRL",18:"KEY_ALT",19:"KEY_PAUSE",20:"KEY_CAPS_LOCK",27:"KEY_ESCAPE",32:"KEY_SPACEBAR",33:"KEY_PAGE_UP",34:"KEY_PAGE_DOWN",35:"KEY_END",36:"KEY_HOME",37:"KEY_ARROW_LEFT",38:"KEY_ARROW_UP",39:"KEY_ARROW_RIGHT",40:"KEY_ARROW_DOWN",44:"KEY_PRINT_SCREEN",45:"KEY_INSERT",46:"KEY_DELETE",59:"KEY_SEMICOLON",91:"KEY_WINDOWS_LEFT",92:"KEY_WINDOWS_RIGHT",93:"KEY_SELECT",106:"KEY_NUM_PAD_ASTERISK",107:"KEY_NUM_PAD_PLUS_SIGN",109:"KEY_NUM_PAD_HYPHEN-MINUS",110:"KEY_NUM_PAD_FULL_STOP",111:"KEY_NUM_PAD_SOLIDUS",144:"KEY_NUM_LOCK",145:"KEY_SCROLL_LOCK",186:"KEY_SEMICOLON",187:"KEY_EQUALS_SIGN",188:"KEY_COMMA",189:"KEY_HYPHEN-MINUS",190:"KEY_FULL_STOP",191:"KEY_SOLIDUS",192:"KEY_GRAVE_ACCENT",219:"KEY_LEFT_SQUARE_BRACKET",220:"KEY_REVERSE_SOLIDUS",221:"KEY_RIGHT_SQUARE_BRACKET",222:"KEY_APOSTROPHE"};
+(function(){
+var _562=MochiKit.Signal._specialKeys;
+for(var i=48;i<=57;i++){
+_562[i]="KEY_"+(i-48);
+}
+for(i=65;i<=90;i++){
+_562[i]="KEY_"+String.fromCharCode(i);
+}
+for(i=96;i<=105;i++){
+_562[i]="KEY_NUM_PAD_"+(i-96);
+}
+for(i=112;i<=123;i++){
+_562[i]="KEY_F"+(i-112+1);
+}
+})();
+MochiKit.Signal.Ident=function(_564){
+this.source=_564.source;
+this.signal=_564.signal;
+this.listener=_564.listener;
+this.isDOM=_564.isDOM;
+this.objOrFunc=_564.objOrFunc;
+this.funcOrStr=_564.funcOrStr;
+this.connected=_564.connected;
+};
+MochiKit.Signal.Ident.prototype={};
+MochiKit.Base.update(MochiKit.Signal,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},_unloadCache:function(){
+var self=MochiKit.Signal;
+var _566=self._observers;
+for(var i=0;i<_566.length;i++){
+if(_566[i].signal!=="onload"&&_566[i].signal!=="onunload"){
+self._disconnect(_566[i]);
+}
+}
+},_listener:function(src,sig,func,obj,_56c){
+var self=MochiKit.Signal;
+var E=self.Event;
+if(!_56c){
+if(typeof (func.im_self)=="undefined"){
+return MochiKit.Base.bindLate(func,obj);
+}else{
+return func;
+}
+}
+obj=obj||src;
+if(typeof (func)=="string"){
+if(sig==="onload"||sig==="onunload"){
+return function(_56f){
+obj[func].apply(obj,[new E(src,_56f)]);
+var _570=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:obj,funcOrStr:func});
+MochiKit.Signal._disconnect(_570);
+};
+}else{
+return function(_571){
+obj[func].apply(obj,[new E(src,_571)]);
+};
+}
+}else{
+if(sig==="onload"||sig==="onunload"){
+return function(_572){
+func.apply(obj,[new E(src,_572)]);
+var _573=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:func});
+MochiKit.Signal._disconnect(_573);
+};
+}else{
+return function(_574){
+func.apply(obj,[new E(src,_574)]);
+};
+}
+}
+},_browserAlreadyHasMouseEnterAndLeave:function(){
+return /MSIE/.test(navigator.userAgent);
+},_browserLacksMouseWheelEvent:function(){
+return /Gecko\//.test(navigator.userAgent);
+},_mouseEnterListener:function(src,sig,func,obj){
+var E=MochiKit.Signal.Event;
+return function(_57a){
+var e=new E(src,_57a);
+try{
+e.relatedTarget().nodeName;
+}
+catch(err){
+return;
+}
+e.stop();
+if(MochiKit.DOM.isChildNode(e.relatedTarget(),src)){
+return;
+}
+e.type=function(){
+return sig;
+};
+if(typeof (func)=="string"){
+return obj[func].apply(obj,[e]);
+}else{
+return func.apply(obj,[e]);
+}
+};
+},_getDestPair:function(_57c,_57d){
+var obj=null;
+var func=null;
+if(typeof (_57d)!="undefined"){
+obj=_57c;
+func=_57d;
+if(typeof (_57d)=="string"){
+if(typeof (_57c[_57d])!="function"){
+throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
+}
+}else{
+if(typeof (_57d)!="function"){
+throw new Error("'funcOrStr' must be a function or string");
+}
+}
+}else{
+if(typeof (_57c)!="function"){
+throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
+}else{
+func=_57c;
+}
+}
+return [obj,func];
+},connect:function(src,sig,_582,_583){
+src=MochiKit.DOM.getElement(src);
+var self=MochiKit.Signal;
+if(typeof (sig)!="string"){
+throw new Error("'sig' must be a string");
+}
+var _585=self._getDestPair(_582,_583);
+var obj=_585[0];
+var func=_585[1];
+if(typeof (obj)=="undefined"||obj===null){
+obj=src;
+}
+var _588=!!(src.addEventListener||src.attachEvent);
+if(_588&&(sig==="onmouseenter"||sig==="onmouseleave")&&!self._browserAlreadyHasMouseEnterAndLeave()){
+var _589=self._mouseEnterListener(src,sig.substr(2),func,obj);
+if(sig==="onmouseenter"){
+sig="onmouseover";
+}else{
+sig="onmouseout";
+}
+}else{
+if(_588&&sig=="onmousewheel"&&self._browserLacksMouseWheelEvent()){
+var _589=self._listener(src,sig,func,obj,_588);
+sig="onDOMMouseScroll";
+}else{
+var _589=self._listener(src,sig,func,obj,_588);
+}
+}
+if(src.addEventListener){
+src.addEventListener(sig.substr(2),_589,false);
+}else{
+if(src.attachEvent){
+src.attachEvent(sig,_589);
+}
+}
+var _58a=new MochiKit.Signal.Ident({source:src,signal:sig,listener:_589,isDOM:_588,objOrFunc:_582,funcOrStr:_583,connected:true});
+self._observers.push(_58a);
+if(!_588&&typeof (src.__connect__)=="function"){
+var args=MochiKit.Base.extend([_58a],arguments,1);
+src.__connect__.apply(src,args);
+}
+return _58a;
+},_disconnect:function(_58c){
+if(!_58c.connected){
+return;
+}
+_58c.connected=false;
+var src=_58c.source;
+var sig=_58c.signal;
+var _58f=_58c.listener;
+if(!_58c.isDOM){
+if(typeof (src.__disconnect__)=="function"){
+src.__disconnect__(_58c,sig,_58c.objOrFunc,_58c.funcOrStr);
+}
+return;
+}
+if(src.removeEventListener){
+src.removeEventListener(sig.substr(2),_58f,false);
+}else{
+if(src.detachEvent){
+src.detachEvent(sig,_58f);
+}else{
+throw new Error("'src' must be a DOM element");
+}
+}
+},disconnect:function(_590){
+var self=MochiKit.Signal;
+var _592=self._observers;
+var m=MochiKit.Base;
+if(arguments.length>1){
+var src=MochiKit.DOM.getElement(arguments[0]);
+var sig=arguments[1];
+var obj=arguments[2];
+var func=arguments[3];
+for(var i=_592.length-1;i>=0;i--){
+var o=_592[i];
+if(o.source===src&&o.signal===sig&&o.objOrFunc===obj&&o.funcOrStr===func){
+self._disconnect(o);
+if(!self._lock){
+_592.splice(i,1);
+}else{
+self._dirty=true;
+}
+return true;
+}
+}
+}else{
+var idx=m.findIdentical(_592,_590);
+if(idx>=0){
+self._disconnect(_590);
+if(!self._lock){
+_592.splice(idx,1);
+}else{
+self._dirty=true;
+}
+return true;
+}
+}
+return false;
+},disconnectAllTo:function(_59b,_59c){
+var self=MochiKit.Signal;
+var _59e=self._observers;
+var _59f=self._disconnect;
+var _5a0=self._lock;
+var _5a1=self._dirty;
+if(typeof (_59c)==="undefined"){
+_59c=null;
+}
+for(var i=_59e.length-1;i>=0;i--){
+var _5a3=_59e[i];
+if(_5a3.objOrFunc===_59b&&(_59c===null||_5a3.funcOrStr===_59c)){
+_59f(_5a3);
+if(_5a0){
+_5a1=true;
+}else{
+_59e.splice(i,1);
+}
+}
+}
+self._dirty=_5a1;
+},disconnectAll:function(src,sig){
+src=MochiKit.DOM.getElement(src);
+var m=MochiKit.Base;
+var _5a7=m.flattenArguments(m.extend(null,arguments,1));
+var self=MochiKit.Signal;
+var _5a9=self._disconnect;
+var _5aa=self._observers;
+var i,_5ac;
+var _5ad=self._lock;
+var _5ae=self._dirty;
+if(_5a7.length===0){
+for(i=_5aa.length-1;i>=0;i--){
+_5ac=_5aa[i];
+if(_5ac.source===src){
+_5a9(_5ac);
+if(!_5ad){
+_5aa.splice(i,1);
+}else{
+_5ae=true;
+}
+}
+}
+}else{
+var sigs={};
+for(i=0;i<_5a7.length;i++){
+sigs[_5a7[i]]=true;
+}
+for(i=_5aa.length-1;i>=0;i--){
+_5ac=_5aa[i];
+if(_5ac.source===src&&_5ac.signal in sigs){
+_5a9(_5ac);
+if(!_5ad){
+_5aa.splice(i,1);
+}else{
+_5ae=true;
+}
+}
+}
+}
+self._dirty=_5ae;
+},signal:function(src,sig){
+var self=MochiKit.Signal;
+var _5b3=self._observers;
+src=MochiKit.DOM.getElement(src);
+var args=MochiKit.Base.extend(null,arguments,2);
+var _5b5=[];
+self._lock=true;
+for(var i=0;i<_5b3.length;i++){
+var _5b7=_5b3[i];
+if(_5b7.source===src&&_5b7.signal===sig&&_5b7.connected){
+try{
+_5b7.listener.apply(src,args);
+}
+catch(e){
+_5b5.push(e);
+}
+}
+}
+self._lock=false;
+if(self._dirty){
+self._dirty=false;
+for(var i=_5b3.length-1;i>=0;i--){
+if(!_5b3[i].connected){
+_5b3.splice(i,1);
+}
+}
+}
+if(_5b5.length==1){
+throw _5b5[0];
+}else{
+if(_5b5.length>1){
+var e=new Error("Multiple errors thrown in handling 'sig', see errors property");
+e.errors=_5b5;
+throw e;
+}
+}
+}});
+MochiKit.Signal.EXPORT_OK=[];
+MochiKit.Signal.EXPORT=["connect","disconnect","signal","disconnectAll","disconnectAllTo"];
+MochiKit.Signal.__new__=function(win){
+var m=MochiKit.Base;
+this._document=document;
+this._window=win;
+this._lock=false;
+this._dirty=false;
+try{
+this.connect(window,"onunload",this._unloadCache);
+}
+catch(e){
+}
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Signal.__new__(this);
+if(MochiKit.__export__){
+connect=MochiKit.Signal.connect;
+disconnect=MochiKit.Signal.disconnect;
+disconnectAll=MochiKit.Signal.disconnectAll;
+signal=MochiKit.Signal.signal;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Signal);
+MochiKit.Base._deps("Position",["Base","DOM","Style"]);
+MochiKit.Position.NAME="MochiKit.Position";
+MochiKit.Position.VERSION="1.4.2";
+MochiKit.Position.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Position.toString=function(){
+return this.__repr__();
+};
+MochiKit.Position.EXPORT_OK=[];
+MochiKit.Position.EXPORT=[];
+MochiKit.Base.update(MochiKit.Position,{includeScrollOffsets:false,prepare:function(){
+var _5bb=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;
+var _5bc=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;
+this.windowOffset=new MochiKit.Style.Coordinates(_5bb,_5bc);
+},cumulativeOffset:function(_5bd){
+var _5be=0;
+var _5bf=0;
+do{
+_5be+=_5bd.offsetTop||0;
+_5bf+=_5bd.offsetLeft||0;
+_5bd=_5bd.offsetParent;
+}while(_5bd);
+return new MochiKit.Style.Coordinates(_5bf,_5be);
+},realOffset:function(_5c0){
+var _5c1=0;
+var _5c2=0;
+do{
+_5c1+=_5c0.scrollTop||0;
+_5c2+=_5c0.scrollLeft||0;
+_5c0=_5c0.parentNode;
+}while(_5c0);
+return new MochiKit.Style.Coordinates(_5c2,_5c1);
+},within:function(_5c3,x,y){
+if(this.includeScrollOffsets){
+return this.withinIncludingScrolloffsets(_5c3,x,y);
+}
+this.xcomp=x;
+this.ycomp=y;
+this.offset=this.cumulativeOffset(_5c3);
+if(_5c3.style.position=="fixed"){
+this.offset.x+=this.windowOffset.x;
+this.offset.y+=this.windowOffset.y;
+}
+return (y>=this.offset.y&&y<this.offset.y+_5c3.offsetHeight&&x>=this.offset.x&&x<this.offset.x+_5c3.offsetWidth);
+},withinIncludingScrolloffsets:function(_5c6,x,y){
+var _5c9=this.realOffset(_5c6);
+this.xcomp=x+_5c9.x-this.windowOffset.x;
+this.ycomp=y+_5c9.y-this.windowOffset.y;
+this.offset=this.cumulativeOffset(_5c6);
+return (this.ycomp>=this.offset.y&&this.ycomp<this.offset.y+_5c6.offsetHeight&&this.xcomp>=this.offset.x&&this.xcomp<this.offset.x+_5c6.offsetWidth);
+},overlap:function(mode,_5cb){
+if(!mode){
+return 0;
+}
+if(mode=="vertical"){
+return ((this.offset.y+_5cb.offsetHeight)-this.ycomp)/_5cb.offsetHeight;
+}
+if(mode=="horizontal"){
+return ((this.offset.x+_5cb.offsetWidth)-this.xcomp)/_5cb.offsetWidth;
+}
+},absolutize:function(_5cc){
+_5cc=MochiKit.DOM.getElement(_5cc);
+if(_5cc.style.position=="absolute"){
+return;
+}
+MochiKit.Position.prepare();
+var _5cd=MochiKit.Position.positionedOffset(_5cc);
+var _5ce=_5cc.clientWidth;
+var _5cf=_5cc.clientHeight;
+var _5d0={"position":_5cc.style.position,"left":_5cd.x-parseFloat(_5cc.style.left||0),"top":_5cd.y-parseFloat(_5cc.style.top||0),"width":_5cc.style.width,"height":_5cc.style.height};
+_5cc.style.position="absolute";
+_5cc.style.top=_5cd.y+"px";
+_5cc.style.left=_5cd.x+"px";
+_5cc.style.width=_5ce+"px";
+_5cc.style.height=_5cf+"px";
+return _5d0;
+},positionedOffset:function(_5d1){
+var _5d2=0,_5d3=0;
+do{
+_5d2+=_5d1.offsetTop||0;
+_5d3+=_5d1.offsetLeft||0;
+_5d1=_5d1.offsetParent;
+if(_5d1){
+p=MochiKit.Style.getStyle(_5d1,"position");
+if(p=="relative"||p=="absolute"){
+break;
+}
+}
+}while(_5d1);
+return new MochiKit.Style.Coordinates(_5d3,_5d2);
+},relativize:function(_5d4,_5d5){
+_5d4=MochiKit.DOM.getElement(_5d4);
+if(_5d4.style.position=="relative"){
+return;
+}
+MochiKit.Position.prepare();
+var top=parseFloat(_5d4.style.top||0)-(_5d5["top"]||0);
+var left=parseFloat(_5d4.style.left||0)-(_5d5["left"]||0);
+_5d4.style.position=_5d5["position"];
+_5d4.style.top=top+"px";
+_5d4.style.left=left+"px";
+_5d4.style.width=_5d5["width"];
+_5d4.style.height=_5d5["height"];
+},clone:function(_5d8,_5d9){
+_5d8=MochiKit.DOM.getElement(_5d8);
+_5d9=MochiKit.DOM.getElement(_5d9);
+_5d9.style.position="absolute";
+var _5da=this.cumulativeOffset(_5d8);
+_5d9.style.top=_5da.y+"px";
+_5d9.style.left=_5da.x+"px";
+_5d9.style.width=_5d8.offsetWidth+"px";
+_5d9.style.height=_5d8.offsetHeight+"px";
+},page:function(_5db){
+var _5dc=0;
+var _5dd=0;
+var _5de=_5db;
+do{
+_5dc+=_5de.offsetTop||0;
+_5dd+=_5de.offsetLeft||0;
+if(_5de.offsetParent==document.body&&MochiKit.Style.getStyle(_5de,"position")=="absolute"){
+break;
+}
+}while(_5de=_5de.offsetParent);
+_5de=_5db;
+do{
+_5dc-=_5de.scrollTop||0;
+_5dd-=_5de.scrollLeft||0;
+}while(_5de=_5de.parentNode);
+return new MochiKit.Style.Coordinates(_5dd,_5dc);
+}});
+MochiKit.Position.__new__=function(win){
+var m=MochiKit.Base;
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Position.__new__(this);
+MochiKit.Base._exportSymbols(this,MochiKit.Position);
+MochiKit.Base._deps("Visual",["Base","DOM","Style","Color","Position"]);
+MochiKit.Visual.NAME="MochiKit.Visual";
+MochiKit.Visual.VERSION="1.4.2";
+MochiKit.Visual.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Visual.toString=function(){
+return this.__repr__();
+};
+MochiKit.Visual._RoundCorners=function(e,_5e2){
+e=MochiKit.DOM.getElement(e);
+this._setOptions(_5e2);
+if(this.options.__unstable__wrapElement){
+e=this._doWrap(e);
+}
+var _5e3=this.options.color;
+var C=MochiKit.Color.Color;
+if(this.options.color==="fromElement"){
+_5e3=C.fromBackground(e);
+}else{
+if(!(_5e3 instanceof C)){
+_5e3=C.fromString(_5e3);
+}
+}
+this.isTransparent=(_5e3.asRGB().a<=0);
+var _5e5=this.options.bgColor;
+if(this.options.bgColor==="fromParent"){
+_5e5=C.fromBackground(e.offsetParent);
+}else{
+if(!(_5e5 instanceof C)){
+_5e5=C.fromString(_5e5);
+}
+}
+this._roundCornersImpl(e,_5e3,_5e5);
+};
+MochiKit.Visual._RoundCorners.prototype={_doWrap:function(e){
+var _5e7=e.parentNode;
+var doc=MochiKit.DOM.currentDocument();
+if(typeof (doc.defaultView)==="undefined"||doc.defaultView===null){
+return e;
+}
+var _5e9=doc.defaultView.getComputedStyle(e,null);
+if(typeof (_5e9)==="undefined"||_5e9===null){
+return e;
+}
+var _5ea=MochiKit.DOM.DIV({"style":{display:"block",marginTop:_5e9.getPropertyValue("padding-top"),marginRight:_5e9.getPropertyValue("padding-right"),marginBottom:_5e9.getPropertyValue("padding-bottom"),marginLeft:_5e9.getPropertyValue("padding-left"),padding:"0px"}});
+_5ea.innerHTML=e.innerHTML;
+e.innerHTML="";
+e.appendChild(_5ea);
+return e;
+},_roundCornersImpl:function(e,_5ec,_5ed){
+if(this.options.border){
+this._renderBorder(e,_5ed);
+}
+if(this._isTopRounded()){
+this._roundTopCorners(e,_5ec,_5ed);
+}
+if(this._isBottomRounded()){
+this._roundBottomCorners(e,_5ec,_5ed);
+}
+},_renderBorder:function(el,_5ef){
+var _5f0="1px solid "+this._borderColor(_5ef);
+var _5f1="border-left: "+_5f0;
+var _5f2="border-right: "+_5f0;
+var _5f3="style='"+_5f1+";"+_5f2+"'";
+el.innerHTML="<div "+_5f3+">"+el.innerHTML+"</div>";
+},_roundTopCorners:function(el,_5f5,_5f6){
+var _5f7=this._createCorner(_5f6);
+for(var i=0;i<this.options.numSlices;i++){
+_5f7.appendChild(this._createCornerSlice(_5f5,_5f6,i,"top"));
+}
+el.style.paddingTop=0;
+el.insertBefore(_5f7,el.firstChild);
+},_roundBottomCorners:function(el,_5fa,_5fb){
+var _5fc=this._createCorner(_5fb);
+for(var i=(this.options.numSlices-1);i>=0;i--){
+_5fc.appendChild(this._createCornerSlice(_5fa,_5fb,i,"bottom"));
+}
+el.style.paddingBottom=0;
+el.appendChild(_5fc);
+},_createCorner:function(_5fe){
+var dom=MochiKit.DOM;
+return dom.DIV({style:{backgroundColor:_5fe.toString()}});
+},_createCornerSlice:function(_600,_601,n,_603){
+var _604=MochiKit.DOM.SPAN();
+var _605=_604.style;
+_605.backgroundColor=_600.toString();
+_605.display="block";
+_605.height="1px";
+_605.overflow="hidden";
+_605.fontSize="1px";
+var _606=this._borderColor(_600,_601);
+if(this.options.border&&n===0){
+_605.borderTopStyle="solid";
+_605.borderTopWidth="1px";
+_605.borderLeftWidth="0px";
+_605.borderRightWidth="0px";
+_605.borderBottomWidth="0px";
+_605.height="0px";
+_605.borderColor=_606.toString();
+}else{
+if(_606){
+_605.borderColor=_606.toString();
+_605.borderStyle="solid";
+_605.borderWidth="0px 1px";
+}
+}
+if(!this.options.compact&&(n==(this.options.numSlices-1))){
+_605.height="2px";
+}
+this._setMargin(_604,n,_603);
+this._setBorder(_604,n,_603);
+return _604;
+},_setOptions:function(_607){
+this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:true,border:false,compact:false,__unstable__wrapElement:false};
+MochiKit.Base.update(this.options,_607);
+this.options.numSlices=(this.options.compact?2:4);
+},_whichSideTop:function(){
+var _608=this.options.corners;
+if(this._hasString(_608,"all","top")){
+return "";
+}
+var _609=(_608.indexOf("tl")!=-1);
+var _60a=(_608.indexOf("tr")!=-1);
+if(_609&&_60a){
+return "";
+}
+if(_609){
+return "left";
+}
+if(_60a){
+return "right";
+}
+return "";
+},_whichSideBottom:function(){
+var _60b=this.options.corners;
+if(this._hasString(_60b,"all","bottom")){
+return "";
+}
+var _60c=(_60b.indexOf("bl")!=-1);
+var _60d=(_60b.indexOf("br")!=-1);
+if(_60c&&_60d){
+return "";
+}
+if(_60c){
+return "left";
+}
+if(_60d){
+return "right";
+}
+return "";
+},_borderColor:function(_60e,_60f){
+if(_60e=="transparent"){
+return _60f;
+}else{
+if(this.options.border){
+return this.options.border;
+}else{
+if(this.options.blend){
+return _60f.blendedColor(_60e);
+}
+}
+}
+return "";
+},_setMargin:function(el,n,_612){
+var _613=this._marginSize(n)+"px";
+var _614=(_612=="top"?this._whichSideTop():this._whichSideBottom());
+var _615=el.style;
+if(_614=="left"){
+_615.marginLeft=_613;
+_615.marginRight="0px";
+}else{
+if(_614=="right"){
+_615.marginRight=_613;
+_615.marginLeft="0px";
+}else{
+_615.marginLeft=_613;
+_615.marginRight=_613;
+}
+}
+},_setBorder:function(el,n,_618){
+var _619=this._borderSize(n)+"px";
+var _61a=(_618=="top"?this._whichSideTop():this._whichSideBottom());
+var _61b=el.style;
+if(_61a=="left"){
+_61b.borderLeftWidth=_619;
+_61b.borderRightWidth="0px";
+}else{
+if(_61a=="right"){
+_61b.borderRightWidth=_619;
+_61b.borderLeftWidth="0px";
+}else{
+_61b.borderLeftWidth=_619;
+_61b.borderRightWidth=_619;
+}
+}
+},_marginSize:function(n){
+if(this.isTransparent){
+return 0;
+}
+var o=this.options;
+if(o.compact&&o.blend){
+var _61e=[1,0];
+return _61e[n];
+}else{
+if(o.compact){
+var _61f=[2,1];
+return _61f[n];
+}else{
+if(o.blend){
+var _620=[3,2,1,0];
+return _620[n];
+}else{
+var _621=[5,3,2,1];
+return _621[n];
+}
+}
+}
+},_borderSize:function(n){
+var o=this.options;
+var _624;
+if(o.compact&&(o.blend||this.isTransparent)){
+return 1;
+}else{
+if(o.compact){
+_624=[1,0];
+}else{
+if(o.blend){
+_624=[2,1,1,1];
+}else{
+if(o.border){
+_624=[0,2,0,0];
+}else{
+if(this.isTransparent){
+_624=[5,3,2,1];
+}else{
+return 0;
+}
+}
+}
+}
+}
+return _624[n];
+},_hasString:function(str){
+for(var i=1;i<arguments.length;i++){
+if(str.indexOf(arguments[i])!=-1){
+return true;
+}
+}
+return false;
+},_isTopRounded:function(){
+return this._hasString(this.options.corners,"all","top","tl","tr");
+},_isBottomRounded:function(){
+return this._hasString(this.options.corners,"all","bottom","bl","br");
+},_hasSingleTextChild:function(el){
+return (el.childNodes.length==1&&el.childNodes[0].nodeType==3);
+}};
+MochiKit.Visual.roundElement=function(e,_629){
+new MochiKit.Visual._RoundCorners(e,_629);
+};
+MochiKit.Visual.roundClass=function(_62a,_62b,_62c){
+var _62d=MochiKit.DOM.getElementsByTagAndClassName(_62a,_62b);
+for(var i=0;i<_62d.length;i++){
+MochiKit.Visual.roundElement(_62d[i],_62c);
+}
+};
+MochiKit.Visual.tagifyText=function(_62f,_630){
+_630=_630||"position:relative";
+if(/MSIE/.test(navigator.userAgent)){
+_630+=";zoom:1";
+}
+_62f=MochiKit.DOM.getElement(_62f);
+var ma=MochiKit.Base.map;
+ma(function(_632){
+if(_632.nodeType==3){
+ma(function(_633){
+_62f.insertBefore(MochiKit.DOM.SPAN({style:_630},_633==" "?String.fromCharCode(160):_633),_632);
+},_632.nodeValue.split(""));
+MochiKit.DOM.removeElement(_632);
+}
+},_62f.childNodes);
+};
+MochiKit.Visual.forceRerendering=function(_634){
+try{
+_634=MochiKit.DOM.getElement(_634);
+var n=document.createTextNode(" ");
+_634.appendChild(n);
+_634.removeChild(n);
+}
+catch(e){
+}
+};
+MochiKit.Visual.multiple=function(_636,_637,_638){
+_638=MochiKit.Base.update({speed:0.1,delay:0},_638);
+var _639=_638.delay;
+var _63a=0;
+MochiKit.Base.map(function(_63b){
+_638.delay=_63a*_638.speed+_639;
+new _637(_63b,_638);
+_63a+=1;
+},_636);
+};
+MochiKit.Visual.PAIRS={"slide":["slideDown","slideUp"],"blind":["blindDown","blindUp"],"appear":["appear","fade"],"size":["grow","shrink"]};
+MochiKit.Visual.toggle=function(_63c,_63d,_63e){
+_63c=MochiKit.DOM.getElement(_63c);
+_63d=(_63d||"appear").toLowerCase();
+_63e=MochiKit.Base.update({queue:{position:"end",scope:(_63c.id||"global"),limit:1}},_63e);
+var v=MochiKit.Visual;
+v[MochiKit.Style.getStyle(_63c,"display")!="none"?v.PAIRS[_63d][1]:v.PAIRS[_63d][0]](_63c,_63e);
+};
+MochiKit.Visual.Transitions={};
+MochiKit.Visual.Transitions.linear=function(pos){
+return pos;
+};
+MochiKit.Visual.Transitions.sinoidal=function(pos){
+return 0.5-Math.cos(pos*Math.PI)/2;
+};
+MochiKit.Visual.Transitions.reverse=function(pos){
+return 1-pos;
+};
+MochiKit.Visual.Transitions.flicker=function(pos){
+return 0.25-Math.cos(pos*Math.PI)/4+Math.random()/2;
+};
+MochiKit.Visual.Transitions.wobble=function(pos){
+return 0.5-Math.cos(9*pos*Math.PI)/2;
+};
+MochiKit.Visual.Transitions.pulse=function(pos,_646){
+if(_646){
+pos*=2*_646;
+}else{
+pos*=10;
+}
+var _647=pos-Math.floor(pos);
+return (Math.floor(pos)%2==0)?_647:1-_647;
+};
+MochiKit.Visual.Transitions.parabolic=function(pos){
+return pos*pos;
+};
+MochiKit.Visual.Transitions.none=function(pos){
+return 0;
+};
+MochiKit.Visual.Transitions.full=function(pos){
+return 1;
+};
+MochiKit.Visual.ScopedQueue=function(){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls();
+}
+this.__init__();
+};
+MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype,{__init__:function(){
+this.effects=[];
+this.interval=null;
+},add:function(_64c){
+var _64d=new Date().getTime();
+var _64e=(typeof (_64c.options.queue)=="string")?_64c.options.queue:_64c.options.queue.position;
+var ma=MochiKit.Base.map;
+switch(_64e){
+case "front":
+ma(function(e){
+if(e.state=="idle"){
+e.startOn+=_64c.finishOn;
+e.finishOn+=_64c.finishOn;
+}
+},this.effects);
+break;
+case "end":
+var _651;
+ma(function(e){
+var i=e.finishOn;
+if(i>=(_651||i)){
+_651=i;
+}
+},this.effects);
+_64d=_651||_64d;
+break;
+case "break":
+ma(function(e){
+e.finalize();
+},this.effects);
+break;
+}
+_64c.startOn+=_64d;
+_64c.finishOn+=_64d;
+if(!_64c.options.queue.limit||this.effects.length<_64c.options.queue.limit){
+this.effects.push(_64c);
+}
+if(!this.interval){
+this.interval=this.startLoop(MochiKit.Base.bind(this.loop,this),40);
+}
+},startLoop:function(func,_656){
+return setInterval(func,_656);
+},remove:function(_657){
+this.effects=MochiKit.Base.filter(function(e){
+return e!=_657;
+},this.effects);
+if(!this.effects.length){
+this.stopLoop(this.interval);
+this.interval=null;
+}
+},stopLoop:function(_659){
+clearInterval(_659);
+},loop:function(){
+var _65a=new Date().getTime();
+MochiKit.Base.map(function(_65b){
+_65b.loop(_65a);
+},this.effects);
+}});
+MochiKit.Visual.Queues={instances:{},get:function(_65c){
+if(typeof (_65c)!="string"){
+return _65c;
+}
+if(!this.instances[_65c]){
+this.instances[_65c]=new MochiKit.Visual.ScopedQueue();
+}
+return this.instances[_65c];
+}};
+MochiKit.Visual.Queue=MochiKit.Visual.Queues.get("global");
+MochiKit.Visual.DefaultOptions={transition:MochiKit.Visual.Transitions.sinoidal,duration:1,fps:25,sync:false,from:0,to:1,delay:0,queue:"parallel"};
+MochiKit.Visual.Base=function(){
+};
+MochiKit.Visual.Base.prototype={__class__:MochiKit.Visual.Base,start:function(_65d){
+var v=MochiKit.Visual;
+this.options=MochiKit.Base.setdefault(_65d,v.DefaultOptions);
+this.currentFrame=0;
+this.state="idle";
+this.startOn=this.options.delay*1000;
+this.finishOn=this.startOn+(this.options.duration*1000);
+this.event("beforeStart");
+if(!this.options.sync){
+v.Queues.get(typeof (this.options.queue)=="string"?"global":this.options.queue.scope).add(this);
+}
+},loop:function(_65f){
+if(_65f>=this.startOn){
+if(_65f>=this.finishOn){
+return this.finalize();
+}
+var pos=(_65f-this.startOn)/(this.finishOn-this.startOn);
+var _661=Math.round(pos*this.options.fps*this.options.duration);
+if(_661>this.currentFrame){
+this.render(pos);
+this.currentFrame=_661;
+}
+}
+},render:function(pos){
+if(this.state=="idle"){
+this.state="running";
+this.event("beforeSetup");
+this.setup();
+this.event("afterSetup");
+}
+if(this.state=="running"){
+if(this.options.transition){
+pos=this.options.transition(pos);
+}
+pos*=(this.options.to-this.options.from);
+pos+=this.options.from;
+this.event("beforeUpdate");
+this.update(pos);
+this.event("afterUpdate");
+}
+},cancel:function(){
+if(!this.options.sync){
+MochiKit.Visual.Queues.get(typeof (this.options.queue)=="string"?"global":this.options.queue.scope).remove(this);
+}
+this.state="finished";
+},finalize:function(){
+this.render(1);
+this.cancel();
+this.event("beforeFinish");
+this.finish();
+this.event("afterFinish");
+},setup:function(){
+},finish:function(){
+},update:function(_663){
+},event:function(_664){
+if(this.options[_664+"Internal"]){
+this.options[_664+"Internal"](this);
+}
+if(this.options[_664]){
+this.options[_664](this);
+}
+},repr:function(){
+return "["+this.__class__.NAME+", options:"+MochiKit.Base.repr(this.options)+"]";
+}};
+MochiKit.Visual.Parallel=function(_665,_666){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_665,_666);
+}
+this.__init__(_665,_666);
+};
+MochiKit.Visual.Parallel.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Parallel.prototype,{__class__:MochiKit.Visual.Parallel,__init__:function(_668,_669){
+this.effects=_668||[];
+this.start(_669);
+},update:function(_66a){
+MochiKit.Base.map(function(_66b){
+_66b.render(_66a);
+},this.effects);
+},finish:function(){
+MochiKit.Base.map(function(_66c){
+_66c.finalize();
+},this.effects);
+}});
+MochiKit.Visual.Sequence=function(_66d,_66e){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_66d,_66e);
+}
+this.__init__(_66d,_66e);
+};
+MochiKit.Visual.Sequence.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Sequence.prototype,{__class__:MochiKit.Visual.Sequence,__init__:function(_670,_671){
+var defs={transition:MochiKit.Visual.Transitions.linear,duration:0};
+this.effects=_670||[];
+MochiKit.Base.map(function(_673){
+defs.duration+=_673.options.duration;
+},this.effects);
+MochiKit.Base.setdefault(_671,defs);
+this.start(_671);
+},update:function(_674){
+var time=_674*this.options.duration;
+for(var i=0;i<this.effects.length;i++){
+var _677=this.effects[i];
+if(time<=_677.options.duration){
+_677.render(time/_677.options.duration);
+break;
+}else{
+time-=_677.options.duration;
+}
+}
+},finish:function(){
+MochiKit.Base.map(function(_678){
+_678.finalize();
+},this.effects);
+}});
+MochiKit.Visual.Opacity=function(_679,_67a){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_679,_67a);
+}
+this.__init__(_679,_67a);
+};
+MochiKit.Visual.Opacity.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Opacity.prototype,{__class__:MochiKit.Visual.Opacity,__init__:function(_67c,_67d){
+var b=MochiKit.Base;
+var s=MochiKit.Style;
+this.element=MochiKit.DOM.getElement(_67c);
+if(this.element.currentStyle&&(!this.element.currentStyle.hasLayout)){
+s.setStyle(this.element,{zoom:1});
+}
+_67d=b.update({from:s.getStyle(this.element,"opacity")||0,to:1},_67d);
+this.start(_67d);
+},update:function(_680){
+MochiKit.Style.setStyle(this.element,{"opacity":_680});
+}});
+MochiKit.Visual.Move=function(_681,_682){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_681,_682);
+}
+this.__init__(_681,_682);
+};
+MochiKit.Visual.Move.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Move.prototype,{__class__:MochiKit.Visual.Move,__init__:function(_684,_685){
+this.element=MochiKit.DOM.getElement(_684);
+_685=MochiKit.Base.update({x:0,y:0,mode:"relative"},_685);
+this.start(_685);
+},setup:function(){
+MochiKit.Style.makePositioned(this.element);
+var s=this.element.style;
+var _687=s.visibility;
+var _688=s.display;
+if(_688=="none"){
+s.visibility="hidden";
+s.display="";
+}
+this.originalLeft=parseFloat(MochiKit.Style.getStyle(this.element,"left")||"0");
+this.originalTop=parseFloat(MochiKit.Style.getStyle(this.element,"top")||"0");
+if(this.options.mode=="absolute"){
+this.options.x-=this.originalLeft;
+this.options.y-=this.originalTop;
+}
+if(_688=="none"){
+s.visibility=_687;
+s.display=_688;
+}
+},update:function(_689){
+MochiKit.Style.setStyle(this.element,{left:Math.round(this.options.x*_689+this.originalLeft)+"px",top:Math.round(this.options.y*_689+this.originalTop)+"px"});
+}});
+MochiKit.Visual.Scale=function(_68a,_68b,_68c){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_68a,_68b,_68c);
+}
+this.__init__(_68a,_68b,_68c);
+};
+MochiKit.Visual.Scale.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Scale.prototype,{__class__:MochiKit.Visual.Scale,__init__:function(_68e,_68f,_690){
+this.element=MochiKit.DOM.getElement(_68e);
+_690=MochiKit.Base.update({scaleX:true,scaleY:true,scaleContent:true,scaleFromCenter:false,scaleMode:"box",scaleFrom:100,scaleTo:_68f},_690);
+this.start(_690);
+},setup:function(){
+this.restoreAfterFinish=this.options.restoreAfterFinish||false;
+this.elementPositioning=MochiKit.Style.getStyle(this.element,"position");
+var ma=MochiKit.Base.map;
+var b=MochiKit.Base.bind;
+this.originalStyle={};
+ma(b(function(k){
+this.originalStyle[k]=this.element.style[k];
+},this),["top","left","width","height","fontSize"]);
+this.originalTop=this.element.offsetTop;
+this.originalLeft=this.element.offsetLeft;
+var _694=MochiKit.Style.getStyle(this.element,"font-size")||"100%";
+ma(b(function(_695){
+if(_694.indexOf(_695)>0){
+this.fontSize=parseFloat(_694);
+this.fontSizeType=_695;
+}
+},this),["em","px","%"]);
+this.factor=(this.options.scaleTo-this.options.scaleFrom)/100;
+if(/^content/.test(this.options.scaleMode)){
+this.dims=[this.element.scrollHeight,this.element.scrollWidth];
+}else{
+if(this.options.scaleMode=="box"){
+this.dims=[this.element.offsetHeight,this.element.offsetWidth];
+}else{
+this.dims=[this.options.scaleMode.originalHeight,this.options.scaleMode.originalWidth];
+}
+}
+},update:function(_696){
+var _697=(this.options.scaleFrom/100)+(this.factor*_696);
+if(this.options.scaleContent&&this.fontSize){
+MochiKit.Style.setStyle(this.element,{fontSize:this.fontSize*_697+this.fontSizeType});
+}
+this.setDimensions(this.dims[0]*_697,this.dims[1]*_697);
+},finish:function(){
+if(this.restoreAfterFinish){
+MochiKit.Style.setStyle(this.element,this.originalStyle);
+}
+},setDimensions:function(_698,_699){
+var d={};
+var r=Math.round;
+if(/MSIE/.test(navigator.userAgent)){
+r=Math.ceil;
+}
+if(this.options.scaleX){
+d.width=r(_699)+"px";
+}
+if(this.options.scaleY){
+d.height=r(_698)+"px";
+}
+if(this.options.scaleFromCenter){
+var topd=(_698-this.dims[0])/2;
+var _69d=(_699-this.dims[1])/2;
+if(this.elementPositioning=="absolute"){
+if(this.options.scaleY){
+d.top=this.originalTop-topd+"px";
+}
+if(this.options.scaleX){
+d.left=this.originalLeft-_69d+"px";
+}
+}else{
+if(this.options.scaleY){
+d.top=-topd+"px";
+}
+if(this.options.scaleX){
+d.left=-_69d+"px";
+}
+}
+}
+MochiKit.Style.setStyle(this.element,d);
+}});
+MochiKit.Visual.Highlight=function(_69e,_69f){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_69e,_69f);
+}
+this.__init__(_69e,_69f);
+};
+MochiKit.Visual.Highlight.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Highlight.prototype,{__class__:MochiKit.Visual.Highlight,__init__:function(_6a1,_6a2){
+this.element=MochiKit.DOM.getElement(_6a1);
+_6a2=MochiKit.Base.update({startcolor:"#ffff99"},_6a2);
+this.start(_6a2);
+},setup:function(){
+var b=MochiKit.Base;
+var s=MochiKit.Style;
+if(s.getStyle(this.element,"display")=="none"){
+this.cancel();
+return;
+}
+this.oldStyle={backgroundImage:s.getStyle(this.element,"background-image")};
+s.setStyle(this.element,{backgroundImage:"none"});
+if(!this.options.endcolor){
+this.options.endcolor=MochiKit.Color.Color.fromBackground(this.element).toHexString();
+}
+if(b.isUndefinedOrNull(this.options.restorecolor)){
+this.options.restorecolor=s.getStyle(this.element,"background-color");
+}
+this._base=b.map(b.bind(function(i){
+return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16);
+},this),[0,1,2]);
+this._delta=b.map(b.bind(function(i){
+return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i];
+},this),[0,1,2]);
+},update:function(_6a7){
+var m="#";
+MochiKit.Base.map(MochiKit.Base.bind(function(i){
+m+=MochiKit.Color.toColorPart(Math.round(this._base[i]+this._delta[i]*_6a7));
+},this),[0,1,2]);
+MochiKit.Style.setStyle(this.element,{backgroundColor:m});
+},finish:function(){
+MochiKit.Style.setStyle(this.element,MochiKit.Base.update(this.oldStyle,{backgroundColor:this.options.restorecolor}));
+}});
+MochiKit.Visual.ScrollTo=function(_6aa,_6ab){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_6aa,_6ab);
+}
+this.__init__(_6aa,_6ab);
+};
+MochiKit.Visual.ScrollTo.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype,{__class__:MochiKit.Visual.ScrollTo,__init__:function(_6ad,_6ae){
+this.element=MochiKit.DOM.getElement(_6ad);
+this.start(_6ae);
+},setup:function(){
+var p=MochiKit.Position;
+p.prepare();
+var _6b0=p.cumulativeOffset(this.element);
+if(this.options.offset){
+_6b0.y+=this.options.offset;
+}
+var max;
+if(window.innerHeight){
+max=window.innerHeight-window.height;
+}else{
+if(document.documentElement&&document.documentElement.clientHeight){
+max=document.documentElement.clientHeight-document.body.scrollHeight;
+}else{
+if(document.body){
+max=document.body.clientHeight-document.body.scrollHeight;
+}
+}
+}
+this.scrollStart=p.windowOffset.y;
+this.delta=(_6b0.y>max?max:_6b0.y)-this.scrollStart;
+},update:function(_6b2){
+var p=MochiKit.Position;
+p.prepare();
+window.scrollTo(p.windowOffset.x,this.scrollStart+(_6b2*this.delta));
+}});
+MochiKit.Visual.CSS_LENGTH=/^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+MochiKit.Visual.Morph=function(_6b4,_6b5){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_6b4,_6b5);
+}
+this.__init__(_6b4,_6b5);
+};
+MochiKit.Visual.Morph.prototype=new MochiKit.Visual.Base();
+MochiKit.Base.update(MochiKit.Visual.Morph.prototype,{__class__:MochiKit.Visual.Morph,__init__:function(_6b7,_6b8){
+this.element=MochiKit.DOM.getElement(_6b7);
+this.start(_6b8);
+},setup:function(){
+var b=MochiKit.Base;
+var _6ba=this.options.style;
+this.styleStart={};
+this.styleEnd={};
+this.units={};
+var _6bb,unit;
+for(var s in _6ba){
+_6bb=_6ba[s];
+s=b.camelize(s);
+if(MochiKit.Visual.CSS_LENGTH.test(_6bb)){
+var _6be=_6bb.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+_6bb=parseFloat(_6be[1]);
+unit=(_6be.length==3)?_6be[2]:null;
+this.styleEnd[s]=_6bb;
+this.units[s]=unit;
+_6bb=MochiKit.Style.getStyle(this.element,s);
+_6be=_6bb.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+_6bb=parseFloat(_6be[1]);
+this.styleStart[s]=_6bb;
+}else{
+if(/[Cc]olor$/.test(s)){
+var c=MochiKit.Color.Color;
+_6bb=c.fromString(_6bb);
+if(_6bb){
+this.units[s]="color";
+this.styleEnd[s]=_6bb.toHexString();
+_6bb=MochiKit.Style.getStyle(this.element,s);
+this.styleStart[s]=c.fromString(_6bb).toHexString();
+this.styleStart[s]=b.map(b.bind(function(i){
+return parseInt(this.styleStart[s].slice(i*2+1,i*2+3),16);
+},this),[0,1,2]);
+this.styleEnd[s]=b.map(b.bind(function(i){
+return parseInt(this.styleEnd[s].slice(i*2+1,i*2+3),16);
+},this),[0,1,2]);
+}
+}else{
+this.element.style[s]=_6bb;
+}
+}
+}
+},update:function(_6c2){
+var _6c3;
+for(var s in this.styleStart){
+if(this.units[s]=="color"){
+var m="#";
+var _6c6=this.styleStart[s];
+var end=this.styleEnd[s];
+MochiKit.Base.map(MochiKit.Base.bind(function(i){
+m+=MochiKit.Color.toColorPart(Math.round(_6c6[i]+(end[i]-_6c6[i])*_6c2));
+},this),[0,1,2]);
+this.element.style[s]=m;
+}else{
+_6c3=this.styleStart[s]+Math.round((this.styleEnd[s]-this.styleStart[s])*_6c2*1000)/1000+this.units[s];
+this.element.style[s]=_6c3;
+}
+}
+}});
+MochiKit.Visual.fade=function(_6c9,_6ca){
+var s=MochiKit.Style;
+var _6cc=s.getStyle(_6c9,"opacity");
+_6ca=MochiKit.Base.update({from:s.getStyle(_6c9,"opacity")||1,to:0,afterFinishInternal:function(_6cd){
+if(_6cd.options.to!==0){
+return;
+}
+s.hideElement(_6cd.element);
+s.setStyle(_6cd.element,{"opacity":_6cc});
+}},_6ca);
+return new MochiKit.Visual.Opacity(_6c9,_6ca);
+};
+MochiKit.Visual.appear=function(_6ce,_6cf){
+var s=MochiKit.Style;
+var v=MochiKit.Visual;
+_6cf=MochiKit.Base.update({from:(s.getStyle(_6ce,"display")=="none"?0:s.getStyle(_6ce,"opacity")||0),to:1,afterFinishInternal:function(_6d2){
+v.forceRerendering(_6d2.element);
+},beforeSetupInternal:function(_6d3){
+s.setStyle(_6d3.element,{"opacity":_6d3.options.from});
+s.showElement(_6d3.element);
+}},_6cf);
+return new v.Opacity(_6ce,_6cf);
+};
+MochiKit.Visual.puff=function(_6d4,_6d5){
+var s=MochiKit.Style;
+var v=MochiKit.Visual;
+_6d4=MochiKit.DOM.getElement(_6d4);
+var _6d8=MochiKit.Style.getElementDimensions(_6d4,true);
+var _6d9={position:s.getStyle(_6d4,"position"),top:_6d4.style.top,left:_6d4.style.left,width:_6d4.style.width,height:_6d4.style.height,opacity:s.getStyle(_6d4,"opacity")};
+_6d5=MochiKit.Base.update({beforeSetupInternal:function(_6da){
+MochiKit.Position.absolutize(_6da.effects[0].element);
+},afterFinishInternal:function(_6db){
+s.hideElement(_6db.effects[0].element);
+s.setStyle(_6db.effects[0].element,_6d9);
+},scaleContent:true,scaleFromCenter:true},_6d5);
+return new v.Parallel([new v.Scale(_6d4,200,{sync:true,scaleFromCenter:_6d5.scaleFromCenter,scaleMode:{originalHeight:_6d8.h,originalWidth:_6d8.w},scaleContent:_6d5.scaleContent,restoreAfterFinish:true}),new v.Opacity(_6d4,{sync:true,to:0})],_6d5);
+};
+MochiKit.Visual.blindUp=function(_6dc,_6dd){
+var d=MochiKit.DOM;
+var s=MochiKit.Style;
+_6dc=d.getElement(_6dc);
+var _6e0=s.getElementDimensions(_6dc,true);
+var _6e1=s.makeClipping(_6dc);
+_6dd=MochiKit.Base.update({scaleContent:false,scaleX:false,scaleMode:{originalHeight:_6e0.h,originalWidth:_6e0.w},restoreAfterFinish:true,afterFinishInternal:function(_6e2){
+s.hideElement(_6e2.element);
+s.undoClipping(_6e2.element,_6e1);
+}},_6dd);
+return new MochiKit.Visual.Scale(_6dc,0,_6dd);
+};
+MochiKit.Visual.blindDown=function(_6e3,_6e4){
+var d=MochiKit.DOM;
+var s=MochiKit.Style;
+_6e3=d.getElement(_6e3);
+var _6e7=s.getElementDimensions(_6e3,true);
+var _6e8;
+_6e4=MochiKit.Base.update({scaleContent:false,scaleX:false,scaleFrom:0,scaleMode:{originalHeight:_6e7.h,originalWidth:_6e7.w},restoreAfterFinish:true,afterSetupInternal:function(_6e9){
+_6e8=s.makeClipping(_6e9.element);
+s.setStyle(_6e9.element,{height:"0px"});
+s.showElement(_6e9.element);
+},afterFinishInternal:function(_6ea){
+s.undoClipping(_6ea.element,_6e8);
+}},_6e4);
+return new MochiKit.Visual.Scale(_6e3,100,_6e4);
+};
+MochiKit.Visual.switchOff=function(_6eb,_6ec){
+var d=MochiKit.DOM;
+var s=MochiKit.Style;
+_6eb=d.getElement(_6eb);
+var _6ef=s.getElementDimensions(_6eb,true);
+var _6f0=s.getStyle(_6eb,"opacity");
+var _6f1;
+_6ec=MochiKit.Base.update({duration:0.7,restoreAfterFinish:true,beforeSetupInternal:function(_6f2){
+s.makePositioned(_6eb);
+_6f1=s.makeClipping(_6eb);
+},afterFinishInternal:function(_6f3){
+s.hideElement(_6eb);
+s.undoClipping(_6eb,_6f1);
+s.undoPositioned(_6eb);
+s.setStyle(_6eb,{"opacity":_6f0});
+}},_6ec);
+var v=MochiKit.Visual;
+return new v.Sequence([new v.appear(_6eb,{sync:true,duration:0.57*_6ec.duration,from:0,transition:v.Transitions.flicker}),new v.Scale(_6eb,1,{sync:true,duration:0.43*_6ec.duration,scaleFromCenter:true,scaleX:false,scaleMode:{originalHeight:_6ef.h,originalWidth:_6ef.w},scaleContent:false,restoreAfterFinish:true})],_6ec);
+};
+MochiKit.Visual.dropOut=function(_6f5,_6f6){
+var d=MochiKit.DOM;
+var s=MochiKit.Style;
+_6f5=d.getElement(_6f5);
+var _6f9={top:s.getStyle(_6f5,"top"),left:s.getStyle(_6f5,"left"),opacity:s.getStyle(_6f5,"opacity")};
+_6f6=MochiKit.Base.update({duration:0.5,distance:100,beforeSetupInternal:function(_6fa){
+s.makePositioned(_6fa.effects[0].element);
+},afterFinishInternal:function(_6fb){
+s.hideElement(_6fb.effects[0].element);
+s.undoPositioned(_6fb.effects[0].element);
+s.setStyle(_6fb.effects[0].element,_6f9);
+}},_6f6);
+var v=MochiKit.Visual;
+return new v.Parallel([new v.Move(_6f5,{x:0,y:_6f6.distance,sync:true}),new v.Opacity(_6f5,{sync:true,to:0})],_6f6);
+};
+MochiKit.Visual.shake=function(_6fd,_6fe){
+var d=MochiKit.DOM;
+var v=MochiKit.Visual;
+var s=MochiKit.Style;
+_6fd=d.getElement(_6fd);
+var _702={top:s.getStyle(_6fd,"top"),left:s.getStyle(_6fd,"left")};
+_6fe=MochiKit.Base.update({duration:0.5,afterFinishInternal:function(_703){
+s.undoPositioned(_6fd);
+s.setStyle(_6fd,_702);
+}},_6fe);
+return new v.Sequence([new v.Move(_6fd,{sync:true,duration:0.1*_6fe.duration,x:20,y:0}),new v.Move(_6fd,{sync:true,duration:0.2*_6fe.duration,x:-40,y:0}),new v.Move(_6fd,{sync:true,duration:0.2*_6fe.duration,x:40,y:0}),new v.Move(_6fd,{sync:true,duration:0.2*_6fe.duration,x:-40,y:0}),new v.Move(_6fd,{sync:true,duration:0.2*_6fe.duration,x:40,y:0}),new v.Move(_6fd,{sync:true,duration:0.1*_6fe.duration,x:-20,y:0})],_6fe);
+};
+MochiKit.Visual.slideDown=function(_704,_705){
+var d=MochiKit.DOM;
+var b=MochiKit.Base;
+var s=MochiKit.Style;
+_704=d.getElement(_704);
+if(!_704.firstChild){
+throw new Error("MochiKit.Visual.slideDown must be used on a element with a child");
+}
+d.removeEmptyTextNodes(_704);
+var _709=s.getStyle(_704.firstChild,"bottom")||0;
+var _70a=s.getElementDimensions(_704,true);
+var _70b;
+_705=b.update({scaleContent:false,scaleX:false,scaleFrom:0,scaleMode:{originalHeight:_70a.h,originalWidth:_70a.w},restoreAfterFinish:true,afterSetupInternal:function(_70c){
+s.makePositioned(_70c.element);
+s.makePositioned(_70c.element.firstChild);
+if(/Opera/.test(navigator.userAgent)){
+s.setStyle(_70c.element,{top:""});
+}
+_70b=s.makeClipping(_70c.element);
+s.setStyle(_70c.element,{height:"0px"});
+s.showElement(_70c.element);
+},afterUpdateInternal:function(_70d){
+var _70e=s.getElementDimensions(_70d.element,true);
+s.setStyle(_70d.element.firstChild,{bottom:(_70d.dims[0]-_70e.h)+"px"});
+},afterFinishInternal:function(_70f){
+s.undoClipping(_70f.element,_70b);
+if(/MSIE/.test(navigator.userAgent)){
+s.undoPositioned(_70f.element);
+s.undoPositioned(_70f.element.firstChild);
+}else{
+s.undoPositioned(_70f.element.firstChild);
+s.undoPositioned(_70f.element);
+}
+s.setStyle(_70f.element.firstChild,{bottom:_709});
+}},_705);
+return new MochiKit.Visual.Scale(_704,100,_705);
+};
+MochiKit.Visual.slideUp=function(_710,_711){
+var d=MochiKit.DOM;
+var b=MochiKit.Base;
+var s=MochiKit.Style;
+_710=d.getElement(_710);
+if(!_710.firstChild){
+throw new Error("MochiKit.Visual.slideUp must be used on a element with a child");
+}
+d.removeEmptyTextNodes(_710);
+var _715=s.getStyle(_710.firstChild,"bottom");
+var _716=s.getElementDimensions(_710,true);
+var _717;
+_711=b.update({scaleContent:false,scaleX:false,scaleMode:{originalHeight:_716.h,originalWidth:_716.w},scaleFrom:100,restoreAfterFinish:true,beforeStartInternal:function(_718){
+s.makePositioned(_718.element);
+s.makePositioned(_718.element.firstChild);
+if(/Opera/.test(navigator.userAgent)){
+s.setStyle(_718.element,{top:""});
+}
+_717=s.makeClipping(_718.element);
+s.showElement(_718.element);
+},afterUpdateInternal:function(_719){
+var _71a=s.getElementDimensions(_719.element,true);
+s.setStyle(_719.element.firstChild,{bottom:(_719.dims[0]-_71a.h)+"px"});
+},afterFinishInternal:function(_71b){
+s.hideElement(_71b.element);
+s.undoClipping(_71b.element,_717);
+s.undoPositioned(_71b.element.firstChild);
+s.undoPositioned(_71b.element);
+s.setStyle(_71b.element.firstChild,{bottom:_715});
+}},_711);
+return new MochiKit.Visual.Scale(_710,0,_711);
+};
+MochiKit.Visual.squish=function(_71c,_71d){
+var d=MochiKit.DOM;
+var b=MochiKit.Base;
+var s=MochiKit.Style;
+var _721=s.getElementDimensions(_71c,true);
+var _722;
+_71d=b.update({restoreAfterFinish:true,scaleMode:{originalHeight:_721.w,originalWidth:_721.h},beforeSetupInternal:function(_723){
+_722=s.makeClipping(_723.element);
+},afterFinishInternal:function(_724){
+s.hideElement(_724.element);
+s.undoClipping(_724.element,_722);
+}},_71d);
+return new MochiKit.Visual.Scale(_71c,/Opera/.test(navigator.userAgent)?1:0,_71d);
+};
+MochiKit.Visual.grow=function(_725,_726){
+var d=MochiKit.DOM;
+var v=MochiKit.Visual;
+var s=MochiKit.Style;
+_725=d.getElement(_725);
+_726=MochiKit.Base.update({direction:"center",moveTransition:v.Transitions.sinoidal,scaleTransition:v.Transitions.sinoidal,opacityTransition:v.Transitions.full,scaleContent:true,scaleFromCenter:false},_726);
+var _72a={top:_725.style.top,left:_725.style.left,height:_725.style.height,width:_725.style.width,opacity:s.getStyle(_725,"opacity")};
+var dims=s.getElementDimensions(_725,true);
+var _72c,_72d;
+var _72e,_72f;
+switch(_726.direction){
+case "top-left":
+_72c=_72d=_72e=_72f=0;
+break;
+case "top-right":
+_72c=dims.w;
+_72d=_72f=0;
+_72e=-dims.w;
+break;
+case "bottom-left":
+_72c=_72e=0;
+_72d=dims.h;
+_72f=-dims.h;
+break;
+case "bottom-right":
+_72c=dims.w;
+_72d=dims.h;
+_72e=-dims.w;
+_72f=-dims.h;
+break;
+case "center":
+_72c=dims.w/2;
+_72d=dims.h/2;
+_72e=-dims.w/2;
+_72f=-dims.h/2;
+break;
+}
+var _730=MochiKit.Base.update({beforeSetupInternal:function(_731){
+s.setStyle(_731.effects[0].element,{height:"0px"});
+s.showElement(_731.effects[0].element);
+},afterFinishInternal:function(_732){
+s.undoClipping(_732.effects[0].element);
+s.undoPositioned(_732.effects[0].element);
+s.setStyle(_732.effects[0].element,_72a);
+}},_726);
+return new v.Move(_725,{x:_72c,y:_72d,duration:0.01,beforeSetupInternal:function(_733){
+s.hideElement(_733.element);
+s.makeClipping(_733.element);
+s.makePositioned(_733.element);
+},afterFinishInternal:function(_734){
+new v.Parallel([new v.Opacity(_734.element,{sync:true,to:1,from:0,transition:_726.opacityTransition}),new v.Move(_734.element,{x:_72e,y:_72f,sync:true,transition:_726.moveTransition}),new v.Scale(_734.element,100,{scaleMode:{originalHeight:dims.h,originalWidth:dims.w},sync:true,scaleFrom:/Opera/.test(navigator.userAgent)?1:0,transition:_726.scaleTransition,scaleContent:_726.scaleContent,scaleFromCenter:_726.scaleFromCenter,restoreAfterFinish:true})],_730);
+}});
+};
+MochiKit.Visual.shrink=function(_735,_736){
+var d=MochiKit.DOM;
+var v=MochiKit.Visual;
+var s=MochiKit.Style;
+_735=d.getElement(_735);
+_736=MochiKit.Base.update({direction:"center",moveTransition:v.Transitions.sinoidal,scaleTransition:v.Transitions.sinoidal,opacityTransition:v.Transitions.none,scaleContent:true,scaleFromCenter:false},_736);
+var _73a={top:_735.style.top,left:_735.style.left,height:_735.style.height,width:_735.style.width,opacity:s.getStyle(_735,"opacity")};
+var dims=s.getElementDimensions(_735,true);
+var _73c,_73d;
+switch(_736.direction){
+case "top-left":
+_73c=_73d=0;
+break;
+case "top-right":
+_73c=dims.w;
+_73d=0;
+break;
+case "bottom-left":
+_73c=0;
+_73d=dims.h;
+break;
+case "bottom-right":
+_73c=dims.w;
+_73d=dims.h;
+break;
+case "center":
+_73c=dims.w/2;
+_73d=dims.h/2;
+break;
+}
+var _73e;
+var _73f=MochiKit.Base.update({beforeStartInternal:function(_740){
+s.makePositioned(_740.effects[0].element);
+_73e=s.makeClipping(_740.effects[0].element);
+},afterFinishInternal:function(_741){
+s.hideElement(_741.effects[0].element);
+s.undoClipping(_741.effects[0].element,_73e);
+s.undoPositioned(_741.effects[0].element);
+s.setStyle(_741.effects[0].element,_73a);
+}},_736);
+return new v.Parallel([new v.Opacity(_735,{sync:true,to:0,from:1,transition:_736.opacityTransition}),new v.Scale(_735,/Opera/.test(navigator.userAgent)?1:0,{scaleMode:{originalHeight:dims.h,originalWidth:dims.w},sync:true,transition:_736.scaleTransition,scaleContent:_736.scaleContent,scaleFromCenter:_736.scaleFromCenter,restoreAfterFinish:true}),new v.Move(_735,{x:_73c,y:_73d,sync:true,transition:_736.moveTransition})],_73f);
+};
+MochiKit.Visual.pulsate=function(_742,_743){
+var d=MochiKit.DOM;
+var v=MochiKit.Visual;
+var b=MochiKit.Base;
+var _747=MochiKit.Style.getStyle(_742,"opacity");
+_743=b.update({duration:3,from:0,afterFinishInternal:function(_748){
+MochiKit.Style.setStyle(_748.element,{"opacity":_747});
+}},_743);
+var _749=_743.transition||v.Transitions.sinoidal;
+_743.transition=function(pos){
+return _749(1-v.Transitions.pulse(pos,_743.pulses));
+};
+return new v.Opacity(_742,_743);
+};
+MochiKit.Visual.fold=function(_74b,_74c){
+var d=MochiKit.DOM;
+var v=MochiKit.Visual;
+var s=MochiKit.Style;
+_74b=d.getElement(_74b);
+var _750=s.getElementDimensions(_74b,true);
+var _751={top:_74b.style.top,left:_74b.style.left,width:_74b.style.width,height:_74b.style.height};
+var _752=s.makeClipping(_74b);
+_74c=MochiKit.Base.update({scaleContent:false,scaleX:false,scaleMode:{originalHeight:_750.h,originalWidth:_750.w},afterFinishInternal:function(_753){
+new v.Scale(_74b,1,{scaleContent:false,scaleY:false,scaleMode:{originalHeight:_750.h,originalWidth:_750.w},afterFinishInternal:function(_754){
+s.hideElement(_754.element);
+s.undoClipping(_754.element,_752);
+s.setStyle(_754.element,_751);
+}});
+}},_74c);
+return new v.Scale(_74b,5,_74c);
+};
+MochiKit.Visual.Color=MochiKit.Color.Color;
+MochiKit.Visual.getElementsComputedStyle=MochiKit.DOM.computedStyle;
+MochiKit.Visual.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+MochiKit.Visual.EXPORT=["roundElement","roundClass","tagifyText","multiple","toggle","Parallel","Sequence","Opacity","Move","Scale","Highlight","ScrollTo","Morph","fade","appear","puff","blindUp","blindDown","switchOff","dropOut","shake","slideDown","slideUp","squish","grow","shrink","pulsate","fold"];
+MochiKit.Visual.EXPORT_OK=["Base","PAIRS"];
+MochiKit.Visual.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Visual);
+MochiKit.Base._deps("DragAndDrop",["Base","Iter","DOM","Signal","Visual","Position"]);
+MochiKit.DragAndDrop.NAME="MochiKit.DragAndDrop";
+MochiKit.DragAndDrop.VERSION="1.4.2";
+MochiKit.DragAndDrop.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.DragAndDrop.toString=function(){
+return this.__repr__();
+};
+MochiKit.DragAndDrop.EXPORT=["Droppable","Draggable"];
+MochiKit.DragAndDrop.EXPORT_OK=["Droppables","Draggables"];
+MochiKit.DragAndDrop.Droppables={drops:[],remove:function(_756){
+this.drops=MochiKit.Base.filter(function(d){
+return d.element!=MochiKit.DOM.getElement(_756);
+},this.drops);
+},register:function(drop){
+this.drops.push(drop);
+},unregister:function(drop){
+this.drops=MochiKit.Base.filter(function(d){
+return d!=drop;
+},this.drops);
+},prepare:function(_75b){
+MochiKit.Base.map(function(drop){
+if(drop.isAccepted(_75b)){
+if(drop.options.activeclass){
+MochiKit.DOM.addElementClass(drop.element,drop.options.activeclass);
+}
+drop.options.onactive(drop.element,_75b);
+}
+},this.drops);
+},findDeepestChild:function(_75d){
+deepest=_75d[0];
+for(i=1;i<_75d.length;++i){
+if(MochiKit.DOM.isChildNode(_75d[i].element,deepest.element)){
+deepest=_75d[i];
+}
+}
+return deepest;
+},show:function(_75e,_75f){
+if(!this.drops.length){
+return;
+}
+var _760=[];
+if(this.last_active){
+this.last_active.deactivate();
+}
+MochiKit.Iter.forEach(this.drops,function(drop){
+if(drop.isAffected(_75e,_75f)){
+_760.push(drop);
+}
+});
+if(_760.length>0){
+drop=this.findDeepestChild(_760);
+MochiKit.Position.within(drop.element,_75e.page.x,_75e.page.y);
+drop.options.onhover(_75f,drop.element,MochiKit.Position.overlap(drop.options.overlap,drop.element));
+drop.activate();
+}
+},fire:function(_762,_763){
+if(!this.last_active){
+return;
+}
+MochiKit.Position.prepare();
+if(this.last_active.isAffected(_762.mouse(),_763)){
+this.last_active.options.ondrop(_763,this.last_active.element,_762);
+}
+},reset:function(_764){
+MochiKit.Base.map(function(drop){
+if(drop.options.activeclass){
+MochiKit.DOM.removeElementClass(drop.element,drop.options.activeclass);
+}
+drop.options.ondesactive(drop.element,_764);
+},this.drops);
+if(this.last_active){
+this.last_active.deactivate();
+}
+}};
+MochiKit.DragAndDrop.Droppable=function(_766,_767){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_766,_767);
+}
+this.__init__(_766,_767);
+};
+MochiKit.DragAndDrop.Droppable.prototype={__class__:MochiKit.DragAndDrop.Droppable,__init__:function(_769,_76a){
+var d=MochiKit.DOM;
+var b=MochiKit.Base;
+this.element=d.getElement(_769);
+this.options=b.update({greedy:true,hoverclass:null,activeclass:null,hoverfunc:b.noop,accept:null,onactive:b.noop,ondesactive:b.noop,onhover:b.noop,ondrop:b.noop,containment:[],tree:false},_76a);
+this.options._containers=[];
+b.map(MochiKit.Base.bind(function(c){
+this.options._containers.push(d.getElement(c));
+},this),this.options.containment);
+MochiKit.Style.makePositioned(this.element);
+MochiKit.DragAndDrop.Droppables.register(this);
+},isContained:function(_76e){
+if(this.options._containers.length){
+var _76f;
+if(this.options.tree){
+_76f=_76e.treeNode;
+}else{
+_76f=_76e.parentNode;
+}
+return MochiKit.Iter.some(this.options._containers,function(c){
+return _76f==c;
+});
+}else{
+return true;
+}
+},isAccepted:function(_771){
+return ((!this.options.accept)||MochiKit.Iter.some(this.options.accept,function(c){
+return MochiKit.DOM.hasElementClass(_771,c);
+}));
+},isAffected:function(_773,_774){
+return ((this.element!=_774)&&this.isContained(_774)&&this.isAccepted(_774)&&MochiKit.Position.within(this.element,_773.page.x,_773.page.y));
+},deactivate:function(){
+if(this.options.hoverclass){
+MochiKit.DOM.removeElementClass(this.element,this.options.hoverclass);
+}
+this.options.hoverfunc(this.element,false);
+MochiKit.DragAndDrop.Droppables.last_active=null;
+},activate:function(){
+if(this.options.hoverclass){
+MochiKit.DOM.addElementClass(this.element,this.options.hoverclass);
+}
+this.options.hoverfunc(this.element,true);
+MochiKit.DragAndDrop.Droppables.last_active=this;
+},destroy:function(){
+MochiKit.DragAndDrop.Droppables.unregister(this);
+},repr:function(){
+return "["+this.__class__.NAME+", options:"+MochiKit.Base.repr(this.options)+"]";
+}};
+MochiKit.DragAndDrop.Draggables={drags:[],register:function(_775){
+if(this.drags.length===0){
+var conn=MochiKit.Signal.connect;
+this.eventMouseUp=conn(document,"onmouseup",this,this.endDrag);
+this.eventMouseMove=conn(document,"onmousemove",this,this.updateDrag);
+this.eventKeypress=conn(document,"onkeypress",this,this.keyPress);
+}
+this.drags.push(_775);
+},unregister:function(_777){
+this.drags=MochiKit.Base.filter(function(d){
+return d!=_777;
+},this.drags);
+if(this.drags.length===0){
+var disc=MochiKit.Signal.disconnect;
+disc(this.eventMouseUp);
+disc(this.eventMouseMove);
+disc(this.eventKeypress);
+}
+},activate:function(_77a){
+window.focus();
+this.activeDraggable=_77a;
+},deactivate:function(){
+this.activeDraggable=null;
+},updateDrag:function(_77b){
+if(!this.activeDraggable){
+return;
+}
+var _77c=_77b.mouse();
+if(this._lastPointer&&(MochiKit.Base.repr(this._lastPointer.page)==MochiKit.Base.repr(_77c.page))){
+return;
+}
+this._lastPointer=_77c;
+this.activeDraggable.updateDrag(_77b,_77c);
+},endDrag:function(_77d){
+if(!this.activeDraggable){
+return;
+}
+this._lastPointer=null;
+this.activeDraggable.endDrag(_77d);
+this.activeDraggable=null;
+},keyPress:function(_77e){
+if(this.activeDraggable){
+this.activeDraggable.keyPress(_77e);
+}
+},notify:function(_77f,_780,_781){
+MochiKit.Signal.signal(this,_77f,_780,_781);
+}};
+MochiKit.DragAndDrop.Draggable=function(_782,_783){
+var cls=arguments.callee;
+if(!(this instanceof cls)){
+return new cls(_782,_783);
+}
+this.__init__(_782,_783);
+};
+MochiKit.DragAndDrop.Draggable.prototype={__class__:MochiKit.DragAndDrop.Draggable,__init__:function(_785,_786){
+var v=MochiKit.Visual;
+var b=MochiKit.Base;
+_786=b.update({handle:false,starteffect:function(_789){
+this._savedOpacity=MochiKit.Style.getStyle(_789,"opacity")||1;
+new v.Opacity(_789,{duration:0.2,from:this._savedOpacity,to:0.7});
+},reverteffect:function(_78a,_78b,_78c){
+var dur=Math.sqrt(Math.abs(_78b^2)+Math.abs(_78c^2))*0.02;
+return new v.Move(_78a,{x:-_78c,y:-_78b,duration:dur});
+},endeffect:function(_78e){
+new v.Opacity(_78e,{duration:0.2,from:0.7,to:this._savedOpacity});
+},onchange:b.noop,zindex:1000,revert:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,snap:false},_786);
+var d=MochiKit.DOM;
+this.element=d.getElement(_785);
+if(_786.handle&&(typeof (_786.handle)=="string")){
+this.handle=d.getFirstElementByTagAndClassName(null,_786.handle,this.element);
+}
+if(!this.handle){
+this.handle=d.getElement(_786.handle);
+}
+if(!this.handle){
+this.handle=this.element;
+}
+if(_786.scroll&&!_786.scroll.scrollTo&&!_786.scroll.outerHTML){
+_786.scroll=d.getElement(_786.scroll);
+this._isScrollChild=MochiKit.DOM.isChildNode(this.element,_786.scroll);
+}
+MochiKit.Style.makePositioned(this.element);
+this.delta=this.currentDelta();
+this.options=_786;
+this.dragging=false;
+this.eventMouseDown=MochiKit.Signal.connect(this.handle,"onmousedown",this,this.initDrag);
+MochiKit.DragAndDrop.Draggables.register(this);
+},destroy:function(){
+MochiKit.Signal.disconnect(this.eventMouseDown);
+MochiKit.DragAndDrop.Draggables.unregister(this);
+},currentDelta:function(){
+var s=MochiKit.Style.getStyle;
+return [parseInt(s(this.element,"left")||"0"),parseInt(s(this.element,"top")||"0")];
+},initDrag:function(_791){
+if(!_791.mouse().button.left){
+return;
+}
+var src=_791.target();
+var _793=(src.tagName||"").toUpperCase();
+if(_793==="INPUT"||_793==="SELECT"||_793==="OPTION"||_793==="BUTTON"||_793==="TEXTAREA"){
+return;
+}
+if(this._revert){
+this._revert.cancel();
+this._revert=null;
+}
+var _794=_791.mouse();
+var pos=MochiKit.Position.cumulativeOffset(this.element);
+this.offset=[_794.page.x-pos.x,_794.page.y-pos.y];
+MochiKit.DragAndDrop.Draggables.activate(this);
+_791.stop();
+},startDrag:function(_796){
+this.dragging=true;
+if(this.options.selectclass){
+MochiKit.DOM.addElementClass(this.element,this.options.selectclass);
+}
+if(this.options.zindex){
+this.originalZ=parseInt(MochiKit.Style.getStyle(this.element,"z-index")||"0");
+this.element.style.zIndex=this.options.zindex;
+}
+if(this.options.ghosting){
+this._clone=this.element.cloneNode(true);
+this.ghostPosition=MochiKit.Position.absolutize(this.element);
+this.element.parentNode.insertBefore(this._clone,this.element);
+}
+if(this.options.scroll){
+if(this.options.scroll==window){
+var _797=this._getWindowScroll(this.options.scroll);
+this.originalScrollLeft=_797.left;
+this.originalScrollTop=_797.top;
+}else{
+this.originalScrollLeft=this.options.scroll.scrollLeft;
+this.originalScrollTop=this.options.scroll.scrollTop;
+}
+}
+MochiKit.DragAndDrop.Droppables.prepare(this.element);
+MochiKit.DragAndDrop.Draggables.notify("start",this,_796);
+if(this.options.starteffect){
+this.options.starteffect(this.element);
+}
+},updateDrag:function(_798,_799){
+if(!this.dragging){
+this.startDrag(_798);
+}
+MochiKit.Position.prepare();
+MochiKit.DragAndDrop.Droppables.show(_799,this.element);
+MochiKit.DragAndDrop.Draggables.notify("drag",this,_798);
+this.draw(_799);
+this.options.onchange(this);
+if(this.options.scroll){
+this.stopScrolling();
+var p,q;
+if(this.options.scroll==window){
+var s=this._getWindowScroll(this.options.scroll);
+p=new MochiKit.Style.Coordinates(s.left,s.top);
+q=new MochiKit.Style.Coordinates(s.left+s.width,s.top+s.height);
+}else{
+p=MochiKit.Position.page(this.options.scroll);
+p.x+=this.options.scroll.scrollLeft;
+p.y+=this.options.scroll.scrollTop;
+p.x+=(window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0);
+p.y+=(window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0);
+q=new MochiKit.Style.Coordinates(p.x+this.options.scroll.offsetWidth,p.y+this.options.scroll.offsetHeight);
+}
+var _79d=[0,0];
+if(_799.page.x>(q.x-this.options.scrollSensitivity)){
+_79d[0]=_799.page.x-(q.x-this.options.scrollSensitivity);
+}else{
+if(_799.page.x<(p.x+this.options.scrollSensitivity)){
+_79d[0]=_799.page.x-(p.x+this.options.scrollSensitivity);
+}
+}
+if(_799.page.y>(q.y-this.options.scrollSensitivity)){
+_79d[1]=_799.page.y-(q.y-this.options.scrollSensitivity);
+}else{
+if(_799.page.y<(p.y+this.options.scrollSensitivity)){
+_79d[1]=_799.page.y-(p.y+this.options.scrollSensitivity);
+}
+}
+this.startScrolling(_79d);
+}
+if(/AppleWebKit/.test(navigator.appVersion)){
+window.scrollBy(0,0);
+}
+_798.stop();
+},finishDrag:function(_79e,_79f){
+var dr=MochiKit.DragAndDrop;
+this.dragging=false;
+if(this.options.selectclass){
+MochiKit.DOM.removeElementClass(this.element,this.options.selectclass);
+}
+if(this.options.ghosting){
+MochiKit.Position.relativize(this.element,this.ghostPosition);
+MochiKit.DOM.removeElement(this._clone);
+this._clone=null;
+}
+if(_79f){
+dr.Droppables.fire(_79e,this.element);
+}
+dr.Draggables.notify("end",this,_79e);
+var _7a1=this.options.revert;
+if(_7a1&&typeof (_7a1)=="function"){
+_7a1=_7a1(this.element);
+}
+var d=this.currentDelta();
+if(_7a1&&this.options.reverteffect){
+this._revert=this.options.reverteffect(this.element,d[1]-this.delta[1],d[0]-this.delta[0]);
+}else{
+this.delta=d;
+}
+if(this.options.zindex){
+this.element.style.zIndex=this.originalZ;
+}
+if(this.options.endeffect){
+this.options.endeffect(this.element);
+}
+dr.Draggables.deactivate();
+dr.Droppables.reset(this.element);
+},keyPress:function(_7a3){
+if(_7a3.key().string!="KEY_ESCAPE"){
+return;
+}
+this.finishDrag(_7a3,false);
+_7a3.stop();
+},endDrag:function(_7a4){
+if(!this.dragging){
+return;
+}
+this.stopScrolling();
+this.finishDrag(_7a4,true);
+_7a4.stop();
+},draw:function(_7a5){
+var pos=MochiKit.Position.cumulativeOffset(this.element);
+var d=this.currentDelta();
+pos.x-=d[0];
+pos.y-=d[1];
+if(this.options.scroll&&(this.options.scroll!=window&&this._isScrollChild)){
+pos.x-=this.options.scroll.scrollLeft-this.originalScrollLeft;
+pos.y-=this.options.scroll.scrollTop-this.originalScrollTop;
+}
+var p=[_7a5.page.x-pos.x-this.offset[0],_7a5.page.y-pos.y-this.offset[1]];
+if(this.options.snap){
+if(typeof (this.options.snap)=="function"){
+p=this.options.snap(p[0],p[1]);
+}else{
+if(this.options.snap instanceof Array){
+var i=-1;
+p=MochiKit.Base.map(MochiKit.Base.bind(function(v){
+i+=1;
+return Math.round(v/this.options.snap[i])*this.options.snap[i];
+},this),p);
+}else{
+p=MochiKit.Base.map(MochiKit.Base.bind(function(v){
+return Math.round(v/this.options.snap)*this.options.snap;
+},this),p);
+}
+}
+}
+var _7ac=this.element.style;
+if((!this.options.constraint)||(this.options.constraint=="horizontal")){
+_7ac.left=p[0]+"px";
+}
+if((!this.options.constraint)||(this.options.constraint=="vertical")){
+_7ac.top=p[1]+"px";
+}
+if(_7ac.visibility=="hidden"){
+_7ac.visibility="";
+}
+},stopScrolling:function(){
+if(this.scrollInterval){
+clearInterval(this.scrollInterval);
+this.scrollInterval=null;
+MochiKit.DragAndDrop.Draggables._lastScrollPointer=null;
+}
+},startScrolling:function(_7ad){
+if(!_7ad[0]&&!_7ad[1]){
+return;
+}
+this.scrollSpeed=[_7ad[0]*this.options.scrollSpeed,_7ad[1]*this.options.scrollSpeed];
+this.lastScrolled=new Date();
+this.scrollInterval=setInterval(MochiKit.Base.bind(this.scroll,this),10);
+},scroll:function(){
+var _7ae=new Date();
+var _7af=_7ae-this.lastScrolled;
+this.lastScrolled=_7ae;
+if(this.options.scroll==window){
+var s=this._getWindowScroll(this.options.scroll);
+if(this.scrollSpeed[0]||this.scrollSpeed[1]){
+var dm=_7af/1000;
+this.options.scroll.scrollTo(s.left+dm*this.scrollSpeed[0],s.top+dm*this.scrollSpeed[1]);
+}
+}else{
+this.options.scroll.scrollLeft+=this.scrollSpeed[0]*_7af/1000;
+this.options.scroll.scrollTop+=this.scrollSpeed[1]*_7af/1000;
+}
+var d=MochiKit.DragAndDrop;
+MochiKit.Position.prepare();
+d.Droppables.show(d.Draggables._lastPointer,this.element);
+d.Draggables.notify("drag",this);
+if(this._isScrollChild){
+d.Draggables._lastScrollPointer=d.Draggables._lastScrollPointer||d.Draggables._lastPointer;
+d.Draggables._lastScrollPointer.x+=this.scrollSpeed[0]*_7af/1000;
+d.Draggables._lastScrollPointer.y+=this.scrollSpeed[1]*_7af/1000;
+if(d.Draggables._lastScrollPointer.x<0){
+d.Draggables._lastScrollPointer.x=0;
+}
+if(d.Draggables._lastScrollPointer.y<0){
+d.Draggables._lastScrollPointer.y=0;
+}
+this.draw(d.Draggables._lastScrollPointer);
+}
+this.options.onchange(this);
+},_getWindowScroll:function(win){
+var vp,w,h;
+MochiKit.DOM.withWindow(win,function(){
+vp=MochiKit.Style.getViewportPosition(win.document);
+});
+if(win.innerWidth){
+w=win.innerWidth;
+h=win.innerHeight;
+}else{
+if(win.document.documentElement&&win.document.documentElement.clientWidth){
+w=win.document.documentElement.clientWidth;
+h=win.document.documentElement.clientHeight;
+}else{
+w=win.document.body.offsetWidth;
+h=win.document.body.offsetHeight;
+}
+}
+return {top:vp.y,left:vp.x,width:w,height:h};
+},repr:function(){
+return "["+this.__class__.NAME+", options:"+MochiKit.Base.repr(this.options)+"]";
+}};
+MochiKit.DragAndDrop.__new__=function(){
+MochiKit.Base.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":MochiKit.Base.concat(this.EXPORT,this.EXPORT_OK)};
+};
+MochiKit.DragAndDrop.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.DragAndDrop);
+MochiKit.Base._deps("Sortable",["Base","Iter","DOM","Position","DragAndDrop"]);
+MochiKit.Sortable.NAME="MochiKit.Sortable";
+MochiKit.Sortable.VERSION="1.4.2";
+MochiKit.Sortable.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Sortable.toString=function(){
+return this.__repr__();
+};
+MochiKit.Sortable.EXPORT=[];
+MochiKit.Sortable.EXPORT_OK=[];
+MochiKit.Base.update(MochiKit.Sortable,{sortables:{},_findRootElement:function(_7b7){
+while(_7b7.tagName.toUpperCase()!="BODY"){
+if(_7b7.id&&MochiKit.Sortable.sortables[_7b7.id]){
+return _7b7;
+}
+_7b7=_7b7.parentNode;
+}
+},_createElementId:function(_7b8){
+if(_7b8.id==null||_7b8.id==""){
+var d=MochiKit.DOM;
+var id;
+var _7bb=1;
+while(d.getElement(id="sortable"+_7bb)!=null){
+_7bb+=1;
+}
+d.setNodeAttribute(_7b8,"id",id);
+}
+},options:function(_7bc){
+_7bc=MochiKit.Sortable._findRootElement(MochiKit.DOM.getElement(_7bc));
+if(!_7bc){
+return;
+}
+return MochiKit.Sortable.sortables[_7bc.id];
+},destroy:function(_7bd){
+var s=MochiKit.Sortable.options(_7bd);
+var b=MochiKit.Base;
+var d=MochiKit.DragAndDrop;
+if(s){
+MochiKit.Signal.disconnect(s.startHandle);
+MochiKit.Signal.disconnect(s.endHandle);
+b.map(function(dr){
+d.Droppables.remove(dr);
+},s.droppables);
+b.map(function(dr){
+dr.destroy();
+},s.draggables);
+delete MochiKit.Sortable.sortables[s.element.id];
+}
+},create:function(_7c3,_7c4){
+_7c3=MochiKit.DOM.getElement(_7c3);
+var self=MochiKit.Sortable;
+self._createElementId(_7c3);
+_7c4=MochiKit.Base.update({element:_7c3,tag:"li",dropOnEmpty:false,tree:false,treeTag:"ul",overlap:"vertical",constraint:"vertical",containment:[_7c3],handle:false,only:false,hoverclass:null,ghosting:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,format:/^[^_]*_(.*)$/,onChange:MochiKit.Base.noop,onUpdate:MochiKit.Base.noop,accept:null},_7c4);
+self.destroy(_7c3);
+var _7c6={revert:true,ghosting:_7c4.ghosting,scroll:_7c4.scroll,scrollSensitivity:_7c4.scrollSensitivity,scrollSpeed:_7c4.scrollSpeed,constraint:_7c4.constraint,handle:_7c4.handle};
+if(_7c4.starteffect){
+_7c6.starteffect=_7c4.starteffect;
+}
+if(_7c4.reverteffect){
+_7c6.reverteffect=_7c4.reverteffect;
+}else{
+if(_7c4.ghosting){
+_7c6.reverteffect=function(_7c7){
+_7c7.style.top=0;
+_7c7.style.left=0;
+};
+}
+}
+if(_7c4.endeffect){
+_7c6.endeffect=_7c4.endeffect;
+}
+if(_7c4.zindex){
+_7c6.zindex=_7c4.zindex;
+}
+var _7c8={overlap:_7c4.overlap,containment:_7c4.containment,hoverclass:_7c4.hoverclass,onhover:self.onHover,tree:_7c4.tree,accept:_7c4.accept};
+var _7c9={onhover:self.onEmptyHover,overlap:_7c4.overlap,containment:_7c4.containment,hoverclass:_7c4.hoverclass,accept:_7c4.accept};
+MochiKit.DOM.removeEmptyTextNodes(_7c3);
+_7c4.draggables=[];
+_7c4.droppables=[];
+if(_7c4.dropOnEmpty||_7c4.tree){
+new MochiKit.DragAndDrop.Droppable(_7c3,_7c9);
+_7c4.droppables.push(_7c3);
+}
+MochiKit.Base.map(function(e){
+var _7cb=_7c4.handle?MochiKit.DOM.getFirstElementByTagAndClassName(null,_7c4.handle,e):e;
+_7c4.draggables.push(new MochiKit.DragAndDrop.Draggable(e,MochiKit.Base.update(_7c6,{handle:_7cb})));
+new MochiKit.DragAndDrop.Droppable(e,_7c8);
+if(_7c4.tree){
+e.treeNode=_7c3;
+}
+_7c4.droppables.push(e);
+},(self.findElements(_7c3,_7c4)||[]));
+if(_7c4.tree){
+MochiKit.Base.map(function(e){
+new MochiKit.DragAndDrop.Droppable(e,_7c9);
+e.treeNode=_7c3;
+_7c4.droppables.push(e);
+},(self.findTreeElements(_7c3,_7c4)||[]));
+}
+self.sortables[_7c3.id]=_7c4;
+_7c4.lastValue=self.serialize(_7c3);
+_7c4.startHandle=MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables,"start",MochiKit.Base.partial(self.onStart,_7c3));
+_7c4.endHandle=MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables,"end",MochiKit.Base.partial(self.onEnd,_7c3));
+},onStart:function(_7cd,_7ce){
+var self=MochiKit.Sortable;
+var _7d0=self.options(_7cd);
+_7d0.lastValue=self.serialize(_7d0.element);
+},onEnd:function(_7d1,_7d2){
+var self=MochiKit.Sortable;
+self.unmark();
+var _7d4=self.options(_7d1);
+if(_7d4.lastValue!=self.serialize(_7d4.element)){
+_7d4.onUpdate(_7d4.element);
+}
+},findElements:function(_7d5,_7d6){
+return MochiKit.Sortable.findChildren(_7d5,_7d6.only,_7d6.tree,_7d6.tag);
+},findTreeElements:function(_7d7,_7d8){
+return MochiKit.Sortable.findChildren(_7d7,_7d8.only,_7d8.tree?true:false,_7d8.treeTag);
+},findChildren:function(_7d9,only,_7db,_7dc){
+if(!_7d9.hasChildNodes()){
+return null;
+}
+_7dc=_7dc.toUpperCase();
+if(only){
+only=MochiKit.Base.flattenArray([only]);
+}
+var _7dd=[];
+MochiKit.Base.map(function(e){
+if(e.tagName&&e.tagName.toUpperCase()==_7dc&&(!only||MochiKit.Iter.some(only,function(c){
+return MochiKit.DOM.hasElementClass(e,c);
+}))){
+_7dd.push(e);
+}
+if(_7db){
+var _7e0=MochiKit.Sortable.findChildren(e,only,_7db,_7dc);
+if(_7e0&&_7e0.length>0){
+_7dd=_7dd.concat(_7e0);
+}
+}
+},_7d9.childNodes);
+return _7dd;
+},onHover:function(_7e1,_7e2,_7e3){
+if(MochiKit.DOM.isChildNode(_7e2,_7e1)){
+return;
+}
+var self=MochiKit.Sortable;
+if(_7e3>0.33&&_7e3<0.66&&self.options(_7e2).tree){
+return;
+}else{
+if(_7e3>0.5){
+self.mark(_7e2,"before");
+if(_7e2.previousSibling!=_7e1){
+var _7e5=_7e1.parentNode;
+_7e1.style.visibility="hidden";
+_7e2.parentNode.insertBefore(_7e1,_7e2);
+if(_7e2.parentNode!=_7e5){
+self.options(_7e5).onChange(_7e1);
+}
+self.options(_7e2.parentNode).onChange(_7e1);
+}
+}else{
+self.mark(_7e2,"after");
+var _7e6=_7e2.nextSibling||null;
+if(_7e6!=_7e1){
+var _7e5=_7e1.parentNode;
+_7e1.style.visibility="hidden";
+_7e2.parentNode.insertBefore(_7e1,_7e6);
+if(_7e2.parentNode!=_7e5){
+self.options(_7e5).onChange(_7e1);
+}
+self.options(_7e2.parentNode).onChange(_7e1);
+}
+}
+}
+},_offsetSize:function(_7e7,type){
+if(type=="vertical"||type=="height"){
+return _7e7.offsetHeight;
+}else{
+return _7e7.offsetWidth;
+}
+},onEmptyHover:function(_7e9,_7ea,_7eb){
+var _7ec=_7e9.parentNode;
+var self=MochiKit.Sortable;
+var _7ee=self.options(_7ea);
+if(!MochiKit.DOM.isChildNode(_7ea,_7e9)){
+var _7ef;
+var _7f0=self.findElements(_7ea,{tag:_7ee.tag,only:_7ee.only});
+var _7f1=null;
+if(_7f0){
+var _7f2=self._offsetSize(_7ea,_7ee.overlap)*(1-_7eb);
+for(_7ef=0;_7ef<_7f0.length;_7ef+=1){
+if(_7f2-self._offsetSize(_7f0[_7ef],_7ee.overlap)>=0){
+_7f2-=self._offsetSize(_7f0[_7ef],_7ee.overlap);
+}else{
+if(_7f2-(self._offsetSize(_7f0[_7ef],_7ee.overlap)/2)>=0){
+_7f1=_7ef+1<_7f0.length?_7f0[_7ef+1]:null;
+break;
+}else{
+_7f1=_7f0[_7ef];
+break;
+}
+}
+}
+}
+_7ea.insertBefore(_7e9,_7f1);
+self.options(_7ec).onChange(_7e9);
+_7ee.onChange(_7e9);
+}
+},unmark:function(){
+var m=MochiKit.Sortable._marker;
+if(m){
+MochiKit.Style.hideElement(m);
+}
+},mark:function(_7f4,_7f5){
+var d=MochiKit.DOM;
+var self=MochiKit.Sortable;
+var _7f8=self.options(_7f4.parentNode);
+if(_7f8&&!_7f8.ghosting){
+return;
+}
+if(!self._marker){
+self._marker=d.getElement("dropmarker")||document.createElement("DIV");
+MochiKit.Style.hideElement(self._marker);
+d.addElementClass(self._marker,"dropmarker");
+self._marker.style.position="absolute";
+document.getElementsByTagName("body").item(0).appendChild(self._marker);
+}
+var _7f9=MochiKit.Position.cumulativeOffset(_7f4);
+self._marker.style.left=_7f9.x+"px";
+self._marker.style.top=_7f9.y+"px";
+if(_7f5=="after"){
+if(_7f8.overlap=="horizontal"){
+self._marker.style.left=(_7f9.x+_7f4.clientWidth)+"px";
+}else{
+self._marker.style.top=(_7f9.y+_7f4.clientHeight)+"px";
+}
+}
+MochiKit.Style.showElement(self._marker);
+},_tree:function(_7fa,_7fb,_7fc){
+var self=MochiKit.Sortable;
+var _7fe=self.findElements(_7fa,_7fb)||[];
+for(var i=0;i<_7fe.length;++i){
+var _800=_7fe[i].id.match(_7fb.format);
+if(!_800){
+continue;
+}
+var _801={id:encodeURIComponent(_800?_800[1]:null),element:_7fa,parent:_7fc,children:[],position:_7fc.children.length,container:self._findChildrenElement(_7fe[i],_7fb.treeTag.toUpperCase())};
+if(_801.container){
+self._tree(_801.container,_7fb,_801);
+}
+_7fc.children.push(_801);
+}
+return _7fc;
+},_findChildrenElement:function(_802,_803){
+if(_802&&_802.hasChildNodes){
+_803=_803.toUpperCase();
+for(var i=0;i<_802.childNodes.length;++i){
+if(_802.childNodes[i].tagName.toUpperCase()==_803){
+return _802.childNodes[i];
+}
+}
+}
+return null;
+},tree:function(_805,_806){
+_805=MochiKit.DOM.getElement(_805);
+var _807=MochiKit.Sortable.options(_805);
+_806=MochiKit.Base.update({tag:_807.tag,treeTag:_807.treeTag,only:_807.only,name:_805.id,format:_807.format},_806||{});
+var root={id:null,parent:null,children:new Array,container:_805,position:0};
+return MochiKit.Sortable._tree(_805,_806,root);
+},setSequence:function(_809,_80a,_80b){
+var self=MochiKit.Sortable;
+var b=MochiKit.Base;
+_809=MochiKit.DOM.getElement(_809);
+_80b=b.update(self.options(_809),_80b||{});
+var _80e={};
+b.map(function(n){
+var m=n.id.match(_80b.format);
+if(m){
+_80e[m[1]]=[n,n.parentNode];
+}
+n.parentNode.removeChild(n);
+},self.findElements(_809,_80b));
+b.map(function(_811){
+var n=_80e[_811];
+if(n){
+n[1].appendChild(n[0]);
+delete _80e[_811];
+}
+},_80a);
+},_constructIndex:function(node){
+var _814="";
+do{
+if(node.id){
+_814="["+node.position+"]"+_814;
+}
+}while((node=node.parent)!=null);
+return _814;
+},sequence:function(_815,_816){
+_815=MochiKit.DOM.getElement(_815);
+var self=MochiKit.Sortable;
+var _816=MochiKit.Base.update(self.options(_815),_816||{});
+return MochiKit.Base.map(function(item){
+return item.id.match(_816.format)?item.id.match(_816.format)[1]:"";
+},MochiKit.DOM.getElement(self.findElements(_815,_816)||[]));
+},serialize:function(_819,_81a){
+_819=MochiKit.DOM.getElement(_819);
+var self=MochiKit.Sortable;
+_81a=MochiKit.Base.update(self.options(_819),_81a||{});
+var name=encodeURIComponent(_81a.name||_819.id);
+if(_81a.tree){
+return MochiKit.Base.flattenArray(MochiKit.Base.map(function(item){
+return [name+self._constructIndex(item)+"[id]="+encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+},self.tree(_819,_81a).children)).join("&");
+}else{
+return MochiKit.Base.map(function(item){
+return name+"[]="+encodeURIComponent(item);
+},self.sequence(_819,_81a)).join("&");
+}
+}});
+MochiKit.Sortable.Sortable=MochiKit.Sortable;
+MochiKit.Sortable.__new__=function(){
+MochiKit.Base.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":MochiKit.Base.concat(this.EXPORT,this.EXPORT_OK)};
+};
+MochiKit.Sortable.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Sortable);
+if(typeof (MochiKit)=="undefined"){
+MochiKit={};
+}
+if(typeof (MochiKit.MochiKit)=="undefined"){
+MochiKit.MochiKit={};
+}
+MochiKit.MochiKit.NAME="MochiKit.MochiKit";
+MochiKit.MochiKit.VERSION="1.4.2";
+MochiKit.MochiKit.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.MochiKit.toString=function(){
+return this.__repr__();
+};
+MochiKit.MochiKit.SUBMODULES=["Base","Iter","Logging","DateTime","Format","Async","DOM","Selector","Style","LoggingPane","Color","Signal","Position","Visual","DragAndDrop","Sortable"];
+if(typeof (JSAN)!="undefined"||typeof (dojo)!="undefined"){
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.MochiKit");
+(function(lst){
+for(var i=0;i<lst.length;i++){
+dojo.require("MochiKit."+lst[i]);
+}
+})(MochiKit.MochiKit.SUBMODULES);
+}
+if(typeof (JSAN)!="undefined"){
+(function(lst){
+for(var i=0;i<lst.length;i++){
+JSAN.use("MochiKit."+lst[i],[]);
+}
+})(MochiKit.MochiKit.SUBMODULES);
+}
+(function(){
+var _823=MochiKit.Base.extend;
+var self=MochiKit.MochiKit;
+var _825=self.SUBMODULES;
+var _826=[];
+var _827=[];
+var _828={};
+var i,k,m,all;
+for(i=0;i<_825.length;i++){
+m=MochiKit[_825[i]];
+_823(_826,m.EXPORT);
+_823(_827,m.EXPORT_OK);
+for(k in m.EXPORT_TAGS){
+_828[k]=_823(_828[k],m.EXPORT_TAGS[k]);
+}
+all=m.EXPORT_TAGS[":all"];
+if(!all){
+all=_823(null,m.EXPORT,m.EXPORT_OK);
+}
+var j;
+for(j=0;j<all.length;j++){
+k=all[j];
+self[k]=m[k];
+}
+}
+self.EXPORT=_826;
+self.EXPORT_OK=_827;
+self.EXPORT_TAGS=_828;
+}());
+}else{
+if(typeof (MochiKit.__compat__)=="undefined"){
+MochiKit.__compat__=true;
+}
+(function(){
+if(typeof (document)=="undefined"){
+return;
+}
+var _82e=document.getElementsByTagName("script");
+var _82f="http://www.w3.org/1999/xhtml";
+var _830="http://www.w3.org/2000/svg";
+var _831="http://www.w3.org/1999/xlink";
+var _832="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+var base=null;
+var _834=null;
+var _835={};
+var i;
+var src;
+for(i=0;i<_82e.length;i++){
+src=null;
+switch(_82e[i].namespaceURI){
+case _830:
+src=_82e[i].getAttributeNS(_831,"href");
+break;
+default:
+src=_82e[i].getAttribute("src");
+break;
+}
+if(!src){
+continue;
+}
+_835[src]=true;
+if(src.match(/MochiKit.js(\?.*)?$/)){
+base=src.substring(0,src.lastIndexOf("MochiKit.js"));
+_834=_82e[i];
+}
+}
+if(base===null){
+return;
+}
+var _838=MochiKit.MochiKit.SUBMODULES;
+for(var i=0;i<_838.length;i++){
+if(MochiKit[_838[i]]){
+continue;
+}
+var uri=base+_838[i]+".js";
+if(uri in _835){
+continue;
+}
+if(_834.namespaceURI==_830||_834.namespaceURI==_832){
+var s=document.createElementNS(_834.namespaceURI,"script");
+s.setAttribute("id","MochiKit_"+base+_838[i]);
+if(_834.namespaceURI==_830){
+s.setAttributeNS(_831,"href",uri);
+}else{
+s.setAttribute("src",uri);
+}
+s.setAttribute("type","application/x-javascript");
+_834.parentNode.appendChild(s);
+}else{
+document.write("<"+_834.nodeName+" src=\""+uri+"\" type=\"text/javascript\"></script>");
+}
+}
+})();
+}
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/debug.js
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/debug.js (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/debug.js 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,161 @@
+function showFrame(anchor) {
+ var tbid = anchor.getAttribute('tbid');
+ var expanded = anchor.expanded;
+ if (expanded) {
+ MochiKit.DOM.hideElement(anchor.expandedElement);
+ anchor.expanded = false;
+ _swapImage(anchor);
+ return false;
+ }
+ anchor.expanded = true;
+ if (anchor.expandedElement) {
+ MochiKit.DOM.showElement(anchor.expandedElement);
+ _swapImage(anchor);
+ $('debug_input_'+tbid).focus();
+ return false;
+ }
+ var url = debug_base
+ + '/show_frame?tbid=' + tbid
+ + '&debugcount=' + debug_count;
+ var d = MochiKit.Async.doSimpleXMLHttpRequest(url);
+ d.addCallbacks(function (data) {
+ var el = MochiKit.DOM.DIV({});
+ anchor.parentNode.insertBefore(el, anchor.nextSibling);
+ el.innerHTML = data.responseText;
+ anchor.expandedElement = el;
+ _swapImage(anchor);
+ $('debug_input_'+tbid).focus();
+ }, function (error) {
+ showError(error.req.responseText);
+ });
+ return false;
+}
+
+function _swapImage(anchor) {
+ var el = anchor.getElementsByTagName('IMG')[0];
+ if (anchor.expanded) {
+ var img = 'minus.jpg';
+ } else {
+ var img = 'plus.jpg';
+ }
+ el.src = debug_base + '/media/' + img;
+}
+
+function submitInput(button, tbid) {
+ var input = $(button.getAttribute('input-from'));
+ var output = $(button.getAttribute('output-to'));
+ var url = debug_base
+ + '/exec_input';
+ var history = input.form.history;
+ input.historyPosition = 0;
+ if (! history) {
+ history = input.form.history = [];
+ }
+ history.push(input.value);
+ var vars = {
+ tbid: tbid,
+ debugcount: debug_count,
+ input: input.value
+ };
+ MochiKit.DOM.showElement(output);
+ var d = MochiKit.Async.doSimpleXMLHttpRequest(url, vars);
+ d.addCallbacks(function (data) {
+ var result = data.responseText;
+ output.innerHTML += result;
+ input.value = '';
+ input.focus();
+ }, function (error) {
+ showError(error.req.responseText);
+ });
+ return false;
+}
+
+function showError(msg) {
+ var el = $('error-container');
+ if (el.innerHTML) {
+ el.innerHTML += '<hr noshade>\n' + msg;
+ } else {
+ el.innerHTML = msg;
+ }
+ MochiKit.DOM.showElement('error-area');
+}
+
+function clearError() {
+ var el = $('error-container');
+ el.innerHTML = '';
+ MochiKit.DOM.hideElement('error-area');
+}
+
+function expandInput(button) {
+ var input = button.form.elements.input;
+ stdops = {
+ name: 'input',
+ style: 'width: 100%',
+ autocomplete: 'off'
+ };
+ if (input.tagName == 'INPUT') {
+ var newEl = MochiKit.DOM.TEXTAREA(stdops);
+ var text = 'Contract';
+ } else {
+ stdops['type'] = 'text';
+ stdops['onkeypress'] = 'upArrow(this)';
+ var newEl = MochiKit.DOM.INPUT(stdops);
+ var text = 'Expand';
+ }
+ newEl.value = input.value;
+ newEl.id = input.id;
+ MochiKit.DOM.swapDOM(input, newEl);
+ newEl.focus();
+ button.value = text;
+ return false;
+}
+
+function upArrow(input, event) {
+ if (window.event) {
+ event = window.event;
+ }
+ if (event.keyCode != 38 && event.keyCode != 40) {
+ // not an up- or down-arrow
+ return true;
+ }
+ var dir = event.keyCode == 38 ? 1 : -1;
+ var history = input.form.history;
+ if (! history) {
+ history = input.form.history = [];
+ }
+ var pos = input.historyPosition || 0;
+ if (! pos && dir == -1) {
+ return true;
+ }
+ if (! pos && input.value) {
+ history.push(input.value);
+ pos = 1;
+ }
+ pos += dir;
+ if (history.length-pos < 0) {
+ pos = 1;
+ }
+ if (history.length-pos > history.length-1) {
+ input.value = '';
+ return true;
+ }
+ input.historyPosition = pos;
+ var line = history[history.length-pos];
+ input.value = line;
+}
+
+function expandLong(anchor) {
+ var span = anchor;
+ while (span) {
+ if (span.style && span.style.display == 'none') {
+ break;
+ }
+ span = span.nextSibling;
+ }
+ if (! span) {
+ return false;
+ }
+ MochiKit.DOM.showElement(span);
+ MochiKit.DOM.hideElement(anchor);
+ return false;
+}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/minus.jpg
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/minus.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/plus.jpg
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/media/plus.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/middleware.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/middleware.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/evalexception/middleware.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,610 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Exception-catching middleware that allows interactive debugging.
+
+This middleware catches all unexpected exceptions. A normal
+traceback, like produced by
+``paste.exceptions.errormiddleware.ErrorMiddleware`` is given, plus
+controls to see local variables and evaluate expressions in a local
+context.
+
+This can only be used in single-process environments, because
+subsequent requests must go back to the same process that the
+exception originally occurred in. Threaded or non-concurrent
+environments both work.
+
+This shouldn't be used in production in any way. That would just be
+silly.
+
+If calling from an XMLHttpRequest call, if the GET variable ``_`` is
+given then it will make the response more compact (and less
+Javascripty), since if you use innerHTML it'll kill your browser. You
+can look for the header X-Debug-URL in your 500 responses if you want
+to see the full debuggable traceback. Also, this URL is printed to
+``wsgi.errors``, so you can open it up in another browser window.
+"""
+import sys
+import os
+import cgi
+import traceback
+from cStringIO import StringIO
+import pprint
+import itertools
+import time
+import re
+from paste.exceptions import errormiddleware, formatter, collector
+from paste import wsgilib
+from paste import urlparser
+from paste import httpexceptions
+from paste import registry
+from paste import request
+from paste import response
+import evalcontext
+
+limit = 200
+
+def html_quote(v):
+ """
+ Escape HTML characters, plus translate None to ''
+ """
+ if v is None:
+ return ''
+ return cgi.escape(str(v), 1)
+
+def preserve_whitespace(v, quote=True):
+ """
+ Quote a value for HTML, preserving whitespace (translating
+ newlines to ``<br>`` and multiple spaces to use `` ``).
+
+ If ``quote`` is true, then the value will be HTML quoted first.
+ """
+ if quote:
+ v = html_quote(v)
+ v = v.replace('\n', '<br>\n')
+ v = re.sub(r'()( +)', _repl_nbsp, v)
+ v = re.sub(r'(\n)( +)', _repl_nbsp, v)
+ v = re.sub(r'^()( +)', _repl_nbsp, v)
+ return '<code>%s</code>' % v
+
+def _repl_nbsp(match):
+ if len(match.group(2)) == 1:
+ return ' '
+ return match.group(1) + ' ' * (len(match.group(2))-1) + ' '
+
+def simplecatcher(application):
+ """
+ A simple middleware that catches errors and turns them into simple
+ tracebacks.
+ """
+ def simplecatcher_app(environ, start_response):
+ try:
+ return application(environ, start_response)
+ except:
+ out = StringIO()
+ traceback.print_exc(file=out)
+ start_response('500 Server Error',
+ [('content-type', 'text/html')],
+ sys.exc_info())
+ res = out.getvalue()
+ return ['<h3>Error</h3><pre>%s</pre>'
+ % html_quote(res)]
+ return simplecatcher_app
+
+def wsgiapp():
+ """
+ Turns a function or method into a WSGI application.
+ """
+ def decorator(func):
+ def wsgiapp_wrapper(*args):
+ # we get 3 args when this is a method, two when it is
+ # a function :(
+ if len(args) == 3:
+ environ = args[1]
+ start_response = args[2]
+ args = [args[0]]
+ else:
+ environ, start_response = args
+ args = []
+ def application(environ, start_response):
+ form = wsgilib.parse_formvars(environ,
+ include_get_vars=True)
+ headers = response.HeaderDict(
+ {'content-type': 'text/html',
+ 'status': '200 OK'})
+ form['environ'] = environ
+ form['headers'] = headers
+ res = func(*args, **form.mixed())
+ status = headers.pop('status')
+ start_response(status, headers.headeritems())
+ return [res]
+ app = httpexceptions.make_middleware(application)
+ app = simplecatcher(app)
+ return app(environ, start_response)
+ wsgiapp_wrapper.exposed = True
+ return wsgiapp_wrapper
+ return decorator
+
+def get_debug_info(func):
+ """
+ A decorator (meant to be used under ``wsgiapp()``) that resolves
+ the ``debugcount`` variable to a ``DebugInfo`` object (or gives an
+ error if it can't be found).
+ """
+ def debug_info_replacement(self, **form):
+ try:
+ if 'debugcount' not in form:
+ raise ValueError('You must provide a debugcount parameter')
+ debugcount = form.pop('debugcount')
+ try:
+ debugcount = int(debugcount)
+ except ValueError:
+ raise ValueError('Bad value for debugcount')
+ if debugcount not in self.debug_infos:
+ raise ValueError(
+ 'Debug %s no longer found (maybe it has expired?)'
+ % debugcount)
+ debug_info = self.debug_infos[debugcount]
+ return func(self, debug_info=debug_info, **form)
+ except ValueError, e:
+ form['headers']['status'] = '500 Server Error'
+ return '<html>There was an error: %s</html>' % html_quote(e)
+ return debug_info_replacement
+
+debug_counter = itertools.count(int(time.time()))
+def get_debug_count(environ):
+ """
+ Return the unique debug count for the current request
+ """
+ if 'paste.evalexception.debug_count' in environ:
+ return environ['paste.evalexception.debug_count']
+ else:
+ environ['paste.evalexception.debug_count'] = next = debug_counter.next()
+ return next
+
+class EvalException(object):
+
+ def __init__(self, application, global_conf=None,
+ xmlhttp_key=None):
+ self.application = application
+ self.debug_infos = {}
+ if xmlhttp_key is None:
+ if global_conf is None:
+ xmlhttp_key = '_'
+ else:
+ xmlhttp_key = global_conf.get('xmlhttp_key', '_')
+ self.xmlhttp_key = xmlhttp_key
+
+ def __call__(self, environ, start_response):
+ assert not environ['wsgi.multiprocess'], (
+ "The EvalException middleware is not usable in a "
+ "multi-process environment")
+ environ['paste.evalexception'] = self
+ if environ.get('PATH_INFO', '').startswith('/_debug/'):
+ return self.debug(environ, start_response)
+ else:
+ return self.respond(environ, start_response)
+
+ def debug(self, environ, start_response):
+ assert request.path_info_pop(environ) == '_debug'
+ next_part = request.path_info_pop(environ)
+ method = getattr(self, next_part, None)
+ if not method:
+ exc = httpexceptions.HTTPNotFound(
+ '%r not found when parsing %r'
+ % (next_part, wsgilib.construct_url(environ)))
+ return exc.wsgi_application(environ, start_response)
+ if not getattr(method, 'exposed', False):
+ exc = httpexceptions.HTTPForbidden(
+ '%r not allowed' % next_part)
+ return exc.wsgi_application(environ, start_response)
+ return method(environ, start_response)
+
+ def media(self, environ, start_response):
+ """
+ Static path where images and other files live
+ """
+ app = urlparser.StaticURLParser(
+ os.path.join(os.path.dirname(__file__), 'media'))
+ return app(environ, start_response)
+ media.exposed = True
+
+ def mochikit(self, environ, start_response):
+ """
+ Static path where MochiKit lives
+ """
+ app = urlparser.StaticURLParser(
+ os.path.join(os.path.dirname(__file__), 'mochikit'))
+ return app(environ, start_response)
+ mochikit.exposed = True
+
+ def summary(self, environ, start_response):
+ """
+ Returns a JSON-format summary of all the cached
+ exception reports
+ """
+ start_response('200 OK', [('Content-type', 'text/x-json')])
+ data = [];
+ items = self.debug_infos.values()
+ items.sort(lambda a, b: cmp(a.created, b.created))
+ data = [item.json() for item in items]
+ return [repr(data)]
+ summary.exposed = True
+
+ def view(self, environ, start_response):
+ """
+ View old exception reports
+ """
+ id = int(request.path_info_pop(environ))
+ if id not in self.debug_infos:
+ start_response(
+ '500 Server Error',
+ [('Content-type', 'text/html')])
+ return [
+ "Traceback by id %s does not exist (maybe "
+ "the server has been restarted?)"
+ % id]
+ debug_info = self.debug_infos[id]
+ return debug_info.wsgi_application(environ, start_response)
+ view.exposed = True
+
+ def make_view_url(self, environ, base_path, count):
+ return base_path + '/_debug/view/%s' % count
+
+ #@wsgiapp()
+ #@get_debug_info
+ def show_frame(self, tbid, debug_info, **kw):
+ frame = debug_info.frame(int(tbid))
+ vars = frame.tb_frame.f_locals
+ if vars:
+ registry.restorer.restoration_begin(debug_info.counter)
+ local_vars = make_table(vars)
+ registry.restorer.restoration_end()
+ else:
+ local_vars = 'No local vars'
+ return input_form(tbid, debug_info) + local_vars
+
+ show_frame = wsgiapp()(get_debug_info(show_frame))
+
+ #@wsgiapp()
+ #@get_debug_info
+ def exec_input(self, tbid, debug_info, input, **kw):
+ if not input.strip():
+ return ''
+ input = input.rstrip() + '\n'
+ frame = debug_info.frame(int(tbid))
+ vars = frame.tb_frame.f_locals
+ glob_vars = frame.tb_frame.f_globals
+ context = evalcontext.EvalContext(vars, glob_vars)
+ registry.restorer.restoration_begin(debug_info.counter)
+ output = context.exec_expr(input)
+ registry.restorer.restoration_end()
+ input_html = formatter.str2html(input)
+ return ('<code style="color: #060">>>></code> '
+ '<code>%s</code><br>\n%s'
+ % (preserve_whitespace(input_html, quote=False),
+ preserve_whitespace(output)))
+
+ exec_input = wsgiapp()(get_debug_info(exec_input))
+
+ def respond(self, environ, start_response):
+ if environ.get('paste.throw_errors'):
+ return self.application(environ, start_response)
+ base_path = request.construct_url(environ, with_path_info=False,
+ with_query_string=False)
+ environ['paste.throw_errors'] = True
+ started = []
+ def detect_start_response(status, headers, exc_info=None):
+ try:
+ return start_response(status, headers, exc_info)
+ except:
+ raise
+ else:
+ started.append(True)
+ try:
+ __traceback_supplement__ = errormiddleware.Supplement, self, environ
+ app_iter = self.application(environ, detect_start_response)
+ try:
+ return_iter = list(app_iter)
+ return return_iter
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ except:
+ exc_info = sys.exc_info()
+ for expected in environ.get('paste.expected_exceptions', []):
+ if isinstance(exc_info[1], expected):
+ raise
+
+ # Tell the Registry to save its StackedObjectProxies current state
+ # for later restoration
+ registry.restorer.save_registry_state(environ)
+
+ count = get_debug_count(environ)
+ view_uri = self.make_view_url(environ, base_path, count)
+ if not started:
+ headers = [('content-type', 'text/html')]
+ headers.append(('X-Debug-URL', view_uri))
+ start_response('500 Internal Server Error',
+ headers,
+ exc_info)
+ environ['wsgi.errors'].write('Debug at: %s\n' % view_uri)
+
+ exc_data = collector.collect_exception(*exc_info)
+ debug_info = DebugInfo(count, exc_info, exc_data, base_path,
+ environ, view_uri)
+ assert count not in self.debug_infos
+ self.debug_infos[count] = debug_info
+
+ if self.xmlhttp_key:
+ get_vars = wsgilib.parse_querystring(environ)
+ if dict(get_vars).get(self.xmlhttp_key):
+ exc_data = collector.collect_exception(*exc_info)
+ html = formatter.format_html(
+ exc_data, include_hidden_frames=False,
+ include_reusable=False, show_extra_data=False)
+ return [html]
+
+ # @@: it would be nice to deal with bad content types here
+ return debug_info.content()
+
+ def exception_handler(self, exc_info, environ):
+ simple_html_error = False
+ if self.xmlhttp_key:
+ get_vars = wsgilib.parse_querystring(environ)
+ if dict(get_vars).get(self.xmlhttp_key):
+ simple_html_error = True
+ return errormiddleware.handle_exception(
+ exc_info, environ['wsgi.errors'],
+ html=True,
+ debug_mode=True,
+ simple_html_error=simple_html_error)
+
+class DebugInfo(object):
+
+ def __init__(self, counter, exc_info, exc_data, base_path,
+ environ, view_uri):
+ self.counter = counter
+ self.exc_data = exc_data
+ self.base_path = base_path
+ self.environ = environ
+ self.view_uri = view_uri
+ self.created = time.time()
+ self.exc_type, self.exc_value, self.tb = exc_info
+ __exception_formatter__ = 1
+ self.frames = []
+ n = 0
+ tb = self.tb
+ while tb is not None and (limit is None or n < limit):
+ if tb.tb_frame.f_locals.get('__exception_formatter__'):
+ # Stop recursion. @@: should make a fake ExceptionFrame
+ break
+ self.frames.append(tb)
+ tb = tb.tb_next
+ n += 1
+
+ def json(self):
+ """Return the JSON-able representation of this object"""
+ return {
+ 'uri': self.view_uri,
+ 'created': time.strftime('%c', time.gmtime(self.created)),
+ 'created_timestamp': self.created,
+ 'exception_type': str(self.exc_type),
+ 'exception': str(self.exc_value),
+ }
+
+ def frame(self, tbid):
+ for frame in self.frames:
+ if id(frame) == tbid:
+ return frame
+ else:
+ raise ValueError, (
+ "No frame by id %s found from %r" % (tbid, self.frames))
+
+ def wsgi_application(self, environ, start_response):
+ start_response('200 OK', [('content-type', 'text/html')])
+ return self.content()
+
+ def content(self):
+ html = format_eval_html(self.exc_data, self.base_path, self.counter)
+ head_html = (formatter.error_css + formatter.hide_display_js)
+ head_html += self.eval_javascript()
+ repost_button = make_repost_button(self.environ)
+ page = error_template % {
+ 'repost_button': repost_button or '',
+ 'head_html': head_html,
+ 'body': html}
+ return [page]
+
+ def eval_javascript(self):
+ base_path = self.base_path + '/_debug'
+ return (
+ '<script type="text/javascript" src="%s/media/MochiKit.packed.js">'
+ '</script>\n'
+ '<script type="text/javascript" src="%s/media/debug.js">'
+ '</script>\n'
+ '<script type="text/javascript">\n'
+ 'debug_base = %r;\n'
+ 'debug_count = %r;\n'
+ '</script>\n'
+ % (base_path, base_path, base_path, self.counter))
+
+class EvalHTMLFormatter(formatter.HTMLFormatter):
+
+ def __init__(self, base_path, counter, **kw):
+ super(EvalHTMLFormatter, self).__init__(**kw)
+ self.base_path = base_path
+ self.counter = counter
+
+ def format_source_line(self, filename, frame):
+ line = formatter.HTMLFormatter.format_source_line(
+ self, filename, frame)
+ return (line +
+ ' <a href="#" class="switch_source" '
+ 'tbid="%s" onClick="return showFrame(this)"> '
+ '<img src="%s/_debug/media/plus.jpg" border=0 width=9 '
+ 'height=9> </a>'
+ % (frame.tbid, self.base_path))
+
+def make_table(items):
+ if isinstance(items, dict):
+ items = items.items()
+ items.sort()
+ rows = []
+ i = 0
+ for name, value in items:
+ i += 1
+ out = StringIO()
+ try:
+ pprint.pprint(value, out)
+ except Exception, e:
+ print >> out, 'Error: %s' % e
+ value = html_quote(out.getvalue())
+ if len(value) > 100:
+ # @@: This can actually break the HTML :(
+ # should I truncate before quoting?
+ orig_value = value
+ value = value[:100]
+ value += '<a class="switch_source" style="background-color: #999" href="#" onclick="return expandLong(this)">...</a>'
+ value += '<span style="display: none">%s</span>' % orig_value[100:]
+ value = formatter.make_wrappable(value)
+ if i % 2:
+ attr = ' class="even"'
+ else:
+ attr = ' class="odd"'
+ rows.append('<tr%s style="vertical-align: top;"><td>'
+ '<b>%s</b></td><td style="overflow: auto">%s<td></tr>'
+ % (attr, html_quote(name),
+ preserve_whitespace(value, quote=False)))
+ return '<table>%s</table>' % (
+ '\n'.join(rows))
+
+def format_eval_html(exc_data, base_path, counter):
+ short_formatter = EvalHTMLFormatter(
+ base_path=base_path,
+ counter=counter,
+ include_reusable=False)
+ short_er = short_formatter.format_collected_data(exc_data)
+ long_formatter = EvalHTMLFormatter(
+ base_path=base_path,
+ counter=counter,
+ show_hidden_frames=True,
+ show_extra_data=False,
+ include_reusable=False)
+ long_er = long_formatter.format_collected_data(exc_data)
+ text_er = formatter.format_text(exc_data, show_hidden_frames=True)
+ if short_formatter.filter_frames(exc_data.frames) != \
+ long_formatter.filter_frames(exc_data.frames):
+ # Only display the full traceback when it differs from the
+ # short version
+ full_traceback_html = """
+ <br>
+ <script type="text/javascript">
+ show_button('full_traceback', 'full traceback')
+ </script>
+ <div id="full_traceback" class="hidden-data">
+ %s
+ </div>
+ """ % long_er
+ else:
+ full_traceback_html = ''
+
+ return """
+ %s
+ %s
+ <br>
+ <script type="text/javascript">
+ show_button('text_version', 'text version')
+ </script>
+ <div id="text_version" class="hidden-data">
+ <textarea style="width: 100%%" rows=10 cols=60>%s</textarea>
+ </div>
+ """ % (short_er, full_traceback_html, cgi.escape(text_er))
+
+def make_repost_button(environ):
+ url = request.construct_url(environ)
+ if environ['REQUEST_METHOD'] == 'GET':
+ return ('<button onclick="window.location.href=%r">'
+ 'Re-GET Page</button><br>' % url)
+ else:
+ # @@: I'd like to reconstruct this, but I can't because
+ # the POST body is probably lost at this point, and
+ # I can't get it back :(
+ return None
+ # @@: Use or lose the following code block
+ """
+ fields = []
+ for name, value in wsgilib.parse_formvars(
+ environ, include_get_vars=False).items():
+ if hasattr(value, 'filename'):
+ # @@: Arg, we'll just submit the body, and leave out
+ # the filename :(
+ value = value.value
+ fields.append(
+ '<input type="hidden" name="%s" value="%s">'
+ % (html_quote(name), html_quote(value)))
+ return '''
+<form action="%s" method="POST">
+%s
+<input type="submit" value="Re-POST Page">
+</form>''' % (url, '\n'.join(fields))
+"""
+
+
+def input_form(tbid, debug_info):
+ return '''
+<form action="#" method="POST"
+ onsubmit="return submitInput($(\'submit_%(tbid)s\'), %(tbid)s)">
+<div id="exec-output-%(tbid)s" style="width: 95%%;
+ padding: 5px; margin: 5px; border: 2px solid #000;
+ display: none"></div>
+<input type="text" name="input" id="debug_input_%(tbid)s"
+ style="width: 100%%"
+ autocomplete="off" onkeypress="upArrow(this, event)"><br>
+<input type="submit" value="Execute" name="submitbutton"
+ onclick="return submitInput(this, %(tbid)s)"
+ id="submit_%(tbid)s"
+ input-from="debug_input_%(tbid)s"
+ output-to="exec-output-%(tbid)s">
+<input type="submit" value="Expand"
+ onclick="return expandInput(this)">
+</form>
+ ''' % {'tbid': tbid}
+
+error_template = '''
+<html>
+<head>
+ <title>Server Error</title>
+ %(head_html)s
+</head>
+<body>
+
+<div id="error-area" style="display: none; background-color: #600; color: #fff; border: 2px solid black">
+<div id="error-container"></div>
+<button onclick="return clearError()">clear this</button>
+</div>
+
+%(repost_button)s
+
+%(body)s
+
+</body>
+</html>
+'''
+
+def make_eval_exception(app, global_conf, xmlhttp_key=None):
+ """
+ Wraps the application in an interactive debugger.
+
+ This debugger is a major security hole, and should only be
+ used during development.
+
+ xmlhttp_key is a string that, if present in QUERY_STRING,
+ indicates that the request is an XMLHttp request, and the
+ Javascript/interactive debugger should not be returned. (If you
+ try to put the debugger somewhere with innerHTML, you will often
+ crash the browser)
+ """
+ if xmlhttp_key is None:
+ xmlhttp_key = global_conf.get('xmlhttp_key', '_')
+ return EvalException(app, xmlhttp_key=xmlhttp_key)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Package for catching exceptions and displaying annotated exception
+reports
+"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/collector.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/collector.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/collector.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,526 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+## Originally zExceptions.ExceptionFormatter from Zope;
+## Modified by Ian Bicking, Imaginary Landscape, 2005
+"""
+An exception collector that finds traceback information plus
+supplements
+"""
+
+import sys
+import traceback
+import time
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+import linecache
+from paste.exceptions import serial_number_generator
+import warnings
+
+DEBUG_EXCEPTION_FORMATTER = True
+DEBUG_IDENT_PREFIX = 'E-'
+FALLBACK_ENCODING = 'UTF-8'
+
+__all__ = ['collect_exception', 'ExceptionCollector']
+
+class ExceptionCollector(object):
+
+ """
+ Produces a data structure that can be used by formatters to
+ display exception reports.
+
+ Magic variables:
+
+ If you define one of these variables in your local scope, you can
+ add information to tracebacks that happen in that context. This
+ allows applications to add all sorts of extra information about
+ the context of the error, including URLs, environmental variables,
+ users, hostnames, etc. These are the variables we look for:
+
+ ``__traceback_supplement__``:
+ You can define this locally or globally (unlike all the other
+ variables, which must be defined locally).
+
+ ``__traceback_supplement__`` is a tuple of ``(factory, arg1,
+ arg2...)``. When there is an exception, ``factory(arg1, arg2,
+ ...)`` is called, and the resulting object is inspected for
+ supplemental information.
+
+ ``__traceback_info__``:
+ This information is added to the traceback, usually fairly
+ literally.
+
+ ``__traceback_hide__``:
+ If set and true, this indicates that the frame should be
+ hidden from abbreviated tracebacks. This way you can hide
+ some of the complexity of the larger framework and let the
+ user focus on their own errors.
+
+ By setting it to ``'before'``, all frames before this one will
+ be thrown away. By setting it to ``'after'`` then all frames
+ after this will be thrown away until ``'reset'`` is found. In
+ each case the frame where it is set is included, unless you
+ append ``'_and_this'`` to the value (e.g.,
+ ``'before_and_this'``).
+
+ Note that formatters will ignore this entirely if the frame
+ that contains the error wouldn't normally be shown according
+ to these rules.
+
+ ``__traceback_reporter__``:
+ This should be a reporter object (see the reporter module),
+ or a list/tuple of reporter objects. All reporters found this
+ way will be given the exception, innermost first.
+
+ ``__traceback_decorator__``:
+ This object (defined in a local or global scope) will get the
+ result of this function (the CollectedException defined
+ below). It may modify this object in place, or return an
+ entirely new object. This gives the object the ability to
+ manipulate the traceback arbitrarily.
+
+ The actually interpretation of these values is largely up to the
+ reporters and formatters.
+
+ ``collect_exception(*sys.exc_info())`` will return an object with
+ several attributes:
+
+ ``frames``:
+ A list of frames
+ ``exception_formatted``:
+ The formatted exception, generally a full traceback
+ ``exception_type``:
+ The type of the exception, like ``ValueError``
+ ``exception_value``:
+ The string value of the exception, like ``'x not in list'``
+ ``identification_code``:
+ A hash of the exception data meant to identify the general
+ exception, so that it shares this code with other exceptions
+ that derive from the same problem. The code is a hash of
+ all the module names and function names in the traceback,
+ plus exception_type. This should be shown to users so they
+ can refer to the exception later. (@@: should it include a
+ portion that allows identification of the specific instance
+ of the exception as well?)
+
+ The list of frames goes innermost first. Each frame has these
+ attributes; some values may be None if they could not be
+ determined.
+
+ ``modname``:
+ the name of the module
+ ``filename``:
+ the filename of the module
+ ``lineno``:
+ the line of the error
+ ``revision``:
+ the contents of __version__ or __revision__
+ ``name``:
+ the function name
+ ``supplement``:
+ an object created from ``__traceback_supplement__``
+ ``supplement_exception``:
+ a simple traceback of any exception ``__traceback_supplement__``
+ created
+ ``traceback_info``:
+ the str() of any ``__traceback_info__`` variable found in the local
+ scope (@@: should it str()-ify it or not?)
+ ``traceback_hide``:
+ the value of any ``__traceback_hide__`` variable
+ ``traceback_log``:
+ the value of any ``__traceback_log__`` variable
+
+
+ ``__traceback_supplement__`` is thrown away, but a fixed
+ set of attributes are captured; each of these attributes is
+ optional.
+
+ ``object``:
+ the name of the object being visited
+ ``source_url``:
+ the original URL requested
+ ``line``:
+ the line of source being executed (for interpreters, like ZPT)
+ ``column``:
+ the column of source being executed
+ ``expression``:
+ the expression being evaluated (also for interpreters)
+ ``warnings``:
+ a list of (string) warnings to be displayed
+ ``getInfo``:
+ a function/method that takes no arguments, and returns a string
+ describing any extra information
+ ``extraData``:
+ a function/method that takes no arguments, and returns a
+ dictionary. The contents of this dictionary will not be
+ displayed in the context of the traceback, but globally for
+ the exception. Results will be grouped by the keys in the
+ dictionaries (which also serve as titles). The keys can also
+ be tuples of (importance, title); in this case the importance
+ should be ``important`` (shows up at top), ``normal`` (shows
+ up somewhere; unspecified), ``supplemental`` (shows up at
+ bottom), or ``extra`` (shows up hidden or not at all).
+
+ These are used to create an object with attributes of the same
+ names (``getInfo`` becomes a string attribute, not a method).
+ ``__traceback_supplement__`` implementations should be careful to
+ produce values that are relatively static and unlikely to cause
+ further errors in the reporting system -- any complex
+ introspection should go in ``getInfo()`` and should ultimately
+ return a string.
+
+ Note that all attributes are optional, and under certain
+ circumstances may be None or may not exist at all -- the collector
+ can only do a best effort, but must avoid creating any exceptions
+ itself.
+
+ Formatters may want to use ``__traceback_hide__`` as a hint to
+ hide frames that are part of the 'framework' or underlying system.
+ There are a variety of rules about special values for this
+ variables that formatters should be aware of.
+
+ TODO:
+
+ More attributes in __traceback_supplement__? Maybe an attribute
+ that gives a list of local variables that should also be
+ collected? Also, attributes that would be explicitly meant for
+ the entire request, not just a single frame. Right now some of
+ the fixed set of attributes (e.g., source_url) are meant for this
+ use, but there's no explicit way for the supplement to indicate
+ new values, e.g., logged-in user, HTTP referrer, environment, etc.
+ Also, the attributes that do exist are Zope/Web oriented.
+
+ More information on frames? cgitb, for instance, produces
+ extensive information on local variables. There exists the
+ possibility that getting this information may cause side effects,
+ which can make debugging more difficult; but it also provides
+ fodder for post-mortem debugging. However, the collector is not
+ meant to be configurable, but to capture everything it can and let
+ the formatters be configurable. Maybe this would have to be a
+ configuration value, or maybe it could be indicated by another
+ magical variable (which would probably mean 'show all local
+ variables below this frame')
+ """
+
+ show_revisions = 0
+
+ def __init__(self, limit=None):
+ self.limit = limit
+
+ def getLimit(self):
+ limit = self.limit
+ if limit is None:
+ limit = getattr(sys, 'tracebacklimit', None)
+ return limit
+
+ def getRevision(self, globals):
+ if not self.show_revisions:
+ return None
+ revision = globals.get('__revision__', None)
+ if revision is None:
+ # Incorrect but commonly used spelling
+ revision = globals.get('__version__', None)
+
+ if revision is not None:
+ try:
+ revision = str(revision).strip()
+ except:
+ revision = '???'
+ return revision
+
+ def collectSupplement(self, supplement, tb):
+ result = {}
+
+ for name in ('object', 'source_url', 'line', 'column',
+ 'expression', 'warnings'):
+ result[name] = getattr(supplement, name, None)
+
+ func = getattr(supplement, 'getInfo', None)
+ if func:
+ result['info'] = func()
+ else:
+ result['info'] = None
+ func = getattr(supplement, 'extraData', None)
+ if func:
+ result['extra'] = func()
+ else:
+ result['extra'] = None
+ return SupplementaryData(**result)
+
+ def collectLine(self, tb, extra_data):
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ co = f.f_code
+ filename = co.co_filename
+ name = co.co_name
+ globals = f.f_globals
+ locals = f.f_locals
+ if not hasattr(locals, 'has_key'):
+ # Something weird about this frame; it's not a real dict
+ warnings.warn(
+ "Frame %s has an invalid locals(): %r" % (
+ globals.get('__name__', 'unknown'), locals))
+ locals = {}
+ data = {}
+ data['modname'] = globals.get('__name__', None)
+ data['filename'] = filename
+ data['lineno'] = lineno
+ data['revision'] = self.getRevision(globals)
+ data['name'] = name
+ data['tbid'] = id(tb)
+
+ # Output a traceback supplement, if any.
+ if locals.has_key('__traceback_supplement__'):
+ # Use the supplement defined in the function.
+ tbs = locals['__traceback_supplement__']
+ elif globals.has_key('__traceback_supplement__'):
+ # Use the supplement defined in the module.
+ # This is used by Scripts (Python).
+ tbs = globals['__traceback_supplement__']
+ else:
+ tbs = None
+ if tbs is not None:
+ factory = tbs[0]
+ args = tbs[1:]
+ try:
+ supp = factory(*args)
+ data['supplement'] = self.collectSupplement(supp, tb)
+ if data['supplement'].extra:
+ for key, value in data['supplement'].extra.items():
+ extra_data.setdefault(key, []).append(value)
+ except:
+ if DEBUG_EXCEPTION_FORMATTER:
+ out = StringIO()
+ traceback.print_exc(file=out)
+ text = out.getvalue()
+ data['supplement_exception'] = text
+ # else just swallow the exception.
+
+ try:
+ tbi = locals.get('__traceback_info__', None)
+ if tbi is not None:
+ data['traceback_info'] = str(tbi)
+ except:
+ pass
+
+ marker = []
+ for name in ('__traceback_hide__', '__traceback_log__',
+ '__traceback_decorator__'):
+ try:
+ tbh = locals.get(name, globals.get(name, marker))
+ if tbh is not marker:
+ data[name[2:-2]] = tbh
+ except:
+ pass
+
+ return data
+
+ def collectExceptionOnly(self, etype, value):
+ return traceback.format_exception_only(etype, value)
+
+ def collectException(self, etype, value, tb, limit=None):
+ # The next line provides a way to detect recursion.
+ __exception_formatter__ = 1
+ frames = []
+ ident_data = []
+ traceback_decorators = []
+ if limit is None:
+ limit = self.getLimit()
+ n = 0
+ extra_data = {}
+ while tb is not None and (limit is None or n < limit):
+ if tb.tb_frame.f_locals.get('__exception_formatter__'):
+ # Stop recursion. @@: should make a fake ExceptionFrame
+ frames.append('(Recursive formatException() stopped)\n')
+ break
+ data = self.collectLine(tb, extra_data)
+ frame = ExceptionFrame(**data)
+ frames.append(frame)
+ if frame.traceback_decorator is not None:
+ traceback_decorators.append(frame.traceback_decorator)
+ ident_data.append(frame.modname or '?')
+ ident_data.append(frame.name or '?')
+ tb = tb.tb_next
+ n = n + 1
+ ident_data.append(str(etype))
+ ident = serial_number_generator.hash_identifier(
+ ' '.join(ident_data), length=5, upper=True,
+ prefix=DEBUG_IDENT_PREFIX)
+
+ result = CollectedException(
+ frames=frames,
+ exception_formatted=self.collectExceptionOnly(etype, value),
+ exception_type=etype,
+ exception_value=self.safeStr(value),
+ identification_code=ident,
+ date=time.localtime(),
+ extra_data=extra_data)
+ if etype is ImportError:
+ extra_data[('important', 'sys.path')] = [sys.path]
+ for decorator in traceback_decorators:
+ try:
+ new_result = decorator(result)
+ if new_result is not None:
+ result = new_result
+ except:
+ pass
+ return result
+
+ def safeStr(self, obj):
+ try:
+ return str(obj)
+ except UnicodeEncodeError:
+ try:
+ return unicode(obj).encode(FALLBACK_ENCODING, 'replace')
+ except UnicodeEncodeError:
+ # This is when something is really messed up, but this can
+ # happen when the __str__ of an object has to handle unicode
+ return repr(obj)
+
+limit = 200
+
+class Bunch(object):
+
+ """
+ A generic container
+ """
+
+ def __init__(self, **attrs):
+ for name, value in attrs.items():
+ setattr(self, name, value)
+
+ def __repr__(self):
+ name = '<%s ' % self.__class__.__name__
+ name += ' '.join(['%s=%r' % (name, str(value)[:30])
+ for name, value in self.__dict__.items()
+ if not name.startswith('_')])
+ return name + '>'
+
+class CollectedException(Bunch):
+ """
+ This is the result of collection the exception; it contains copies
+ of data of interest.
+ """
+ # A list of frames (ExceptionFrame instances), innermost last:
+ frames = []
+ # The result of traceback.format_exception_only; this looks
+ # like a normal traceback you'd see in the interactive interpreter
+ exception_formatted = None
+ # The *string* representation of the type of the exception
+ # (@@: should we give the # actual class? -- we can't keep the
+ # actual exception around, but the class should be safe)
+ # Something like 'ValueError'
+ exception_type = None
+ # The string representation of the exception, from ``str(e)``.
+ exception_value = None
+ # An identifier which should more-or-less classify this particular
+ # exception, including where in the code it happened.
+ identification_code = None
+ # The date, as time.localtime() returns:
+ date = None
+ # A dictionary of supplemental data:
+ extra_data = {}
+
+class SupplementaryData(Bunch):
+ """
+ The result of __traceback_supplement__. We don't keep the
+ supplement object around, for fear of GC problems and whatnot.
+ (@@: Maybe I'm being too superstitious about copying only specific
+ information over)
+ """
+
+ # These attributes are copied from the object, or left as None
+ # if the object doesn't have these attributes:
+ object = None
+ source_url = None
+ line = None
+ column = None
+ expression = None
+ warnings = None
+ # This is the *return value* of supplement.getInfo():
+ info = None
+
+class ExceptionFrame(Bunch):
+ """
+ This represents one frame of the exception. Each frame is a
+ context in the call stack, typically represented by a line
+ number and module name in the traceback.
+ """
+
+ # The name of the module; can be None, especially when the code
+ # isn't associated with a module.
+ modname = None
+ # The filename (@@: when no filename, is it None or '?'?)
+ filename = None
+ # Line number
+ lineno = None
+ # The value of __revision__ or __version__ -- but only if
+ # show_revision = True (by defaut it is false). (@@: Why not
+ # collect this?)
+ revision = None
+ # The name of the function with the error (@@: None or '?' when
+ # unknown?)
+ name = None
+ # A SupplementaryData object, if __traceback_supplement__ was found
+ # (and produced no errors)
+ supplement = None
+ # If accessing __traceback_supplement__ causes any error, the
+ # plain-text traceback is stored here
+ supplement_exception = None
+ # The str() of any __traceback_info__ value found
+ traceback_info = None
+ # The value of __traceback_hide__
+ traceback_hide = False
+ # The value of __traceback_decorator__
+ traceback_decorator = None
+ # The id() of the traceback scope, can be used to reference the
+ # scope for use elsewhere
+ tbid = None
+
+ def get_source_line(self, context=0):
+ """
+ Return the source of the current line of this frame. You
+ probably want to .strip() it as well, as it is likely to have
+ leading whitespace.
+
+ If context is given, then that many lines on either side will
+ also be returned. E.g., context=1 will give 3 lines.
+ """
+ if not self.filename or not self.lineno:
+ return None
+ lines = []
+ for lineno in range(self.lineno-context, self.lineno+context+1):
+ lines.append(linecache.getline(self.filename, lineno))
+ return ''.join(lines)
+
+if hasattr(sys, 'tracebacklimit'):
+ limit = min(limit, sys.tracebacklimit)
+
+col = ExceptionCollector()
+
+def collect_exception(t, v, tb, limit=None):
+ """
+ Collection an exception from ``sys.exc_info()``.
+
+ Use like::
+
+ try:
+ blah blah
+ except:
+ exc_data = collect_exception(*sys.exc_info())
+ """
+ return col.collectException(t, v, tb, limit=limit)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/errormiddleware.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/errormiddleware.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/errormiddleware.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,460 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Error handler middleware
+"""
+import sys
+import traceback
+import cgi
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+from paste.exceptions import formatter, collector, reporter
+from paste import wsgilib
+from paste import request
+
+__all__ = ['ErrorMiddleware', 'handle_exception']
+
+class _NoDefault(object):
+ def __repr__(self):
+ return '<NoDefault>'
+NoDefault = _NoDefault()
+
+class ErrorMiddleware(object):
+
+ """
+ Error handling middleware
+
+ Usage::
+
+ error_catching_wsgi_app = ErrorMiddleware(wsgi_app)
+
+ Settings:
+
+ ``debug``:
+ If true, then tracebacks will be shown in the browser.
+
+ ``error_email``:
+ an email address (or list of addresses) to send exception
+ reports to
+
+ ``error_log``:
+ a filename to append tracebacks to
+
+ ``show_exceptions_in_wsgi_errors``:
+ If true, then errors will be printed to ``wsgi.errors``
+ (frequently a server error log, or stderr).
+
+ ``from_address``, ``smtp_server``, ``error_subject_prefix``, ``smtp_username``, ``smtp_password``, ``smtp_use_tls``:
+ variables to control the emailed exception reports
+
+ ``error_message``:
+ When debug mode is off, the error message to show to users.
+
+ ``xmlhttp_key``:
+ When this key (default ``_``) is in the request GET variables
+ (not POST!), expect that this is an XMLHttpRequest, and the
+ response should be more minimal; it should not be a complete
+ HTML page.
+
+ Environment Configuration:
+
+ ``paste.throw_errors``:
+ If this setting in the request environment is true, then this
+ middleware is disabled. This can be useful in a testing situation
+ where you don't want errors to be caught and transformed.
+
+ ``paste.expected_exceptions``:
+ When this middleware encounters an exception listed in this
+ environment variable and when the ``start_response`` has not
+ yet occurred, the exception will be re-raised instead of being
+ caught. This should generally be set by middleware that may
+ (but probably shouldn't be) installed above this middleware,
+ and wants to get certain exceptions. Exceptions raised after
+ ``start_response`` have been called are always caught since
+ by definition they are no longer expected.
+
+ """
+
+ def __init__(self, application, global_conf=None,
+ debug=NoDefault,
+ error_email=None,
+ error_log=None,
+ show_exceptions_in_wsgi_errors=NoDefault,
+ from_address=None,
+ smtp_server=None,
+ smtp_username=None,
+ smtp_password=None,
+ smtp_use_tls=False,
+ error_subject_prefix=None,
+ error_message=None,
+ xmlhttp_key=None):
+ from paste.util import converters
+ self.application = application
+ # @@: global_conf should be handled elsewhere in a separate
+ # function for the entry point
+ if global_conf is None:
+ global_conf = {}
+ if debug is NoDefault:
+ debug = converters.asbool(global_conf.get('debug'))
+ if show_exceptions_in_wsgi_errors is NoDefault:
+ show_exceptions_in_wsgi_errors = converters.asbool(global_conf.get('show_exceptions_in_wsgi_errors'))
+ self.debug_mode = converters.asbool(debug)
+ if error_email is None:
+ error_email = (global_conf.get('error_email')
+ or global_conf.get('admin_email')
+ or global_conf.get('webmaster_email')
+ or global_conf.get('sysadmin_email'))
+ self.error_email = converters.aslist(error_email)
+ self.error_log = error_log
+ self.show_exceptions_in_wsgi_errors = show_exceptions_in_wsgi_errors
+ if from_address is None:
+ from_address = global_conf.get('error_from_address', 'errors at localhost')
+ self.from_address = from_address
+ if smtp_server is None:
+ smtp_server = global_conf.get('smtp_server', 'localhost')
+ self.smtp_server = smtp_server
+ self.smtp_username = smtp_username or global_conf.get('smtp_username')
+ self.smtp_password = smtp_password or global_conf.get('smtp_password')
+ self.smtp_use_tls = smtp_use_tls or converters.asbool(global_conf.get('smtp_use_tls'))
+ self.error_subject_prefix = error_subject_prefix or ''
+ if error_message is None:
+ error_message = global_conf.get('error_message')
+ self.error_message = error_message
+ if xmlhttp_key is None:
+ xmlhttp_key = global_conf.get('xmlhttp_key', '_')
+ self.xmlhttp_key = xmlhttp_key
+
+ def __call__(self, environ, start_response):
+ """
+ The WSGI application interface.
+ """
+ # We want to be careful about not sending headers twice,
+ # and the content type that the app has committed to (if there
+ # is an exception in the iterator body of the response)
+ if environ.get('paste.throw_errors'):
+ return self.application(environ, start_response)
+ environ['paste.throw_errors'] = True
+
+ try:
+ __traceback_supplement__ = Supplement, self, environ
+ sr_checker = ResponseStartChecker(start_response)
+ app_iter = self.application(environ, sr_checker)
+ return self.make_catching_iter(app_iter, environ, sr_checker)
+ except:
+ exc_info = sys.exc_info()
+ try:
+ for expect in environ.get('paste.expected_exceptions', []):
+ if isinstance(exc_info[1], expect):
+ raise
+ start_response('500 Internal Server Error',
+ [('content-type', 'text/html')],
+ exc_info)
+ # @@: it would be nice to deal with bad content types here
+ response = self.exception_handler(exc_info, environ)
+ return [response]
+ finally:
+ # clean up locals...
+ exc_info = None
+
+ def make_catching_iter(self, app_iter, environ, sr_checker):
+ if isinstance(app_iter, (list, tuple)):
+ # These don't raise
+ return app_iter
+ return CatchingIter(app_iter, environ, sr_checker, self)
+
+ def exception_handler(self, exc_info, environ):
+ simple_html_error = False
+ if self.xmlhttp_key:
+ get_vars = wsgilib.parse_querystring(environ)
+ if dict(get_vars).get(self.xmlhttp_key):
+ simple_html_error = True
+ return handle_exception(
+ exc_info, environ['wsgi.errors'],
+ html=True,
+ debug_mode=self.debug_mode,
+ error_email=self.error_email,
+ error_log=self.error_log,
+ show_exceptions_in_wsgi_errors=self.show_exceptions_in_wsgi_errors,
+ error_email_from=self.from_address,
+ smtp_server=self.smtp_server,
+ smtp_username=self.smtp_username,
+ smtp_password=self.smtp_password,
+ smtp_use_tls=self.smtp_use_tls,
+ error_subject_prefix=self.error_subject_prefix,
+ error_message=self.error_message,
+ simple_html_error=simple_html_error)
+
+class ResponseStartChecker(object):
+ def __init__(self, start_response):
+ self.start_response = start_response
+ self.response_started = False
+
+ def __call__(self, *args):
+ self.response_started = True
+ self.start_response(*args)
+
+class CatchingIter(object):
+
+ """
+ A wrapper around the application iterator that will catch
+ exceptions raised by the a generator, or by the close method, and
+ display or report as necessary.
+ """
+
+ def __init__(self, app_iter, environ, start_checker, error_middleware):
+ self.app_iterable = app_iter
+ self.app_iterator = iter(app_iter)
+ self.environ = environ
+ self.start_checker = start_checker
+ self.error_middleware = error_middleware
+ self.closed = False
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ __traceback_supplement__ = (
+ Supplement, self.error_middleware, self.environ)
+ if self.closed:
+ raise StopIteration
+ try:
+ return self.app_iterator.next()
+ except StopIteration:
+ self.closed = True
+ close_response = self._close()
+ if close_response is not None:
+ return close_response
+ else:
+ raise StopIteration
+ except:
+ self.closed = True
+ close_response = self._close()
+ exc_info = sys.exc_info()
+ response = self.error_middleware.exception_handler(
+ exc_info, self.environ)
+ if close_response is not None:
+ response += (
+ '<hr noshade>Error in .close():<br>%s'
+ % close_response)
+
+ if not self.start_checker.response_started:
+ self.start_checker('500 Internal Server Error',
+ [('content-type', 'text/html')],
+ exc_info)
+
+ return response
+
+ def close(self):
+ # This should at least print something to stderr if the
+ # close method fails at this point
+ if not self.closed:
+ self._close()
+
+ def _close(self):
+ """Close and return any error message"""
+ if not hasattr(self.app_iterable, 'close'):
+ return None
+ try:
+ self.app_iterable.close()
+ return None
+ except:
+ close_response = self.error_middleware.exception_handler(
+ sys.exc_info(), self.environ)
+ return close_response
+
+
+class Supplement(object):
+
+ """
+ This is a supplement used to display standard WSGI information in
+ the traceback.
+ """
+
+ def __init__(self, middleware, environ):
+ self.middleware = middleware
+ self.environ = environ
+ self.source_url = request.construct_url(environ)
+
+ def extraData(self):
+ data = {}
+ cgi_vars = data[('extra', 'CGI Variables')] = {}
+ wsgi_vars = data[('extra', 'WSGI Variables')] = {}
+ hide_vars = ['paste.config', 'wsgi.errors', 'wsgi.input',
+ 'wsgi.multithread', 'wsgi.multiprocess',
+ 'wsgi.run_once', 'wsgi.version',
+ 'wsgi.url_scheme']
+ for name, value in self.environ.items():
+ if name.upper() == name:
+ if value:
+ cgi_vars[name] = value
+ elif name not in hide_vars:
+ wsgi_vars[name] = value
+ if self.environ['wsgi.version'] != (1, 0):
+ wsgi_vars['wsgi.version'] = self.environ['wsgi.version']
+ proc_desc = tuple([int(bool(self.environ[key]))
+ for key in ('wsgi.multiprocess',
+ 'wsgi.multithread',
+ 'wsgi.run_once')])
+ wsgi_vars['wsgi process'] = self.process_combos[proc_desc]
+ wsgi_vars['application'] = self.middleware.application
+ if 'paste.config' in self.environ:
+ data[('extra', 'Configuration')] = dict(self.environ['paste.config'])
+ return data
+
+ process_combos = {
+ # multiprocess, multithread, run_once
+ (0, 0, 0): 'Non-concurrent server',
+ (0, 1, 0): 'Multithreaded',
+ (1, 0, 0): 'Multiprocess',
+ (1, 1, 0): 'Multi process AND threads (?)',
+ (0, 0, 1): 'Non-concurrent CGI',
+ (0, 1, 1): 'Multithread CGI (?)',
+ (1, 0, 1): 'CGI',
+ (1, 1, 1): 'Multi thread/process CGI (?)',
+ }
+
+def handle_exception(exc_info, error_stream, html=True,
+ debug_mode=False,
+ error_email=None,
+ error_log=None,
+ show_exceptions_in_wsgi_errors=False,
+ error_email_from='errors at localhost',
+ smtp_server='localhost',
+ smtp_username=None,
+ smtp_password=None,
+ smtp_use_tls=False,
+ error_subject_prefix='',
+ error_message=None,
+ simple_html_error=False,
+ ):
+ """
+ For exception handling outside of a web context
+
+ Use like::
+
+ import sys
+ from paste.exceptions.errormiddleware import handle_exception
+ try:
+ do stuff
+ except:
+ handle_exception(
+ sys.exc_info(), sys.stderr, html=False, ...other config...)
+
+ If you want to report, but not fully catch the exception, call
+ ``raise`` after ``handle_exception``, which (when given no argument)
+ will reraise the exception.
+ """
+ reported = False
+ exc_data = collector.collect_exception(*exc_info)
+ extra_data = ''
+ if error_email:
+ rep = reporter.EmailReporter(
+ to_addresses=error_email,
+ from_address=error_email_from,
+ smtp_server=smtp_server,
+ smtp_username=smtp_username,
+ smtp_password=smtp_password,
+ smtp_use_tls=smtp_use_tls,
+ subject_prefix=error_subject_prefix)
+ rep_err = send_report(rep, exc_data, html=html)
+ if rep_err:
+ extra_data += rep_err
+ else:
+ reported = True
+ if error_log:
+ rep = reporter.LogReporter(
+ filename=error_log)
+ rep_err = send_report(rep, exc_data, html=html)
+ if rep_err:
+ extra_data += rep_err
+ else:
+ reported = True
+ if show_exceptions_in_wsgi_errors:
+ rep = reporter.FileReporter(
+ file=error_stream)
+ rep_err = send_report(rep, exc_data, html=html)
+ if rep_err:
+ extra_data += rep_err
+ else:
+ reported = True
+ else:
+ error_stream.write('Error - %s: %s\n' % (
+ exc_data.exception_type, exc_data.exception_value))
+ if html:
+ if debug_mode and simple_html_error:
+ return_error = formatter.format_html(
+ exc_data, include_hidden_frames=False,
+ include_reusable=False, show_extra_data=False)
+ reported = True
+ elif debug_mode and not simple_html_error:
+ error_html = formatter.format_html(
+ exc_data,
+ include_hidden_frames=True,
+ include_reusable=False)
+ head_html = formatter.error_css + formatter.hide_display_js
+ return_error = error_template(
+ head_html, error_html, extra_data)
+ extra_data = ''
+ reported = True
+ else:
+ msg = error_message or '''
+ An error occurred. See the error logs for more information.
+ (Turn debug on to display exception reports here)
+ '''
+ return_error = error_template('', msg, '')
+ else:
+ return_error = None
+ if not reported and error_stream:
+ err_report = formatter.format_text(exc_data, show_hidden_frames=True)
+ err_report += '\n' + '-'*60 + '\n'
+ error_stream.write(err_report)
+ if extra_data:
+ error_stream.write(extra_data)
+ return return_error
+
+def send_report(rep, exc_data, html=True):
+ try:
+ rep.report(exc_data)
+ except:
+ output = StringIO()
+ traceback.print_exc(file=output)
+ if html:
+ return """
+ <p>Additionally an error occurred while sending the %s report:
+
+ <pre>%s</pre>
+ </p>""" % (
+ cgi.escape(str(rep)), output.getvalue())
+ else:
+ return (
+ "Additionally an error occurred while sending the "
+ "%s report:\n%s" % (str(rep), output.getvalue()))
+ else:
+ return ''
+
+def error_template(head_html, exception, extra):
+ return '''
+ <html>
+ <head>
+ <title>Server Error</title>
+ %s
+ </head>
+ <body>
+ <h1>Server Error</h1>
+ %s
+ %s
+ </body>
+ </html>''' % (head_html, exception, extra)
+
+def make_error_middleware(app, global_conf, **kw):
+ return ErrorMiddleware(app, global_conf=global_conf, **kw)
+
+doc_lines = ErrorMiddleware.__doc__.splitlines(True)
+for i in range(len(doc_lines)):
+ if doc_lines[i].strip().startswith('Settings'):
+ make_error_middleware.__doc__ = ''.join(doc_lines[i:])
+ break
+del i, doc_lines
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/formatter.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/formatter.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/formatter.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,564 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Formatters for the exception data that comes from ExceptionCollector.
+"""
+# @@: TODO:
+# Use this: http://www.zope.org/Members/tino/VisualTraceback/VisualTracebackNews
+
+import cgi
+import re
+from paste.util import PySourceColor
+
+def html_quote(s):
+ return cgi.escape(str(s), True)
+
+class AbstractFormatter(object):
+
+ general_data_order = ['object', 'source_url']
+
+ def __init__(self, show_hidden_frames=False,
+ include_reusable=True,
+ show_extra_data=True,
+ trim_source_paths=()):
+ self.show_hidden_frames = show_hidden_frames
+ self.trim_source_paths = trim_source_paths
+ self.include_reusable = include_reusable
+ self.show_extra_data = show_extra_data
+
+ def format_collected_data(self, exc_data):
+ general_data = {}
+ if self.show_extra_data:
+ for name, value_list in exc_data.extra_data.items():
+ if isinstance(name, tuple):
+ importance, title = name
+ else:
+ importance, title = 'normal', name
+ for value in value_list:
+ general_data[(importance, name)] = self.format_extra_data(
+ importance, title, value)
+ lines = []
+ frames = self.filter_frames(exc_data.frames)
+ for frame in frames:
+ sup = frame.supplement
+ if sup:
+ if sup.object:
+ general_data[('important', 'object')] = self.format_sup_object(
+ sup.object)
+ if sup.source_url:
+ general_data[('important', 'source_url')] = self.format_sup_url(
+ sup.source_url)
+ if sup.line:
+ lines.append(self.format_sup_line_pos(sup.line, sup.column))
+ if sup.expression:
+ lines.append(self.format_sup_expression(sup.expression))
+ if sup.warnings:
+ for warning in sup.warnings:
+ lines.append(self.format_sup_warning(warning))
+ if sup.info:
+ lines.extend(self.format_sup_info(sup.info))
+ if frame.supplement_exception:
+ lines.append('Exception in supplement:')
+ lines.append(self.quote_long(frame.supplement_exception))
+ if frame.traceback_info:
+ lines.append(self.format_traceback_info(frame.traceback_info))
+ filename = frame.filename
+ if filename and self.trim_source_paths:
+ for path, repl in self.trim_source_paths:
+ if filename.startswith(path):
+ filename = repl + filename[len(path):]
+ break
+ lines.append(self.format_source_line(filename or '?', frame))
+ source = frame.get_source_line()
+ long_source = frame.get_source_line(2)
+ if source:
+ lines.append(self.format_long_source(
+ source, long_source))
+ etype = exc_data.exception_type
+ if not isinstance(etype, basestring):
+ etype = etype.__name__
+ exc_info = self.format_exception_info(
+ etype,
+ exc_data.exception_value)
+ data_by_importance = {'important': [], 'normal': [],
+ 'supplemental': [], 'extra': []}
+ for (importance, name), value in general_data.items():
+ data_by_importance[importance].append(
+ (name, value))
+ for value in data_by_importance.values():
+ value.sort()
+ return self.format_combine(data_by_importance, lines, exc_info)
+
+ def filter_frames(self, frames):
+ """
+ Removes any frames that should be hidden, according to the
+ values of traceback_hide, self.show_hidden_frames, and the
+ hidden status of the final frame.
+ """
+ if self.show_hidden_frames:
+ return frames
+ new_frames = []
+ hidden = False
+ for frame in frames:
+ hide = frame.traceback_hide
+ # @@: It would be nice to signal a warning if an unknown
+ # hide string was used, but I'm not sure where to put
+ # that warning.
+ if hide == 'before':
+ new_frames = []
+ hidden = False
+ elif hide == 'before_and_this':
+ new_frames = []
+ hidden = False
+ continue
+ elif hide == 'reset':
+ hidden = False
+ elif hide == 'reset_and_this':
+ hidden = False
+ continue
+ elif hide == 'after':
+ hidden = True
+ elif hide == 'after_and_this':
+ hidden = True
+ continue
+ elif hide:
+ continue
+ elif hidden:
+ continue
+ new_frames.append(frame)
+ if frames[-1] not in new_frames:
+ # We must include the last frame; that we don't indicates
+ # that the error happened where something was "hidden",
+ # so we just have to show everything
+ return frames
+ return new_frames
+
+ def pretty_string_repr(self, s):
+ """
+ Formats the string as a triple-quoted string when it contains
+ newlines.
+ """
+ if '\n' in s:
+ s = repr(s)
+ s = s[0]*3 + s[1:-1] + s[-1]*3
+ s = s.replace('\\n', '\n')
+ return s
+ else:
+ return repr(s)
+
+ def long_item_list(self, lst):
+ """
+ Returns true if the list contains items that are long, and should
+ be more nicely formatted.
+ """
+ how_many = 0
+ for item in lst:
+ if len(repr(item)) > 40:
+ how_many += 1
+ if how_many >= 3:
+ return True
+ return False
+
+class TextFormatter(AbstractFormatter):
+
+ def quote(self, s):
+ return s
+ def quote_long(self, s):
+ return s
+ def emphasize(self, s):
+ return s
+ def format_sup_object(self, obj):
+ return 'In object: %s' % self.emphasize(self.quote(repr(obj)))
+ def format_sup_url(self, url):
+ return 'URL: %s' % self.quote(url)
+ def format_sup_line_pos(self, line, column):
+ if column:
+ return self.emphasize('Line %i, Column %i' % (line, column))
+ else:
+ return self.emphasize('Line %i' % line)
+ def format_sup_expression(self, expr):
+ return self.emphasize('In expression: %s' % self.quote(expr))
+ def format_sup_warning(self, warning):
+ return 'Warning: %s' % self.quote(warning)
+ def format_sup_info(self, info):
+ return [self.quote_long(info)]
+ def format_source_line(self, filename, frame):
+ return 'File %r, line %s in %s' % (
+ filename, frame.lineno or '?', frame.name or '?')
+ def format_long_source(self, source, long_source):
+ return self.format_source(source)
+ def format_source(self, source_line):
+ return ' ' + self.quote(source_line.strip())
+ def format_exception_info(self, etype, evalue):
+ return self.emphasize(
+ '%s: %s' % (self.quote(etype), self.quote(evalue)))
+ def format_traceback_info(self, info):
+ return info
+
+ def format_combine(self, data_by_importance, lines, exc_info):
+ lines[:0] = [value for n, value in data_by_importance['important']]
+ lines.append(exc_info)
+ for name in 'normal', 'supplemental', 'extra':
+ lines.extend([value for n, value in data_by_importance[name]])
+ return self.format_combine_lines(lines)
+
+ def format_combine_lines(self, lines):
+ return '\n'.join(lines)
+
+ def format_extra_data(self, importance, title, value):
+ if isinstance(value, str):
+ s = self.pretty_string_repr(value)
+ if '\n' in s:
+ return '%s:\n%s' % (title, s)
+ else:
+ return '%s: %s' % (title, s)
+ elif isinstance(value, dict):
+ lines = ['\n', title, '-'*len(title)]
+ items = value.items()
+ items.sort()
+ for n, v in items:
+ try:
+ v = repr(v)
+ except Exception, e:
+ v = 'Cannot display: %s' % e
+ v = truncate(v)
+ lines.append(' %s: %s' % (n, v))
+ return '\n'.join(lines)
+ elif (isinstance(value, (list, tuple))
+ and self.long_item_list(value)):
+ parts = [truncate(repr(v)) for v in value]
+ return '%s: [\n %s]' % (
+ title, ',\n '.join(parts))
+ else:
+ return '%s: %s' % (title, truncate(repr(value)))
+
+class HTMLFormatter(TextFormatter):
+
+ def quote(self, s):
+ return html_quote(s)
+ def quote_long(self, s):
+ return '<pre>%s</pre>' % self.quote(s)
+ def emphasize(self, s):
+ return '<b>%s</b>' % s
+ def format_sup_url(self, url):
+ return 'URL: <a href="%s">%s</a>' % (url, url)
+ def format_combine_lines(self, lines):
+ return '<br>\n'.join(lines)
+ def format_source_line(self, filename, frame):
+ name = self.quote(frame.name or '?')
+ return 'Module <span class="module" title="%s">%s</span>:<b>%s</b> in <code>%s</code>' % (
+ filename, frame.modname or '?', frame.lineno or '?',
+ name)
+ return 'File %r, line %s in <tt>%s</tt>' % (
+ filename, frame.lineno, name)
+ def format_long_source(self, source, long_source):
+ q_long_source = str2html(long_source, False, 4, True)
+ q_source = str2html(source, True, 0, False)
+ return ('<code style="display: none" class="source" source-type="long"><a class="switch_source" onclick="return switch_source(this, \'long\')" href="#"><< </a>%s</code>'
+ '<code class="source" source-type="short"><a onclick="return switch_source(this, \'short\')" class="switch_source" href="#">>> </a>%s</code>'
+ % (q_long_source,
+ q_source))
+ def format_source(self, source_line):
+ return ' <code class="source">%s</code>' % self.quote(source_line.strip())
+ def format_traceback_info(self, info):
+ return '<pre>%s</pre>' % self.quote(info)
+
+ def format_extra_data(self, importance, title, value):
+ if isinstance(value, str):
+ s = self.pretty_string_repr(value)
+ if '\n' in s:
+ return '%s:<br><pre>%s</pre>' % (title, self.quote(s))
+ else:
+ return '%s: <tt>%s</tt>' % (title, self.quote(s))
+ elif isinstance(value, dict):
+ return self.zebra_table(title, value)
+ elif (isinstance(value, (list, tuple))
+ and self.long_item_list(value)):
+ return '%s: <tt>[<br>\n %s]</tt>' % (
+ title, ',<br> '.join(map(self.quote, map(repr, value))))
+ else:
+ return '%s: <tt>%s</tt>' % (title, self.quote(repr(value)))
+
+ def format_combine(self, data_by_importance, lines, exc_info):
+ lines[:0] = [value for n, value in data_by_importance['important']]
+ lines.append(exc_info)
+ for name in 'normal', 'supplemental':
+ lines.extend([value for n, value in data_by_importance[name]])
+ if data_by_importance['extra']:
+ lines.append(
+ '<script type="text/javascript">\nshow_button(\'extra_data\', \'extra data\');\n</script>\n' +
+ '<div id="extra_data" class="hidden-data">\n')
+ lines.extend([value for n, value in data_by_importance['extra']])
+ lines.append('</div>')
+ text = self.format_combine_lines(lines)
+ if self.include_reusable:
+ return error_css + hide_display_js + text
+ else:
+ # Usually because another error is already on this page,
+ # and so the js & CSS are unneeded
+ return text
+
+ def zebra_table(self, title, rows, table_class="variables"):
+ if isinstance(rows, dict):
+ rows = rows.items()
+ rows.sort()
+ table = ['<table class="%s">' % table_class,
+ '<tr class="header"><th colspan="2">%s</th></tr>'
+ % self.quote(title)]
+ odd = False
+ for name, value in rows:
+ try:
+ value = repr(value)
+ except Exception, e:
+ value = 'Cannot print: %s' % e
+ odd = not odd
+ table.append(
+ '<tr class="%s"><td>%s</td>'
+ % (odd and 'odd' or 'even', self.quote(name)))
+ table.append(
+ '<td><tt>%s</tt></td></tr>'
+ % make_wrappable(self.quote(truncate(value))))
+ table.append('</table>')
+ return '\n'.join(table)
+
+hide_display_js = r'''
+<script type="text/javascript">
+function hide_display(id) {
+ var el = document.getElementById(id);
+ if (el.className == "hidden-data") {
+ el.className = "";
+ return true;
+ } else {
+ el.className = "hidden-data";
+ return false;
+ }
+}
+document.write('<style type="text/css">\n');
+document.write('.hidden-data {display: none}\n');
+document.write('</style>\n');
+function show_button(toggle_id, name) {
+ document.write('<a href="#' + toggle_id
+ + '" onclick="javascript:hide_display(\'' + toggle_id
+ + '\')" class="button">' + name + '</a><br>');
+}
+
+function switch_source(el, hide_type) {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == hide_type) {
+ break;
+ }
+ el = el.parentNode;
+ }
+ if (! el) {
+ return false;
+ }
+ el.style.display = 'none';
+ if (hide_type == 'long') {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == 'short') {
+ break;
+ }
+ el = el.nextSibling;
+ }
+ } else {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == 'long') {
+ break;
+ }
+ el = el.previousSibling;
+ }
+ }
+ if (el) {
+ el.style.display = '';
+ }
+ return false;
+}
+
+</script>'''
+
+
+error_css = """
+<style type="text/css">
+body {
+ font-family: Helvetica, sans-serif;
+}
+
+table {
+ width: 100%;
+}
+
+tr.header {
+ background-color: #006;
+ color: #fff;
+}
+
+tr.even {
+ background-color: #ddd;
+}
+
+table.variables td {
+ vertical-align: top;
+ overflow: auto;
+}
+
+a.button {
+ background-color: #ccc;
+ border: 2px outset #aaa;
+ color: #000;
+ text-decoration: none;
+}
+
+a.button:hover {
+ background-color: #ddd;
+}
+
+code.source {
+ color: #006;
+}
+
+a.switch_source {
+ color: #090;
+ text-decoration: none;
+}
+
+a.switch_source:hover {
+ background-color: #ddd;
+}
+
+.source-highlight {
+ background-color: #ff9;
+}
+
+</style>
+"""
+
+def format_html(exc_data, include_hidden_frames=False, **ops):
+ if not include_hidden_frames:
+ return HTMLFormatter(**ops).format_collected_data(exc_data)
+ short_er = format_html(exc_data, show_hidden_frames=False, **ops)
+ # @@: This should have a way of seeing if the previous traceback
+ # was actually trimmed at all
+ ops['include_reusable'] = False
+ ops['show_extra_data'] = False
+ long_er = format_html(exc_data, show_hidden_frames=True, **ops)
+ text_er = format_text(exc_data, show_hidden_frames=True, **ops)
+ return """
+ %s
+ <br>
+ <script type="text/javascript">
+ show_button('full_traceback', 'full traceback')
+ </script>
+ <div id="full_traceback" class="hidden-data">
+ %s
+ </div>
+ <br>
+ <script type="text/javascript">
+ show_button('text_version', 'text version')
+ </script>
+ <div id="text_version" class="hidden-data">
+ <textarea style="width: 100%%" rows=10 cols=60>%s</textarea>
+ </div>
+ """ % (short_er, long_er, cgi.escape(text_er))
+
+def format_text(exc_data, **ops):
+ return TextFormatter(**ops).format_collected_data(exc_data)
+
+whitespace_re = re.compile(r' +')
+pre_re = re.compile(r'</?pre.*?>')
+error_re = re.compile(r'<h3>ERROR: .*?</h3>')
+
+def str2html(src, strip=False, indent_subsequent=0,
+ highlight_inner=False):
+ """
+ Convert a string to HTML. Try to be really safe about it,
+ returning a quoted version of the string if nothing else works.
+ """
+ try:
+ return _str2html(src, strip=strip,
+ indent_subsequent=indent_subsequent,
+ highlight_inner=highlight_inner)
+ except:
+ return html_quote(src)
+
+def _str2html(src, strip=False, indent_subsequent=0,
+ highlight_inner=False):
+ if strip:
+ src = src.strip()
+ orig_src = src
+ try:
+ src = PySourceColor.str2html(src, form='snip')
+ src = error_re.sub('', src)
+ src = pre_re.sub('', src)
+ src = re.sub(r'^[\n\r]{0,1}', '', src)
+ src = re.sub(r'[\n\r]{0,1}$', '', src)
+ except:
+ src = html_quote(orig_src)
+ lines = src.splitlines()
+ if len(lines) == 1:
+ return lines[0]
+ indent = ' '*indent_subsequent
+ for i in range(1, len(lines)):
+ lines[i] = indent+lines[i]
+ if highlight_inner and i == len(lines)/2:
+ lines[i] = '<span class="source-highlight">%s</span>' % lines[i]
+ src = '<br>\n'.join(lines)
+ src = whitespace_re.sub(
+ lambda m: ' '*(len(m.group(0))-1) + ' ', src)
+ return src
+
+def truncate(string, limit=1000):
+ """
+ Truncate the string to the limit number of
+ characters
+ """
+ if len(string) > limit:
+ return string[:limit-20]+'...'+string[-17:]
+ else:
+ return string
+
+def make_wrappable(html, wrap_limit=60,
+ split_on=';?&@!$#-/\\"\''):
+ # Currently using <wbr>, maybe should use ​
+ # http://www.cs.tut.fi/~jkorpela/html/nobr.html
+ if len(html) <= wrap_limit:
+ return html
+ words = html.split()
+ new_words = []
+ for word in words:
+ wrapped_word = ''
+ while len(word) > wrap_limit:
+ for char in split_on:
+ if char in word:
+ first, rest = word.split(char, 1)
+ wrapped_word += first+char+'<wbr>'
+ word = rest
+ break
+ else:
+ for i in range(0, len(word), wrap_limit):
+ wrapped_word += word[i:i+wrap_limit]+'<wbr>'
+ word = ''
+ wrapped_word += word
+ new_words.append(wrapped_word)
+ return ' '.join(new_words)
+
+def make_pre_wrappable(html, wrap_limit=60,
+ split_on=';?&@!$#-/\\"\''):
+ """
+ Like ``make_wrappable()`` but intended for text that will
+ go in a ``<pre>`` block, so wrap on a line-by-line basis.
+ """
+ lines = html.splitlines()
+ new_lines = []
+ for line in lines:
+ if len(line) > wrap_limit:
+ for char in split_on:
+ if char in line:
+ parts = line.split(char)
+ line = '<wbr>'.join(parts)
+ break
+ new_lines.append(line)
+ return '\n'.join(lines)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/reporter.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/reporter.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/reporter.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,141 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+from email.MIMEText import MIMEText
+from email.MIMEMultipart import MIMEMultipart
+import smtplib
+import time
+try:
+ from socket import sslerror
+except ImportError:
+ sslerror = None
+from paste.exceptions import formatter
+
+class Reporter(object):
+
+ def __init__(self, **conf):
+ for name, value in conf.items():
+ if not hasattr(self, name):
+ raise TypeError(
+ "The keyword argument %s was not expected"
+ % name)
+ setattr(self, name, value)
+ self.check_params()
+
+ def check_params(self):
+ pass
+
+ def format_date(self, exc_data):
+ return time.strftime('%c', exc_data.date)
+
+ def format_html(self, exc_data, **kw):
+ return formatter.format_html(exc_data, **kw)
+
+ def format_text(self, exc_data, **kw):
+ return formatter.format_text(exc_data, **kw)
+
+class EmailReporter(Reporter):
+
+ to_addresses = None
+ from_address = None
+ smtp_server = 'localhost'
+ smtp_username = None
+ smtp_password = None
+ smtp_use_tls = False
+ subject_prefix = ''
+
+ def report(self, exc_data):
+ msg = self.assemble_email(exc_data)
+ server = smtplib.SMTP(self.smtp_server)
+ if self.smtp_use_tls:
+ server.ehlo()
+ server.starttls()
+ server.ehlo()
+ if self.smtp_username and self.smtp_password:
+ server.login(self.smtp_username, self.smtp_password)
+ server.sendmail(self.from_address,
+ self.to_addresses, msg.as_string())
+ try:
+ server.quit()
+ except sslerror:
+ # sslerror is raised in tls connections on closing sometimes
+ pass
+
+ def check_params(self):
+ if not self.to_addresses:
+ raise ValueError("You must set to_addresses")
+ if not self.from_address:
+ raise ValueError("You must set from_address")
+ if isinstance(self.to_addresses, (str, unicode)):
+ self.to_addresses = [self.to_addresses]
+
+ def assemble_email(self, exc_data):
+ short_html_version = self.format_html(
+ exc_data, show_hidden_frames=False)
+ long_html_version = self.format_html(
+ exc_data, show_hidden_frames=True)
+ text_version = self.format_text(
+ exc_data, show_hidden_frames=False)
+ msg = MIMEMultipart()
+ msg.set_type('multipart/alternative')
+ msg.preamble = msg.epilogue = ''
+ text_msg = MIMEText(text_version)
+ text_msg.set_type('text/plain')
+ text_msg.set_param('charset', 'ASCII')
+ msg.attach(text_msg)
+ html_msg = MIMEText(short_html_version)
+ html_msg.set_type('text/html')
+ # @@: Correct character set?
+ html_msg.set_param('charset', 'UTF-8')
+ html_long = MIMEText(long_html_version)
+ html_long.set_type('text/html')
+ html_long.set_param('charset', 'UTF-8')
+ msg.attach(html_msg)
+ msg.attach(html_long)
+ subject = '%s: %s' % (exc_data.exception_type,
+ formatter.truncate(str(exc_data.exception_value)))
+ msg['Subject'] = self.subject_prefix + subject
+ msg['From'] = self.from_address
+ msg['To'] = ', '.join(self.to_addresses)
+ return msg
+
+class LogReporter(Reporter):
+
+ filename = None
+ show_hidden_frames = True
+
+ def check_params(self):
+ assert self.filename is not None, (
+ "You must give a filename")
+
+ def report(self, exc_data):
+ text = self.format_text(
+ exc_data, show_hidden_frames=self.show_hidden_frames)
+ f = open(self.filename, 'a')
+ try:
+ f.write(text + '\n' + '-'*60 + '\n')
+ finally:
+ f.close()
+
+class FileReporter(Reporter):
+
+ file = None
+ show_hidden_frames = True
+
+ def check_params(self):
+ assert self.file is not None, (
+ "You must give a file object")
+
+ def report(self, exc_data):
+ text = self.format_text(
+ exc_data, show_hidden_frames=self.show_hidden_frames)
+ self.file.write(text + '\n' + '-'*60 + '\n')
+
+class WSGIAppReporter(Reporter):
+
+ def __init__(self, exc_data):
+ self.exc_data = exc_data
+
+ def __call__(self, environ, start_response):
+ start_response('500 Server Error', [('Content-type', 'text/html')])
+ return [formatter.format_html(self.exc_data)]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/serial_number_generator.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/serial_number_generator.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/exceptions/serial_number_generator.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,123 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Creates a human-readable identifier, using numbers and digits,
+avoiding ambiguous numbers and letters. hash_identifier can be used
+to create compact representations that are unique for a certain string
+(or concatenation of strings)
+"""
+
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+
+good_characters = "23456789abcdefghjkmnpqrtuvwxyz"
+
+base = len(good_characters)
+
+def make_identifier(number):
+ """
+ Encodes a number as an identifier.
+ """
+ if not isinstance(number, (int, long)):
+ raise ValueError(
+ "You can only make identifiers out of integers (not %r)"
+ % number)
+ if number < 0:
+ raise ValueError(
+ "You cannot make identifiers out of negative numbers: %r"
+ % number)
+ result = []
+ while number:
+ next = number % base
+ result.append(good_characters[next])
+ # Note, this depends on integer rounding of results:
+ number = number / base
+ return ''.join(result)
+
+def hash_identifier(s, length, pad=True, hasher=md5, prefix='',
+ group=None, upper=False):
+ """
+ Hashes the string (with the given hashing module), then turns that
+ hash into an identifier of the given length (using modulo to
+ reduce the length of the identifier). If ``pad`` is False, then
+ the minimum-length identifier will be used; otherwise the
+ identifier will be padded with 0's as necessary.
+
+ ``prefix`` will be added last, and does not count towards the
+ target length. ``group`` will group the characters with ``-`` in
+ the given lengths, and also does not count towards the target
+ length. E.g., ``group=4`` will cause a identifier like
+ ``a5f3-hgk3-asdf``. Grouping occurs before the prefix.
+ """
+ if not callable(hasher):
+ # Accept sha/md5 modules as well as callables
+ hasher = hasher.new
+ if length > 26 and hasher is md5:
+ raise ValueError, (
+ "md5 cannot create hashes longer than 26 characters in "
+ "length (you gave %s)" % length)
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ h = hasher(str(s))
+ bin_hash = h.digest()
+ modulo = base ** length
+ number = 0
+ for c in list(bin_hash):
+ number = (number * 256 + ord(c)) % modulo
+ ident = make_identifier(number)
+ if pad:
+ ident = good_characters[0]*(length-len(ident)) + ident
+ if group:
+ parts = []
+ while ident:
+ parts.insert(0, ident[-group:])
+ ident = ident[:-group]
+ ident = '-'.join(parts)
+ if upper:
+ ident = ident.upper()
+ return prefix + ident
+
+# doctest tests:
+__test__ = {
+ 'make_identifier': """
+ >>> make_identifier(0)
+ ''
+ >>> make_identifier(1000)
+ 'c53'
+ >>> make_identifier(-100)
+ Traceback (most recent call last):
+ ...
+ ValueError: You cannot make identifiers out of negative numbers: -100
+ >>> make_identifier('test')
+ Traceback (most recent call last):
+ ...
+ ValueError: You can only make identifiers out of integers (not 'test')
+ >>> make_identifier(1000000000000)
+ 'c53x9rqh3'
+ """,
+ 'hash_identifier': """
+ >>> hash_identifier(0, 5)
+ 'cy2dr'
+ >>> hash_identifier(0, 10)
+ 'cy2dr6rg46'
+ >>> hash_identifier('this is a test of a long string', 5)
+ 'awatu'
+ >>> hash_identifier(0, 26)
+ 'cy2dr6rg46cx8t4w2f3nfexzk4'
+ >>> hash_identifier(0, 30)
+ Traceback (most recent call last):
+ ...
+ ValueError: md5 cannot create hashes longer than 26 characters in length (you gave 30)
+ >>> hash_identifier(0, 10, group=4)
+ 'cy-2dr6-rg46'
+ >>> hash_identifier(0, 10, group=4, upper=True, prefix='M-')
+ 'M-CY-2DR6-RG46'
+ """}
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fileapp.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fileapp.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fileapp.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,354 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Ian Bicking, Clark C. Evans and contributors
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+This module handles sending static content such as in-memory data or
+files. At this time it has cache helpers and understands the
+if-modified-since request header.
+"""
+
+import os, time, mimetypes, zipfile, tarfile
+from paste.httpexceptions import *
+from paste.httpheaders import *
+
+CACHE_SIZE = 4096
+BLOCK_SIZE = 4096 * 16
+
+__all__ = ['DataApp', 'FileApp', 'DirectoryApp', 'ArchiveStore']
+
+class DataApp(object):
+ """
+ Returns an application that will send content in a single chunk,
+ this application has support for setting cache-control and for
+ responding to conditional (or HEAD) requests.
+
+ Constructor Arguments:
+
+ ``content`` the content being sent to the client
+
+ ``headers`` the headers to send /w the response
+
+ The remaining ``kwargs`` correspond to headers, where the
+ underscore is replaced with a dash. These values are only
+ added to the headers if they are not already provided; thus,
+ they can be used for default values. Examples include, but
+ are not limited to:
+
+ ``content_type``
+ ``content_encoding``
+ ``content_location``
+
+ ``cache_control()``
+
+ This method provides validated construction of the ``Cache-Control``
+ header as well as providing for automated filling out of the
+ ``EXPIRES`` header for HTTP/1.0 clients.
+
+ ``set_content()``
+
+ This method provides a mechanism to set the content after the
+ application has been constructed. This method does things
+ like changing ``Last-Modified`` and ``Content-Length`` headers.
+
+ """
+
+ allowed_methods = ('GET', 'HEAD')
+
+ def __init__(self, content, headers=None, allowed_methods=None,
+ **kwargs):
+ assert isinstance(headers, (type(None), list))
+ self.expires = None
+ self.content = None
+ self.content_length = None
+ self.last_modified = 0
+ if allowed_methods is not None:
+ self.allowed_methods = allowed_methods
+ self.headers = headers or []
+ for (k, v) in kwargs.items():
+ header = get_header(k)
+ header.update(self.headers, v)
+ ACCEPT_RANGES.update(self.headers, bytes=True)
+ if not CONTENT_TYPE(self.headers):
+ CONTENT_TYPE.update(self.headers)
+ if content is not None:
+ self.set_content(content)
+
+ def cache_control(self, **kwargs):
+ self.expires = CACHE_CONTROL.apply(self.headers, **kwargs) or None
+ return self
+
+ def set_content(self, content, last_modified=None):
+ assert content is not None
+ if last_modified is None:
+ self.last_modified = time.time()
+ else:
+ self.last_modified = last_modified
+ self.content = content
+ self.content_length = len(content)
+ LAST_MODIFIED.update(self.headers, time=self.last_modified)
+ return self
+
+ def content_disposition(self, **kwargs):
+ CONTENT_DISPOSITION.apply(self.headers, **kwargs)
+ return self
+
+ def __call__(self, environ, start_response):
+ method = environ['REQUEST_METHOD'].upper()
+ if method not in self.allowed_methods:
+ exc = HTTPMethodNotAllowed(
+ 'You cannot %s a file' % method,
+ headers=[('Allow', ','.join(self.allowed_methods))])
+ return exc(environ, start_response)
+ return self.get(environ, start_response)
+
+ def calculate_etag(self):
+ return '"%s-%s"' % (self.last_modified, self.content_length)
+
+ def get(self, environ, start_response):
+ headers = self.headers[:]
+ current_etag = self.calculate_etag()
+ ETAG.update(headers, current_etag)
+ if self.expires is not None:
+ EXPIRES.update(headers, delta=self.expires)
+
+ try:
+ client_etags = IF_NONE_MATCH.parse(environ)
+ if client_etags:
+ for etag in client_etags:
+ if etag == current_etag or etag == '*':
+ # horribly inefficient, n^2 performance, yuck!
+ for head in list_headers(entity=True):
+ head.delete(headers)
+ start_response('304 Not Modified', headers)
+ return ['']
+ except HTTPBadRequest, exce:
+ return exce.wsgi_application(environ, start_response)
+
+ # If we get If-None-Match and If-Modified-Since, and
+ # If-None-Match doesn't match, then we should not try to
+ # figure out If-Modified-Since (which has 1-second granularity
+ # and just isn't as accurate)
+ if not client_etags:
+ try:
+ client_clock = IF_MODIFIED_SINCE.parse(environ)
+ if client_clock >= int(self.last_modified):
+ # horribly inefficient, n^2 performance, yuck!
+ for head in list_headers(entity=True):
+ head.delete(headers)
+ start_response('304 Not Modified', headers)
+ return [''] # empty body
+ except HTTPBadRequest, exce:
+ return exce.wsgi_application(environ, start_response)
+
+ (lower, upper) = (0, self.content_length - 1)
+ range = RANGE.parse(environ)
+ if range and 'bytes' == range[0] and 1 == len(range[1]):
+ (lower, upper) = range[1][0]
+ upper = upper or (self.content_length - 1)
+ if upper >= self.content_length or lower > upper:
+ return HTTPRequestRangeNotSatisfiable((
+ "Range request was made beyond the end of the content,\r\n"
+ "which is %s long.\r\n Range: %s\r\n") % (
+ self.content_length, RANGE(environ))
+ ).wsgi_application(environ, start_response)
+
+ content_length = upper - lower + 1
+ CONTENT_RANGE.update(headers, first_byte=lower, last_byte=upper,
+ total_length = self.content_length)
+ CONTENT_LENGTH.update(headers, content_length)
+ if content_length == self.content_length:
+ start_response('200 OK', headers)
+ else:
+ start_response('206 Partial Content', headers)
+ if self.content is not None:
+ return [self.content[lower:upper+1]]
+ return (lower, content_length)
+
+class FileApp(DataApp):
+ """
+ Returns an application that will send the file at the given
+ filename. Adds a mime type based on ``mimetypes.guess_type()``.
+ See DataApp for the arguments beyond ``filename``.
+ """
+
+ def __init__(self, filename, headers=None, **kwargs):
+ self.filename = filename
+ content_type, content_encoding = self.guess_type()
+ if content_type and 'content_type' not in kwargs:
+ kwargs['content_type'] = content_type
+ if content_encoding and 'content_encoding' not in kwargs:
+ kwargs['content_encoding'] = content_encoding
+ DataApp.__init__(self, None, headers, **kwargs)
+
+ def guess_type(self):
+ return mimetypes.guess_type(self.filename)
+
+ def update(self, force=False):
+ stat = os.stat(self.filename)
+ if not force and stat.st_mtime == self.last_modified:
+ return
+ self.last_modified = stat.st_mtime
+ if stat.st_size < CACHE_SIZE:
+ fh = open(self.filename,"rb")
+ self.set_content(fh.read(), stat.st_mtime)
+ fh.close()
+ else:
+ self.content = None
+ self.content_length = stat.st_size
+ # This is updated automatically if self.set_content() is
+ # called
+ LAST_MODIFIED.update(self.headers, time=self.last_modified)
+
+ def get(self, environ, start_response):
+ is_head = environ['REQUEST_METHOD'].upper() == 'HEAD'
+ if 'max-age=0' in CACHE_CONTROL(environ).lower():
+ self.update(force=True) # RFC 2616 13.2.6
+ else:
+ self.update()
+ if not self.content:
+ if not os.path.exists(self.filename):
+ exc = HTTPNotFound(
+ 'The resource does not exist',
+ comment="No file at %r" % self.filename)
+ return exc(environ, start_response)
+ try:
+ file = open(self.filename, 'rb')
+ except (IOError, OSError), e:
+ exc = HTTPForbidden(
+ 'You are not permitted to view this file (%s)' % e)
+ return exc.wsgi_application(
+ environ, start_response)
+ retval = DataApp.get(self, environ, start_response)
+ if isinstance(retval, list):
+ # cached content, exception, or not-modified
+ if is_head:
+ return ['']
+ return retval
+ (lower, content_length) = retval
+ if is_head:
+ return ['']
+ file.seek(lower)
+ file_wrapper = environ.get('wsgi.file_wrapper', None)
+ if file_wrapper:
+ return file_wrapper(file, BLOCK_SIZE)
+ else:
+ return _FileIter(file, size=content_length)
+
+class _FileIter(object):
+
+ def __init__(self, file, block_size=None, size=None):
+ self.file = file
+ self.size = size
+ self.block_size = block_size or BLOCK_SIZE
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ chunk_size = self.block_size
+ if self.size is not None:
+ if chunk_size > self.size:
+ chunk_size = self.size
+ self.size -= chunk_size
+ data = self.file.read(chunk_size)
+ if not data:
+ raise StopIteration
+ return data
+
+ def close(self):
+ self.file.close()
+
+
+class DirectoryApp(object):
+ """
+ Returns an application that dispatches requests to corresponding FileApps based on PATH_INFO.
+ FileApp instances are cached. This app makes sure not to serve any files that are not in a subdirectory.
+ To customize FileApp creation override ``DirectoryApp.make_fileapp``
+ """
+
+ def __init__(self, path):
+ self.path = os.path.abspath(path)
+ if not self.path.endswith(os.path.sep):
+ self.path += os.path.sep
+ assert os.path.isdir(self.path)
+ self.cached_apps = {}
+
+ make_fileapp = FileApp
+
+ def __call__(self, environ, start_response):
+ path_info = environ['PATH_INFO']
+ app = self.cached_apps.get(path_info)
+ if app is None:
+ path = os.path.join(self.path, path_info.lstrip('/'))
+ if not os.path.normpath(path).startswith(self.path):
+ app = HTTPForbidden()
+ elif os.path.isfile(path):
+ app = self.make_fileapp(path)
+ self.cached_apps[path_info] = app
+ else:
+ app = HTTPNotFound(comment=path)
+ return app(environ, start_response)
+
+
+class ArchiveStore(object):
+ """
+ Returns an application that serves up a DataApp for items requested
+ in a given zip or tar archive.
+
+ Constructor Arguments:
+
+ ``filepath`` the path to the archive being served
+
+ ``cache_control()``
+
+ This method provides validated construction of the ``Cache-Control``
+ header as well as providing for automated filling out of the
+ ``EXPIRES`` header for HTTP/1.0 clients.
+ """
+
+ def __init__(self, filepath):
+ if zipfile.is_zipfile(filepath):
+ self.archive = zipfile.ZipFile(filepath,"r")
+ elif tarfile.is_tarfile(filepath):
+ self.archive = tarfile.TarFileCompat(filepath,"r")
+ else:
+ raise AssertionError("filepath '%s' is not a zip or tar " % filepath)
+ self.expires = None
+ self.last_modified = time.time()
+ self.cache = {}
+
+ def cache_control(self, **kwargs):
+ self.expires = CACHE_CONTROL.apply(self.headers, **kwargs) or None
+ return self
+
+ def __call__(self, environ, start_response):
+ path = environ.get("PATH_INFO","")
+ if path.startswith("/"):
+ path = path[1:]
+ application = self.cache.get(path)
+ if application:
+ return application(environ, start_response)
+ try:
+ info = self.archive.getinfo(path)
+ except KeyError:
+ exc = HTTPNotFound("The file requested, '%s', was not found." % path)
+ return exc.wsgi_application(environ, start_response)
+ if info.filename.endswith("/"):
+ exc = HTTPNotFound("Path requested, '%s', is not a file." % path)
+ return exc.wsgi_application(environ, start_response)
+ content_type, content_encoding = mimetypes.guess_type(info.filename)
+ # 'None' is not a valid content-encoding, so don't set the header if
+ # mimetypes.guess_type returns None
+ if content_encoding is not None:
+ app = DataApp(None, content_type = content_type,
+ content_encoding = content_encoding)
+ else:
+ app = DataApp(None, content_type = content_type)
+ app.set_content(self.archive.read(path),
+ time.mktime(info.date_time + (0,0,0)))
+ self.cache[path] = app
+ app.expires = self.expires
+ return app(environ, start_response)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fixture.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fixture.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/fixture.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1725 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Routines for testing WSGI applications.
+
+Most interesting is the `TestApp <class-paste.fixture.TestApp.html>`_
+for testing WSGI applications, and the `TestFileEnvironment
+<class-paste.fixture.TestFileEnvironment.html>`_ class for testing the
+effects of command-line scripts.
+"""
+
+import sys
+import random
+import urllib
+import urlparse
+import mimetypes
+import time
+import cgi
+import os
+import shutil
+import smtplib
+import shlex
+from Cookie import BaseCookie
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+import re
+try:
+ import subprocess
+except ImportError:
+ from paste.util import subprocess24 as subprocess
+
+from paste import wsgilib
+from paste import lint
+from paste.response import HeaderDict
+
+def tempnam_no_warning(*args):
+ """
+ An os.tempnam with the warning turned off, because sometimes
+ you just need to use this and don't care about the stupid
+ security warning.
+ """
+ return os.tempnam(*args)
+
+class NoDefault(object):
+ pass
+
+def sorted(l):
+ l = list(l)
+ l.sort()
+ return l
+
+class Dummy_smtplib(object):
+
+ existing = None
+
+ def __init__(self, server):
+ import warnings
+ warnings.warn(
+ 'Dummy_smtplib is not maintained and is deprecated',
+ DeprecationWarning, 2)
+ assert not self.existing, (
+ "smtplib.SMTP() called again before Dummy_smtplib.existing.reset() "
+ "called.")
+ self.server = server
+ self.open = True
+ self.__class__.existing = self
+
+ def quit(self):
+ assert self.open, (
+ "Called %s.quit() twice" % self)
+ self.open = False
+
+ def sendmail(self, from_address, to_addresses, msg):
+ self.from_address = from_address
+ self.to_addresses = to_addresses
+ self.message = msg
+
+ def install(cls):
+ smtplib.SMTP = cls
+
+ install = classmethod(install)
+
+ def reset(self):
+ assert not self.open, (
+ "SMTP connection not quit")
+ self.__class__.existing = None
+
+class AppError(Exception):
+ pass
+
+class TestApp(object):
+
+ # for py.test
+ disabled = True
+
+ def __init__(self, app, namespace=None, relative_to=None,
+ extra_environ=None, pre_request_hook=None,
+ post_request_hook=None):
+ """
+ Wraps a WSGI application in a more convenient interface for
+ testing.
+
+ ``app`` may be an application, or a Paste Deploy app
+ URI, like ``'config:filename.ini#test'``.
+
+ ``namespace`` is a dictionary that will be written to (if
+ provided). This can be used with doctest or some other
+ system, and the variable ``res`` will be assigned everytime
+ you make a request (instead of returning the request).
+
+ ``relative_to`` is a directory, and filenames used for file
+ uploads are calculated relative to this. Also ``config:``
+ URIs that aren't absolute.
+
+ ``extra_environ`` is a dictionary of values that should go
+ into the environment for each request. These can provide a
+ communication channel with the application.
+
+ ``pre_request_hook`` is a function to be called prior to
+ making requests (such as ``post`` or ``get``). This function
+ must take one argument (the instance of the TestApp).
+
+ ``post_request_hook`` is a function, similar to
+ ``pre_request_hook``, to be called after requests are made.
+ """
+ if isinstance(app, (str, unicode)):
+ from paste.deploy import loadapp
+ # @@: Should pick up relative_to from calling module's
+ # __file__
+ app = loadapp(app, relative_to=relative_to)
+ self.app = app
+ self.namespace = namespace
+ self.relative_to = relative_to
+ if extra_environ is None:
+ extra_environ = {}
+ self.extra_environ = extra_environ
+ self.pre_request_hook = pre_request_hook
+ self.post_request_hook = post_request_hook
+ self.reset()
+
+ def reset(self):
+ """
+ Resets the state of the application; currently just clears
+ saved cookies.
+ """
+ self.cookies = {}
+
+ def _make_environ(self):
+ environ = self.extra_environ.copy()
+ environ['paste.throw_errors'] = True
+ return environ
+
+ def get(self, url, params=None, headers=None, extra_environ=None,
+ status=None, expect_errors=False):
+ """
+ Get the given url (well, actually a path like
+ ``'/page.html'``).
+
+ ``params``:
+ A query string, or a dictionary that will be encoded
+ into a query string. You may also include a query
+ string on the ``url``.
+
+ ``headers``:
+ A dictionary of extra headers to send.
+
+ ``extra_environ``:
+ A dictionary of environmental variables that should
+ be added to the request.
+
+ ``status``:
+ The integer status code you expect (if not 200 or 3xx).
+ If you expect a 404 response, for instance, you must give
+ ``status=404`` or it will be an error. You can also give
+ a wildcard, like ``'3*'`` or ``'*'``.
+
+ ``expect_errors``:
+ If this is not true, then if anything is written to
+ ``wsgi.errors`` it will be an error. If it is true, then
+ non-200/3xx responses are also okay.
+
+ Returns a `response object
+ <class-paste.fixture.TestResponse.html>`_
+ """
+ if extra_environ is None:
+ extra_environ = {}
+ # Hide from py.test:
+ __tracebackhide__ = True
+ if params:
+ if not isinstance(params, (str, unicode)):
+ params = urllib.urlencode(params, doseq=True)
+ if '?' in url:
+ url += '&'
+ else:
+ url += '?'
+ url += params
+ environ = self._make_environ()
+ url = str(url)
+ if '?' in url:
+ url, environ['QUERY_STRING'] = url.split('?', 1)
+ else:
+ environ['QUERY_STRING'] = ''
+ self._set_headers(headers, environ)
+ environ.update(extra_environ)
+ req = TestRequest(url, environ, expect_errors)
+ return self.do_request(req, status=status)
+
+ def _gen_request(self, method, url, params='', headers=None, extra_environ=None,
+ status=None, upload_files=None, expect_errors=False):
+ """
+ Do a generic request.
+ """
+ if headers is None:
+ headers = {}
+ if extra_environ is None:
+ extra_environ = {}
+ environ = self._make_environ()
+ # @@: Should this be all non-strings?
+ if isinstance(params, (list, tuple, dict)):
+ params = urllib.urlencode(params)
+ if hasattr(params, 'items'):
+ # Some other multi-dict like format
+ params = urllib.urlencode(params.items())
+ if upload_files:
+ params = cgi.parse_qsl(params, keep_blank_values=True)
+ content_type, params = self.encode_multipart(
+ params, upload_files)
+ environ['CONTENT_TYPE'] = content_type
+ elif params:
+ environ.setdefault('CONTENT_TYPE', 'application/x-www-form-urlencoded')
+ if '?' in url:
+ url, environ['QUERY_STRING'] = url.split('?', 1)
+ else:
+ environ['QUERY_STRING'] = ''
+ environ['CONTENT_LENGTH'] = str(len(params))
+ environ['REQUEST_METHOD'] = method
+ environ['wsgi.input'] = StringIO(params)
+ self._set_headers(headers, environ)
+ environ.update(extra_environ)
+ req = TestRequest(url, environ, expect_errors)
+ return self.do_request(req, status=status)
+
+ def post(self, url, params='', headers=None, extra_environ=None,
+ status=None, upload_files=None, expect_errors=False):
+ """
+ Do a POST request. Very like the ``.get()`` method.
+ ``params`` are put in the body of the request.
+
+ ``upload_files`` is for file uploads. It should be a list of
+ ``[(fieldname, filename, file_content)]``. You can also use
+ just ``[(fieldname, filename)]`` and the file content will be
+ read from disk.
+
+ Returns a `response object
+ <class-paste.fixture.TestResponse.html>`_
+ """
+ return self._gen_request('POST', url, params=params, headers=headers,
+ extra_environ=extra_environ,status=status,
+ upload_files=upload_files,
+ expect_errors=expect_errors)
+
+ def put(self, url, params='', headers=None, extra_environ=None,
+ status=None, upload_files=None, expect_errors=False):
+ """
+ Do a PUT request. Very like the ``.get()`` method.
+ ``params`` are put in the body of the request.
+
+ ``upload_files`` is for file uploads. It should be a list of
+ ``[(fieldname, filename, file_content)]``. You can also use
+ just ``[(fieldname, filename)]`` and the file content will be
+ read from disk.
+
+ Returns a `response object
+ <class-paste.fixture.TestResponse.html>`_
+ """
+ return self._gen_request('PUT', url, params=params, headers=headers,
+ extra_environ=extra_environ,status=status,
+ upload_files=upload_files,
+ expect_errors=expect_errors)
+
+ def delete(self, url, params='', headers=None, extra_environ=None,
+ status=None, expect_errors=False):
+ """
+ Do a DELETE request. Very like the ``.get()`` method.
+ ``params`` are put in the body of the request.
+
+ Returns a `response object
+ <class-paste.fixture.TestResponse.html>`_
+ """
+ return self._gen_request('DELETE', url, params=params, headers=headers,
+ extra_environ=extra_environ,status=status,
+ upload_files=None, expect_errors=expect_errors)
+
+
+
+
+ def _set_headers(self, headers, environ):
+ """
+ Turn any headers into environ variables
+ """
+ if not headers:
+ return
+ for header, value in headers.items():
+ if header.lower() == 'content-type':
+ var = 'CONTENT_TYPE'
+ elif header.lower() == 'content-length':
+ var = 'CONTENT_LENGTH'
+ else:
+ var = 'HTTP_%s' % header.replace('-', '_').upper()
+ environ[var] = value
+
+ def encode_multipart(self, params, files):
+ """
+ Encodes a set of parameters (typically a name/value list) and
+ a set of files (a list of (name, filename, file_body)) into a
+ typical POST body, returning the (content_type, body).
+ """
+ boundary = '----------a_BoUnDaRy%s$' % random.random()
+ lines = []
+ for key, value in params:
+ lines.append('--'+boundary)
+ lines.append('Content-Disposition: form-data; name="%s"' % key)
+ lines.append('')
+ lines.append(value)
+ for file_info in files:
+ key, filename, value = self._get_file_info(file_info)
+ lines.append('--'+boundary)
+ lines.append('Content-Disposition: form-data; name="%s"; filename="%s"'
+ % (key, filename))
+ fcontent = mimetypes.guess_type(filename)[0]
+ lines.append('Content-Type: %s' %
+ fcontent or 'application/octet-stream')
+ lines.append('')
+ lines.append(value)
+ lines.append('--' + boundary + '--')
+ lines.append('')
+ body = '\r\n'.join(lines)
+ content_type = 'multipart/form-data; boundary=%s' % boundary
+ return content_type, body
+
+ def _get_file_info(self, file_info):
+ if len(file_info) == 2:
+ # It only has a filename
+ filename = file_info[1]
+ if self.relative_to:
+ filename = os.path.join(self.relative_to, filename)
+ f = open(filename, 'rb')
+ content = f.read()
+ f.close()
+ return (file_info[0], filename, content)
+ elif len(file_info) == 3:
+ return file_info
+ else:
+ raise ValueError(
+ "upload_files need to be a list of tuples of (fieldname, "
+ "filename, filecontent) or (fieldname, filename); "
+ "you gave: %r"
+ % repr(file_info)[:100])
+
+ def do_request(self, req, status):
+ """
+ Executes the given request (``req``), with the expected
+ ``status``. Generally ``.get()`` and ``.post()`` are used
+ instead.
+ """
+ if self.pre_request_hook:
+ self.pre_request_hook(self)
+ __tracebackhide__ = True
+ if self.cookies:
+ c = BaseCookie()
+ for name, value in self.cookies.items():
+ c[name] = value
+ hc = '; '.join(['='.join([m.key, m.value]) for m in c.values()])
+ req.environ['HTTP_COOKIE'] = hc
+ req.environ['paste.testing'] = True
+ req.environ['paste.testing_variables'] = {}
+ app = lint.middleware(self.app)
+ old_stdout = sys.stdout
+ out = CaptureStdout(old_stdout)
+ try:
+ sys.stdout = out
+ start_time = time.time()
+ raise_on_wsgi_error = not req.expect_errors
+ raw_res = wsgilib.raw_interactive(
+ app, req.url,
+ raise_on_wsgi_error=raise_on_wsgi_error,
+ **req.environ)
+ end_time = time.time()
+ finally:
+ sys.stdout = old_stdout
+ sys.stderr.write(out.getvalue())
+ res = self._make_response(raw_res, end_time - start_time)
+ res.request = req
+ for name, value in req.environ['paste.testing_variables'].items():
+ if hasattr(res, name):
+ raise ValueError(
+ "paste.testing_variables contains the variable %r, but "
+ "the response object already has an attribute by that "
+ "name" % name)
+ setattr(res, name, value)
+ if self.namespace is not None:
+ self.namespace['res'] = res
+ if not req.expect_errors:
+ self._check_status(status, res)
+ self._check_errors(res)
+ res.cookies_set = {}
+ for header in res.all_headers('set-cookie'):
+ c = BaseCookie(header)
+ for key, morsel in c.items():
+ self.cookies[key] = morsel.value
+ res.cookies_set[key] = morsel.value
+ if self.post_request_hook:
+ self.post_request_hook(self)
+ if self.namespace is None:
+ # It's annoying to return the response in doctests, as it'll
+ # be printed, so we only return it is we couldn't assign
+ # it anywhere
+ return res
+
+ def _check_status(self, status, res):
+ __tracebackhide__ = True
+ if status == '*':
+ return
+ if isinstance(status, (list, tuple)):
+ if res.status not in status:
+ raise AppError(
+ "Bad response: %s (not one of %s for %s)\n%s"
+ % (res.full_status, ', '.join(map(str, status)),
+ res.request.url, res.body))
+ return
+ if status is None:
+ if res.status >= 200 and res.status < 400:
+ return
+ raise AppError(
+ "Bad response: %s (not 200 OK or 3xx redirect for %s)\n%s"
+ % (res.full_status, res.request.url,
+ res.body))
+ if status != res.status:
+ raise AppError(
+ "Bad response: %s (not %s)" % (res.full_status, status))
+
+ def _check_errors(self, res):
+ if res.errors:
+ raise AppError(
+ "Application had errors logged:\n%s" % res.errors)
+
+ def _make_response(self, (status, headers, body, errors), total_time):
+ return TestResponse(self, status, headers, body, errors,
+ total_time)
+
+class CaptureStdout(object):
+
+ def __init__(self, actual):
+ self.captured = StringIO()
+ self.actual = actual
+
+ def write(self, s):
+ self.captured.write(s)
+ self.actual.write(s)
+
+ def flush(self):
+ self.actual.flush()
+
+ def writelines(self, lines):
+ for item in lines:
+ self.write(item)
+
+ def getvalue(self):
+ return self.captured.getvalue()
+
+class TestResponse(object):
+
+ # for py.test
+ disabled = True
+
+ """
+ Instances of this class are return by `TestApp
+ <class-paste.fixture.TestApp.html>`_
+ """
+
+ def __init__(self, test_app, status, headers, body, errors,
+ total_time):
+ self.test_app = test_app
+ self.status = int(status.split()[0])
+ self.full_status = status
+ self.headers = headers
+ self.header_dict = HeaderDict.fromlist(self.headers)
+ self.body = body
+ self.errors = errors
+ self._normal_body = None
+ self.time = total_time
+ self._forms_indexed = None
+
+ def forms__get(self):
+ """
+ Returns a dictionary of ``Form`` objects. Indexes are both in
+ order (from zero) and by form id (if the form is given an id).
+ """
+ if self._forms_indexed is None:
+ self._parse_forms()
+ return self._forms_indexed
+
+ forms = property(forms__get,
+ doc="""
+ A list of <form>s found on the page (instances of
+ `Form <class-paste.fixture.Form.html>`_)
+ """)
+
+ def form__get(self):
+ forms = self.forms
+ if not forms:
+ raise TypeError(
+ "You used response.form, but no forms exist")
+ if 1 in forms:
+ # There is more than one form
+ raise TypeError(
+ "You used response.form, but more than one form exists")
+ return forms[0]
+
+ form = property(form__get,
+ doc="""
+ Returns a single `Form
+ <class-paste.fixture.Form.html>`_ instance; it
+ is an error if there are multiple forms on the
+ page.
+ """)
+
+ _tag_re = re.compile(r'<(/?)([:a-z0-9_\-]*)(.*?)>', re.S|re.I)
+
+ def _parse_forms(self):
+ forms = self._forms_indexed = {}
+ form_texts = []
+ started = None
+ for match in self._tag_re.finditer(self.body):
+ end = match.group(1) == '/'
+ tag = match.group(2).lower()
+ if tag != 'form':
+ continue
+ if end:
+ assert started, (
+ "</form> unexpected at %s" % match.start())
+ form_texts.append(self.body[started:match.end()])
+ started = None
+ else:
+ assert not started, (
+ "Nested form tags at %s" % match.start())
+ started = match.start()
+ assert not started, (
+ "Danging form: %r" % self.body[started:])
+ for i, text in enumerate(form_texts):
+ form = Form(self, text)
+ forms[i] = form
+ if form.id:
+ forms[form.id] = form
+
+ def header(self, name, default=NoDefault):
+ """
+ Returns the named header; an error if there is not exactly one
+ matching header (unless you give a default -- always an error
+ if there is more than one header)
+ """
+ found = None
+ for cur_name, value in self.headers:
+ if cur_name.lower() == name.lower():
+ assert not found, (
+ "Ambiguous header: %s matches %r and %r"
+ % (name, found, value))
+ found = value
+ if found is None:
+ if default is NoDefault:
+ raise KeyError(
+ "No header found: %r (from %s)"
+ % (name, ', '.join([n for n, v in self.headers])))
+ else:
+ return default
+ return found
+
+ def all_headers(self, name):
+ """
+ Gets all headers by the ``name``, returns as a list
+ """
+ found = []
+ for cur_name, value in self.headers:
+ if cur_name.lower() == name.lower():
+ found.append(value)
+ return found
+
+ def follow(self, **kw):
+ """
+ If this request is a redirect, follow that redirect. It
+ is an error if this is not a redirect response. Returns
+ another response object.
+ """
+ assert self.status >= 300 and self.status < 400, (
+ "You can only follow redirect responses (not %s)"
+ % self.full_status)
+ location = self.header('location')
+ type, rest = urllib.splittype(location)
+ host, path = urllib.splithost(rest)
+ # @@: We should test that it's not a remote redirect
+ return self.test_app.get(location, **kw)
+
+ def click(self, description=None, linkid=None, href=None,
+ anchor=None, index=None, verbose=False):
+ """
+ Click the link as described. Each of ``description``,
+ ``linkid``, and ``url`` are *patterns*, meaning that they are
+ either strings (regular expressions), compiled regular
+ expressions (objects with a ``search`` method), or callables
+ returning true or false.
+
+ All the given patterns are ANDed together:
+
+ * ``description`` is a pattern that matches the contents of the
+ anchor (HTML and all -- everything between ``<a...>`` and
+ ``</a>``)
+
+ * ``linkid`` is a pattern that matches the ``id`` attribute of
+ the anchor. It will receive the empty string if no id is
+ given.
+
+ * ``href`` is a pattern that matches the ``href`` of the anchor;
+ the literal content of that attribute, not the fully qualified
+ attribute.
+
+ * ``anchor`` is a pattern that matches the entire anchor, with
+ its contents.
+
+ If more than one link matches, then the ``index`` link is
+ followed. If ``index`` is not given and more than one link
+ matches, or if no link matches, then ``IndexError`` will be
+ raised.
+
+ If you give ``verbose`` then messages will be printed about
+ each link, and why it does or doesn't match. If you use
+ ``app.click(verbose=True)`` you'll see a list of all the
+ links.
+
+ You can use multiple criteria to essentially assert multiple
+ aspects about the link, e.g., where the link's destination is.
+ """
+ __tracebackhide__ = True
+ found_html, found_desc, found_attrs = self._find_element(
+ tag='a', href_attr='href',
+ href_extract=None,
+ content=description,
+ id=linkid,
+ href_pattern=href,
+ html_pattern=anchor,
+ index=index, verbose=verbose)
+ return self.goto(found_attrs['uri'])
+
+ def clickbutton(self, description=None, buttonid=None, href=None,
+ button=None, index=None, verbose=False):
+ """
+ Like ``.click()``, except looks for link-like buttons.
+ This kind of button should look like
+ ``<button onclick="...location.href='url'...">``.
+ """
+ __tracebackhide__ = True
+ found_html, found_desc, found_attrs = self._find_element(
+ tag='button', href_attr='onclick',
+ href_extract=re.compile(r"location\.href='(.*?)'"),
+ content=description,
+ id=buttonid,
+ href_pattern=href,
+ html_pattern=button,
+ index=index, verbose=verbose)
+ return self.goto(found_attrs['uri'])
+
+ def _find_element(self, tag, href_attr, href_extract,
+ content, id,
+ href_pattern,
+ html_pattern,
+ index, verbose):
+ content_pat = _make_pattern(content)
+ id_pat = _make_pattern(id)
+ href_pat = _make_pattern(href_pattern)
+ html_pat = _make_pattern(html_pattern)
+
+ _tag_re = re.compile(r'<%s\s+(.*?)>(.*?)</%s>' % (tag, tag),
+ re.I+re.S)
+
+ def printlog(s):
+ if verbose:
+ print s
+
+ found_links = []
+ total_links = 0
+ for match in _tag_re.finditer(self.body):
+ el_html = match.group(0)
+ el_attr = match.group(1)
+ el_content = match.group(2)
+ attrs = _parse_attrs(el_attr)
+ if verbose:
+ printlog('Element: %r' % el_html)
+ if not attrs.get(href_attr):
+ printlog(' Skipped: no %s attribute' % href_attr)
+ continue
+ el_href = attrs[href_attr]
+ if href_extract:
+ m = href_extract.search(el_href)
+ if not m:
+ printlog(" Skipped: doesn't match extract pattern")
+ continue
+ el_href = m.group(1)
+ attrs['uri'] = el_href
+ if el_href.startswith('#'):
+ printlog(' Skipped: only internal fragment href')
+ continue
+ if el_href.startswith('javascript:'):
+ printlog(' Skipped: cannot follow javascript:')
+ continue
+ total_links += 1
+ if content_pat and not content_pat(el_content):
+ printlog(" Skipped: doesn't match description")
+ continue
+ if id_pat and not id_pat(attrs.get('id', '')):
+ printlog(" Skipped: doesn't match id")
+ continue
+ if href_pat and not href_pat(el_href):
+ printlog(" Skipped: doesn't match href")
+ continue
+ if html_pat and not html_pat(el_html):
+ printlog(" Skipped: doesn't match html")
+ continue
+ printlog(" Accepted")
+ found_links.append((el_html, el_content, attrs))
+ if not found_links:
+ raise IndexError(
+ "No matching elements found (from %s possible)"
+ % total_links)
+ if index is None:
+ if len(found_links) > 1:
+ raise IndexError(
+ "Multiple links match: %s"
+ % ', '.join([repr(anc) for anc, d, attr in found_links]))
+ found_link = found_links[0]
+ else:
+ try:
+ found_link = found_links[index]
+ except IndexError:
+ raise IndexError(
+ "Only %s (out of %s) links match; index %s out of range"
+ % (len(found_links), total_links, index))
+ return found_link
+
+ def goto(self, href, method='get', **args):
+ """
+ Go to the (potentially relative) link ``href``, using the
+ given method (``'get'`` or ``'post'``) and any extra arguments
+ you want to pass to the ``app.get()`` or ``app.post()``
+ methods.
+
+ All hostnames and schemes will be ignored.
+ """
+ scheme, host, path, query, fragment = urlparse.urlsplit(href)
+ # We
+ scheme = host = fragment = ''
+ href = urlparse.urlunsplit((scheme, host, path, query, fragment))
+ href = urlparse.urljoin(self.request.full_url, href)
+ method = method.lower()
+ assert method in ('get', 'post'), (
+ 'Only "get" or "post" are allowed for method (you gave %r)'
+ % method)
+ if method == 'get':
+ method = self.test_app.get
+ else:
+ method = self.test_app.post
+ return method(href, **args)
+
+ _normal_body_regex = re.compile(r'[ \n\r\t]+')
+
+ def normal_body__get(self):
+ if self._normal_body is None:
+ self._normal_body = self._normal_body_regex.sub(
+ ' ', self.body)
+ return self._normal_body
+
+ normal_body = property(normal_body__get,
+ doc="""
+ Return the whitespace-normalized body
+ """)
+
+ def __contains__(self, s):
+ """
+ A response 'contains' a string if it is present in the body
+ of the response. Whitespace is normalized when searching
+ for a string.
+ """
+ if not isinstance(s, (str, unicode)):
+ s = str(s)
+ if isinstance(s, unicode):
+ ## FIXME: we don't know that this response uses utf8:
+ s = s.encode('utf8')
+ return (self.body.find(s) != -1
+ or self.normal_body.find(s) != -1)
+
+ def mustcontain(self, *strings, **kw):
+ """
+ Assert that the response contains all of the strings passed
+ in as arguments.
+
+ Equivalent to::
+
+ assert string in res
+ """
+ if 'no' in kw:
+ no = kw['no']
+ del kw['no']
+ if isinstance(no, basestring):
+ no = [no]
+ else:
+ no = []
+ if kw:
+ raise TypeError(
+ "The only keyword argument allowed is 'no'")
+ for s in strings:
+ if not s in self:
+ print >> sys.stderr, "Actual response (no %r):" % s
+ print >> sys.stderr, self
+ raise IndexError(
+ "Body does not contain string %r" % s)
+ for no_s in no:
+ if no_s in self:
+ print >> sys.stderr, "Actual response (has %r)" % no_s
+ print >> sys.stderr, self
+ raise IndexError(
+ "Body contains string %r" % s)
+
+ def __repr__(self):
+ return '<Response %s %r>' % (self.full_status, self.body[:20])
+
+ def __str__(self):
+ simple_body = '\n'.join([l for l in self.body.splitlines()
+ if l.strip()])
+ return 'Response: %s\n%s\n%s' % (
+ self.status,
+ '\n'.join(['%s: %s' % (n, v) for n, v in self.headers]),
+ simple_body)
+
+ def showbrowser(self):
+ """
+ Show this response in a browser window (for debugging purposes,
+ when it's hard to read the HTML).
+ """
+ import webbrowser
+ fn = tempnam_no_warning(None, 'paste-fixture') + '.html'
+ f = open(fn, 'wb')
+ f.write(self.body)
+ f.close()
+ url = 'file:' + fn.replace(os.sep, '/')
+ webbrowser.open_new(url)
+
+class TestRequest(object):
+
+ # for py.test
+ disabled = True
+
+ """
+ Instances of this class are created by `TestApp
+ <class-paste.fixture.TestApp.html>`_ with the ``.get()`` and
+ ``.post()`` methods, and are consumed there by ``.do_request()``.
+
+ Instances are also available as a ``.req`` attribute on
+ `TestResponse <class-paste.fixture.TestResponse.html>`_ instances.
+
+ Useful attributes:
+
+ ``url``:
+ The url (actually usually the path) of the request, without
+ query string.
+
+ ``environ``:
+ The environment dictionary used for the request.
+
+ ``full_url``:
+ The url/path, with query string.
+ """
+
+ def __init__(self, url, environ, expect_errors=False):
+ if url.startswith('http://localhost'):
+ url = url[len('http://localhost'):]
+ self.url = url
+ self.environ = environ
+ if environ.get('QUERY_STRING'):
+ self.full_url = url + '?' + environ['QUERY_STRING']
+ else:
+ self.full_url = url
+ self.expect_errors = expect_errors
+
+
+class Form(object):
+
+ """
+ This object represents a form that has been found in a page.
+ This has a couple useful attributes:
+
+ ``text``:
+ the full HTML of the form.
+
+ ``action``:
+ the relative URI of the action.
+
+ ``method``:
+ the method (e.g., ``'GET'``).
+
+ ``id``:
+ the id, or None if not given.
+
+ ``fields``:
+ a dictionary of fields, each value is a list of fields by
+ that name. ``<input type=\"radio\">`` and ``<select>`` are
+ both represented as single fields with multiple options.
+ """
+
+ # @@: This really should be using Mechanize/ClientForm or
+ # something...
+
+ _tag_re = re.compile(r'<(/?)([:a-z0-9_\-]*)([^>]*?)>', re.I)
+
+ def __init__(self, response, text):
+ self.response = response
+ self.text = text
+ self._parse_fields()
+ self._parse_action()
+
+ def _parse_fields(self):
+ in_select = None
+ in_textarea = None
+ fields = {}
+ for match in self._tag_re.finditer(self.text):
+ end = match.group(1) == '/'
+ tag = match.group(2).lower()
+ if tag not in ('input', 'select', 'option', 'textarea',
+ 'button'):
+ continue
+ if tag == 'select' and end:
+ assert in_select, (
+ '%r without starting select' % match.group(0))
+ in_select = None
+ continue
+ if tag == 'textarea' and end:
+ assert in_textarea, (
+ "</textarea> with no <textarea> at %s" % match.start())
+ in_textarea[0].value = html_unquote(self.text[in_textarea[1]:match.start()])
+ in_textarea = None
+ continue
+ if end:
+ continue
+ attrs = _parse_attrs(match.group(3))
+ if 'name' in attrs:
+ name = attrs.pop('name')
+ else:
+ name = None
+ if tag == 'option':
+ in_select.options.append((attrs.get('value'),
+ 'selected' in attrs))
+ continue
+ if tag == 'input' and attrs.get('type') == 'radio':
+ field = fields.get(name)
+ if not field:
+ field = Radio(self, tag, name, match.start(), **attrs)
+ fields.setdefault(name, []).append(field)
+ else:
+ field = field[0]
+ assert isinstance(field, Radio)
+ field.options.append((attrs.get('value'),
+ 'checked' in attrs))
+ continue
+ tag_type = tag
+ if tag == 'input':
+ tag_type = attrs.get('type', 'text').lower()
+ FieldClass = Field.classes.get(tag_type, Field)
+ field = FieldClass(self, tag, name, match.start(), **attrs)
+ if tag == 'textarea':
+ assert not in_textarea, (
+ "Nested textareas: %r and %r"
+ % (in_textarea, match.group(0)))
+ in_textarea = field, match.end()
+ elif tag == 'select':
+ assert not in_select, (
+ "Nested selects: %r and %r"
+ % (in_select, match.group(0)))
+ in_select = field
+ fields.setdefault(name, []).append(field)
+ self.fields = fields
+
+ def _parse_action(self):
+ self.action = None
+ for match in self._tag_re.finditer(self.text):
+ end = match.group(1) == '/'
+ tag = match.group(2).lower()
+ if tag != 'form':
+ continue
+ if end:
+ break
+ attrs = _parse_attrs(match.group(3))
+ self.action = attrs.get('action', '')
+ self.method = attrs.get('method', 'GET')
+ self.id = attrs.get('id')
+ # @@: enctype?
+ else:
+ assert 0, "No </form> tag found"
+ assert self.action is not None, (
+ "No <form> tag found")
+
+ def __setitem__(self, name, value):
+ """
+ Set the value of the named field. If there is 0 or multiple
+ fields by that name, it is an error.
+
+ Setting the value of a ``<select>`` selects the given option
+ (and confirms it is an option). Setting radio fields does the
+ same. Checkboxes get boolean values. You cannot set hidden
+ fields or buttons.
+
+ Use ``.set()`` if there is any ambiguity and you must provide
+ an index.
+ """
+ fields = self.fields.get(name)
+ assert fields is not None, (
+ "No field by the name %r found (fields: %s)"
+ % (name, ', '.join(map(repr, self.fields.keys()))))
+ assert len(fields) == 1, (
+ "Multiple fields match %r: %s"
+ % (name, ', '.join(map(repr, fields))))
+ fields[0].value = value
+
+ def __getitem__(self, name):
+ """
+ Get the named field object (ambiguity is an error).
+ """
+ fields = self.fields.get(name)
+ assert fields is not None, (
+ "No field by the name %r found" % name)
+ assert len(fields) == 1, (
+ "Multiple fields match %r: %s"
+ % (name, ', '.join(map(repr, fields))))
+ return fields[0]
+
+ def set(self, name, value, index=None):
+ """
+ Set the given name, using ``index`` to disambiguate.
+ """
+ if index is None:
+ self[name] = value
+ else:
+ fields = self.fields.get(name)
+ assert fields is not None, (
+ "No fields found matching %r" % name)
+ field = fields[index]
+ field.value = value
+
+ def get(self, name, index=None, default=NoDefault):
+ """
+ Get the named/indexed field object, or ``default`` if no field
+ is found.
+ """
+ fields = self.fields.get(name)
+ if fields is None and default is not NoDefault:
+ return default
+ if index is None:
+ return self[name]
+ else:
+ fields = self.fields.get(name)
+ assert fields is not None, (
+ "No fields found matching %r" % name)
+ field = fields[index]
+ return field
+
+ def select(self, name, value, index=None):
+ """
+ Like ``.set()``, except also confirms the target is a
+ ``<select>``.
+ """
+ field = self.get(name, index=index)
+ assert isinstance(field, Select)
+ field.value = value
+
+ def submit(self, name=None, index=None, **args):
+ """
+ Submits the form. If ``name`` is given, then also select that
+ button (using ``index`` to disambiguate)``.
+
+ Any extra keyword arguments are passed to the ``.get()`` or
+ ``.post()`` method.
+
+ Returns a response object.
+ """
+ fields = self.submit_fields(name, index=index)
+ return self.response.goto(self.action, method=self.method,
+ params=fields, **args)
+
+ def submit_fields(self, name=None, index=None):
+ """
+ Return a list of ``[(name, value), ...]`` for the current
+ state of the form.
+ """
+ submit = []
+ if name is not None:
+ field = self.get(name, index=index)
+ submit.append((field.name, field.value_if_submitted()))
+ for name, fields in self.fields.items():
+ if name is None:
+ continue
+ for field in fields:
+ value = field.value
+ if value is None:
+ continue
+ submit.append((name, value))
+ return submit
+
+
+_attr_re = re.compile(r'([^= \n\r\t]+)[ \n\r\t]*(?:=[ \n\r\t]*(?:"([^"]*)"|([^"][^ \n\r\t>]*)))?', re.S)
+
+def _parse_attrs(text):
+ attrs = {}
+ for match in _attr_re.finditer(text):
+ attr_name = match.group(1).lower()
+ attr_body = match.group(2) or match.group(3)
+ attr_body = html_unquote(attr_body or '')
+ attrs[attr_name] = attr_body
+ return attrs
+
+class Field(object):
+
+ """
+ Field object.
+ """
+
+ # Dictionary of field types (select, radio, etc) to classes
+ classes = {}
+
+ settable = True
+
+ def __init__(self, form, tag, name, pos,
+ value=None, id=None, **attrs):
+ self.form = form
+ self.tag = tag
+ self.name = name
+ self.pos = pos
+ self._value = value
+ self.id = id
+ self.attrs = attrs
+
+ def value__set(self, value):
+ if not self.settable:
+ raise AttributeError(
+ "You cannot set the value of the <%s> field %r"
+ % (self.tag, self.name))
+ self._value = value
+
+ def force_value(self, value):
+ """
+ Like setting a value, except forces it even for, say, hidden
+ fields.
+ """
+ self._value = value
+
+ def value__get(self):
+ return self._value
+
+ value = property(value__get, value__set)
+
+class Select(Field):
+
+ """
+ Field representing ``<select>``
+ """
+
+ def __init__(self, *args, **attrs):
+ super(Select, self).__init__(*args, **attrs)
+ self.options = []
+ self.multiple = attrs.get('multiple')
+ assert not self.multiple, (
+ "<select multiple> not yet supported")
+ # Undetermined yet:
+ self.selectedIndex = None
+
+ def value__set(self, value):
+ for i, (option, checked) in enumerate(self.options):
+ if option == str(value):
+ self.selectedIndex = i
+ break
+ else:
+ raise ValueError(
+ "Option %r not found (from %s)"
+ % (value, ', '.join(
+ [repr(o) for o, c in self.options])))
+
+ def value__get(self):
+ if self.selectedIndex is not None:
+ return self.options[self.selectedIndex][0]
+ else:
+ for option, checked in self.options:
+ if checked:
+ return option
+ else:
+ if self.options:
+ return self.options[0][0]
+ else:
+ return None
+
+ value = property(value__get, value__set)
+
+Field.classes['select'] = Select
+
+class Radio(Select):
+
+ """
+ Field representing ``<input type="radio">``
+ """
+
+Field.classes['radio'] = Radio
+
+class Checkbox(Field):
+
+ """
+ Field representing ``<input type="checkbox">``
+ """
+
+ def __init__(self, *args, **attrs):
+ super(Checkbox, self).__init__(*args, **attrs)
+ self.checked = 'checked' in attrs
+
+ def value__set(self, value):
+ self.checked = not not value
+
+ def value__get(self):
+ if self.checked:
+ if self._value is None:
+ return 'on'
+ else:
+ return self._value
+ else:
+ return None
+
+ value = property(value__get, value__set)
+
+Field.classes['checkbox'] = Checkbox
+
+class Text(Field):
+ """
+ Field representing ``<input type="text">``
+ """
+ def __init__(self, form, tag, name, pos,
+ value='', id=None, **attrs):
+ #text fields default to empty string
+ Field.__init__(self, form, tag, name, pos,
+ value=value, id=id, **attrs)
+
+Field.classes['text'] = Text
+
+class Textarea(Text):
+ """
+ Field representing ``<textarea>``
+ """
+
+Field.classes['textarea'] = Textarea
+
+class Hidden(Text):
+ """
+ Field representing ``<input type="hidden">``
+ """
+
+Field.classes['hidden'] = Hidden
+
+class Submit(Field):
+ """
+ Field representing ``<input type="submit">`` and ``<button>``
+ """
+
+ settable = False
+
+ def value__get(self):
+ return None
+
+ value = property(value__get)
+
+ def value_if_submitted(self):
+ return self._value
+
+Field.classes['submit'] = Submit
+
+Field.classes['button'] = Submit
+
+Field.classes['image'] = Submit
+
+############################################################
+## Command-line testing
+############################################################
+
+
+class TestFileEnvironment(object):
+
+ """
+ This represents an environment in which files will be written, and
+ scripts will be run.
+ """
+
+ # for py.test
+ disabled = True
+
+ def __init__(self, base_path, template_path=None,
+ script_path=None,
+ environ=None, cwd=None, start_clear=True,
+ ignore_paths=None, ignore_hidden=True):
+ """
+ Creates an environment. ``base_path`` is used as the current
+ working directory, and generally where changes are looked for.
+
+ ``template_path`` is the directory to look for *template*
+ files, which are files you'll explicitly add to the
+ environment. This is done with ``.writefile()``.
+
+ ``script_path`` is the PATH for finding executables. Usually
+ grabbed from ``$PATH``.
+
+ ``environ`` is the operating system environment,
+ ``os.environ`` if not given.
+
+ ``cwd`` is the working directory, ``base_path`` by default.
+
+ If ``start_clear`` is true (default) then the ``base_path``
+ will be cleared (all files deleted) when an instance is
+ created. You can also use ``.clear()`` to clear the files.
+
+ ``ignore_paths`` is a set of specific filenames that should be
+ ignored when created in the environment. ``ignore_hidden``
+ means, if true (default) that filenames and directories
+ starting with ``'.'`` will be ignored.
+ """
+ self.base_path = base_path
+ self.template_path = template_path
+ if environ is None:
+ environ = os.environ.copy()
+ self.environ = environ
+ if script_path is None:
+ if sys.platform == 'win32':
+ script_path = environ.get('PATH', '').split(';')
+ else:
+ script_path = environ.get('PATH', '').split(':')
+ self.script_path = script_path
+ if cwd is None:
+ cwd = base_path
+ self.cwd = cwd
+ if start_clear:
+ self.clear()
+ elif not os.path.exists(base_path):
+ os.makedirs(base_path)
+ self.ignore_paths = ignore_paths or []
+ self.ignore_hidden = ignore_hidden
+
+ def run(self, script, *args, **kw):
+ """
+ Run the command, with the given arguments. The ``script``
+ argument can have space-separated arguments, or you can use
+ the positional arguments.
+
+ Keywords allowed are:
+
+ ``expect_error``: (default False)
+ Don't raise an exception in case of errors
+ ``expect_stderr``: (default ``expect_error``)
+ Don't raise an exception if anything is printed to stderr
+ ``stdin``: (default ``""``)
+ Input to the script
+ ``printresult``: (default True)
+ Print the result after running
+ ``cwd``: (default ``self.cwd``)
+ The working directory to run in
+
+ Returns a `ProcResponse
+ <class-paste.fixture.ProcResponse.html>`_ object.
+ """
+ __tracebackhide__ = True
+ expect_error = _popget(kw, 'expect_error', False)
+ expect_stderr = _popget(kw, 'expect_stderr', expect_error)
+ cwd = _popget(kw, 'cwd', self.cwd)
+ stdin = _popget(kw, 'stdin', None)
+ printresult = _popget(kw, 'printresult', True)
+ args = map(str, args)
+ assert not kw, (
+ "Arguments not expected: %s" % ', '.join(kw.keys()))
+ if ' ' in script:
+ assert not args, (
+ "You cannot give a multi-argument script (%r) "
+ "and arguments (%s)" % (script, args))
+ script, args = script.split(None, 1)
+ args = shlex.split(args)
+ script = self._find_exe(script)
+ all = [script] + args
+ files_before = self._find_files()
+ proc = subprocess.Popen(all, stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ cwd=cwd,
+ env=self.environ)
+ stdout, stderr = proc.communicate(stdin)
+ files_after = self._find_files()
+ result = ProcResult(
+ self, all, stdin, stdout, stderr,
+ returncode=proc.returncode,
+ files_before=files_before,
+ files_after=files_after)
+ if printresult:
+ print result
+ print '-'*40
+ if not expect_error:
+ result.assert_no_error()
+ if not expect_stderr:
+ result.assert_no_stderr()
+ return result
+
+ def _find_exe(self, script_name):
+ if self.script_path is None:
+ script_name = os.path.join(self.cwd, script_name)
+ if not os.path.exists(script_name):
+ raise OSError(
+ "Script %s does not exist" % script_name)
+ return script_name
+ for path in self.script_path:
+ fn = os.path.join(path, script_name)
+ if os.path.exists(fn):
+ return fn
+ raise OSError(
+ "Script %s could not be found in %s"
+ % (script_name, ':'.join(self.script_path)))
+
+ def _find_files(self):
+ result = {}
+ for fn in os.listdir(self.base_path):
+ if self._ignore_file(fn):
+ continue
+ self._find_traverse(fn, result)
+ return result
+
+ def _ignore_file(self, fn):
+ if fn in self.ignore_paths:
+ return True
+ if self.ignore_hidden and os.path.basename(fn).startswith('.'):
+ return True
+ return False
+
+ def _find_traverse(self, path, result):
+ full = os.path.join(self.base_path, path)
+ if os.path.isdir(full):
+ result[path] = FoundDir(self.base_path, path)
+ for fn in os.listdir(full):
+ fn = os.path.join(path, fn)
+ if self._ignore_file(fn):
+ continue
+ self._find_traverse(fn, result)
+ else:
+ result[path] = FoundFile(self.base_path, path)
+
+ def clear(self):
+ """
+ Delete all the files in the base directory.
+ """
+ if os.path.exists(self.base_path):
+ shutil.rmtree(self.base_path)
+ os.mkdir(self.base_path)
+
+ def writefile(self, path, content=None,
+ frompath=None):
+ """
+ Write a file to the given path. If ``content`` is given then
+ that text is written, otherwise the file in ``frompath`` is
+ used. ``frompath`` is relative to ``self.template_path``
+ """
+ full = os.path.join(self.base_path, path)
+ if not os.path.exists(os.path.dirname(full)):
+ os.makedirs(os.path.dirname(full))
+ f = open(full, 'wb')
+ if content is not None:
+ f.write(content)
+ if frompath is not None:
+ if self.template_path:
+ frompath = os.path.join(self.template_path, frompath)
+ f2 = open(frompath, 'rb')
+ f.write(f2.read())
+ f2.close()
+ f.close()
+ return FoundFile(self.base_path, path)
+
+class ProcResult(object):
+
+ """
+ Represents the results of running a command in
+ `TestFileEnvironment
+ <class-paste.fixture.TestFileEnvironment.html>`_.
+
+ Attributes to pay particular attention to:
+
+ ``stdout``, ``stderr``:
+ What is produced
+
+ ``files_created``, ``files_deleted``, ``files_updated``:
+ Dictionaries mapping filenames (relative to the ``base_dir``)
+ to `FoundFile <class-paste.fixture.FoundFile.html>`_ or
+ `FoundDir <class-paste.fixture.FoundDir.html>`_ objects.
+ """
+
+ def __init__(self, test_env, args, stdin, stdout, stderr,
+ returncode, files_before, files_after):
+ self.test_env = test_env
+ self.args = args
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ self.returncode = returncode
+ self.files_before = files_before
+ self.files_after = files_after
+ self.files_deleted = {}
+ self.files_updated = {}
+ self.files_created = files_after.copy()
+ for path, f in files_before.items():
+ if path not in files_after:
+ self.files_deleted[path] = f
+ continue
+ del self.files_created[path]
+ if f.mtime < files_after[path].mtime:
+ self.files_updated[path] = files_after[path]
+
+ def assert_no_error(self):
+ __tracebackhide__ = True
+ assert self.returncode == 0, (
+ "Script returned code: %s" % self.returncode)
+
+ def assert_no_stderr(self):
+ __tracebackhide__ = True
+ if self.stderr:
+ print 'Error output:'
+ print self.stderr
+ raise AssertionError("stderr output not expected")
+
+ def __str__(self):
+ s = ['Script result: %s' % ' '.join(self.args)]
+ if self.returncode:
+ s.append(' return code: %s' % self.returncode)
+ if self.stderr:
+ s.append('-- stderr: --------------------')
+ s.append(self.stderr)
+ if self.stdout:
+ s.append('-- stdout: --------------------')
+ s.append(self.stdout)
+ for name, files, show_size in [
+ ('created', self.files_created, True),
+ ('deleted', self.files_deleted, True),
+ ('updated', self.files_updated, True)]:
+ if files:
+ s.append('-- %s: -------------------' % name)
+ files = files.items()
+ files.sort()
+ last = ''
+ for path, f in files:
+ t = ' %s' % _space_prefix(last, path, indent=4,
+ include_sep=False)
+ last = path
+ if show_size and f.size != 'N/A':
+ t += ' (%s bytes)' % f.size
+ s.append(t)
+ return '\n'.join(s)
+
+class FoundFile(object):
+
+ """
+ Represents a single file found as the result of a command.
+
+ Has attributes:
+
+ ``path``:
+ The path of the file, relative to the ``base_path``
+
+ ``full``:
+ The full path
+
+ ``stat``:
+ The results of ``os.stat``. Also ``mtime`` and ``size``
+ contain the ``.st_mtime`` and ``st_size`` of the stat.
+
+ ``bytes``:
+ The contents of the file.
+
+ You may use the ``in`` operator with these objects (tested against
+ the contents of the file), and the ``.mustcontain()`` method.
+ """
+
+ file = True
+ dir = False
+
+ def __init__(self, base_path, path):
+ self.base_path = base_path
+ self.path = path
+ self.full = os.path.join(base_path, path)
+ self.stat = os.stat(self.full)
+ self.mtime = self.stat.st_mtime
+ self.size = self.stat.st_size
+ self._bytes = None
+
+ def bytes__get(self):
+ if self._bytes is None:
+ f = open(self.full, 'rb')
+ self._bytes = f.read()
+ f.close()
+ return self._bytes
+ bytes = property(bytes__get)
+
+ def __contains__(self, s):
+ return s in self.bytes
+
+ def mustcontain(self, s):
+ __tracebackhide__ = True
+ bytes = self.bytes
+ if s not in bytes:
+ print 'Could not find %r in:' % s
+ print bytes
+ assert s in bytes
+
+ def __repr__(self):
+ return '<%s %s:%s>' % (
+ self.__class__.__name__,
+ self.base_path, self.path)
+
+class FoundDir(object):
+
+ """
+ Represents a directory created by a command.
+ """
+
+ file = False
+ dir = True
+
+ def __init__(self, base_path, path):
+ self.base_path = base_path
+ self.path = path
+ self.full = os.path.join(base_path, path)
+ self.size = 'N/A'
+ self.mtime = 'N/A'
+
+ def __repr__(self):
+ return '<%s %s:%s>' % (
+ self.__class__.__name__,
+ self.base_path, self.path)
+
+def _popget(d, key, default=None):
+ """
+ Pop the key if found (else return default)
+ """
+ if key in d:
+ return d.pop(key)
+ return default
+
+def _space_prefix(pref, full, sep=None, indent=None, include_sep=True):
+ """
+ Anything shared by pref and full will be replaced with spaces
+ in full, and full returned.
+ """
+ if sep is None:
+ sep = os.path.sep
+ pref = pref.split(sep)
+ full = full.split(sep)
+ padding = []
+ while pref and full and pref[0] == full[0]:
+ if indent is None:
+ padding.append(' ' * (len(full[0]) + len(sep)))
+ else:
+ padding.append(' ' * indent)
+ full.pop(0)
+ pref.pop(0)
+ if padding:
+ if include_sep:
+ return ''.join(padding) + sep + sep.join(full)
+ else:
+ return ''.join(padding) + sep.join(full)
+ else:
+ return sep.join(full)
+
+def _make_pattern(pat):
+ if pat is None:
+ return None
+ if isinstance(pat, (str, unicode)):
+ pat = re.compile(pat)
+ if hasattr(pat, 'search'):
+ return pat.search
+ if callable(pat):
+ return pat
+ assert 0, (
+ "Cannot make callable pattern object out of %r" % pat)
+
+def setup_module(module=None):
+ """
+ This is used by py.test if it is in the module, so you can
+ import this directly.
+
+ Use like::
+
+ from paste.fixture import setup_module
+ """
+ # Deprecated June 2008
+ import warnings
+ warnings.warn(
+ 'setup_module is deprecated',
+ DeprecationWarning, 2)
+ if module is None:
+ # The module we were called from must be the module...
+ module = sys._getframe().f_back.f_globals['__name__']
+ if isinstance(module, (str, unicode)):
+ module = sys.modules[module]
+ if hasattr(module, 'reset_state'):
+ module.reset_state()
+
+def html_unquote(v):
+ """
+ Unquote (some) entities in HTML. (incomplete)
+ """
+ for ent, repl in [(' ', ' '), ('>', '>'),
+ ('<', '<'), ('"', '"'),
+ ('&', '&')]:
+ v = v.replace(ent, repl)
+ return v
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/flup_session.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/flup_session.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/flup_session.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,108 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Creates a session object.
+
+In your application, use::
+
+ environ['paste.flup_session_service'].session
+
+This will return a dictionary. The contents of this dictionary will
+be saved to disk when the request is completed. The session will be
+created when you first fetch the session dictionary, and a cookie will
+be sent in that case. There's current no way to use sessions without
+cookies, and there's no way to delete a session except to clear its
+data.
+"""
+
+from paste import httpexceptions
+from paste import wsgilib
+import flup.middleware.session
+flup_session = flup.middleware.session
+
+# This is a dictionary of existing stores, keyed by a tuple of
+# store type and parameters
+store_cache = {}
+
+class NoDefault(object):
+ pass
+
+class SessionMiddleware(object):
+
+ session_classes = {
+ 'memory': (flup_session.MemorySessionStore,
+ [('session_timeout', 'timeout', int, 60)]),
+ 'disk': (flup_session.DiskSessionStore,
+ [('session_timeout', 'timeout', int, 60),
+ ('session_dir', 'storeDir', str, '/tmp/sessions')]),
+ 'shelve': (flup_session.ShelveSessionStore,
+ [('session_timeout', 'timeout', int, 60),
+ ('session_file', 'storeFile', str,
+ '/tmp/session.shelve')]),
+ }
+
+
+ def __init__(self, app,
+ global_conf=None,
+ session_type=NoDefault,
+ cookie_name=NoDefault,
+ **store_config
+ ):
+ self.application = app
+ if session_type is NoDefault:
+ session_type = global_conf.get('session_type', 'disk')
+ self.session_type = session_type
+ try:
+ self.store_class, self.store_args = self.session_classes[self.session_type]
+ except KeyError:
+ raise KeyError(
+ "The session_type %s is unknown (I know about %s)"
+ % (self.session_type,
+ ', '.join(self.session_classes.keys())))
+ kw = {}
+ for config_name, kw_name, coercer, default in self.store_args:
+ value = coercer(store_config.get(config_name, default))
+ kw[kw_name] = value
+ self.store = self.store_class(**kw)
+ if cookie_name is NoDefault:
+ cookie_name = global_conf.get('session_cookie', '_SID_')
+ self.cookie_name = cookie_name
+
+ def __call__(self, environ, start_response):
+ service = flup_session.SessionService(
+ self.store, environ, cookieName=self.cookie_name,
+ fieldName=self.cookie_name)
+ environ['paste.flup_session_service'] = service
+
+ def cookie_start_response(status, headers, exc_info=None):
+ service.addCookie(headers)
+ return start_response(status, headers, exc_info)
+
+ try:
+ app_iter = self.application(environ, cookie_start_response)
+ except httpexceptions.HTTPException, e:
+ headers = (e.headers or {}).items()
+ service.addCookie(headers)
+ e.headers = dict(headers)
+ service.close()
+ raise
+ except:
+ service.close()
+ raise
+
+ return wsgilib.add_close(app_iter, service.close)
+
+def make_session_middleware(app, global_conf,
+ session_type=NoDefault,
+ cookie_name=NoDefault,
+ **store_config):
+ """
+ Wraps the application in a session-managing middleware.
+ The session service can then be found in
+ ``environ['paste.flup_session_service']``
+ """
+ return SessionMiddleware(
+ app, global_conf=global_conf,
+ session_type=session_type, cookie_name=cookie_name,
+ **store_config)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/gzipper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/gzipper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/gzipper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,111 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+WSGI middleware
+
+Gzip-encodes the response.
+"""
+
+import gzip
+from paste.response import header_value, remove_header
+from paste.httpheaders import CONTENT_LENGTH
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+class GzipOutput(object):
+ pass
+
+class middleware(object):
+
+ def __init__(self, application, compress_level=6):
+ self.application = application
+ self.compress_level = int(compress_level)
+
+ def __call__(self, environ, start_response):
+ if 'gzip' not in environ.get('HTTP_ACCEPT_ENCODING', ''):
+ # nothing for us to do, so this middleware will
+ # be a no-op:
+ return self.application(environ, start_response)
+ response = GzipResponse(start_response, self.compress_level)
+ app_iter = self.application(environ,
+ response.gzip_start_response)
+ if app_iter is not None:
+ response.finish_response(app_iter)
+
+ return response.write()
+
+class GzipResponse(object):
+
+ def __init__(self, start_response, compress_level):
+ self.start_response = start_response
+ self.compress_level = compress_level
+ self.buffer = StringIO()
+ self.compressible = False
+ self.content_length = None
+
+ def gzip_start_response(self, status, headers, exc_info=None):
+ self.headers = headers
+ ct = header_value(headers,'content-type')
+ ce = header_value(headers,'content-encoding')
+ self.compressible = False
+ if ct and (ct.startswith('text/') or ct.startswith('application/')) \
+ and 'zip' not in ct:
+ self.compressible = True
+ if ce:
+ self.compressible = False
+ if self.compressible:
+ headers.append(('content-encoding', 'gzip'))
+ remove_header(headers, 'content-length')
+ self.headers = headers
+ self.status = status
+ return self.buffer.write
+
+ def write(self):
+ out = self.buffer
+ out.seek(0)
+ s = out.getvalue()
+ out.close()
+ return [s]
+
+ def finish_response(self, app_iter):
+ if self.compressible:
+ output = gzip.GzipFile(mode='wb', compresslevel=self.compress_level,
+ fileobj=self.buffer)
+ else:
+ output = self.buffer
+ try:
+ for s in app_iter:
+ output.write(s)
+ if self.compressible:
+ output.close()
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ content_length = self.buffer.tell()
+ CONTENT_LENGTH.update(self.headers, content_length)
+ self.start_response(self.status, self.headers)
+
+def filter_factory(application, **conf):
+ import warnings
+ warnings.warn(
+ 'This function is deprecated; use make_gzip_middleware instead',
+ DeprecationWarning, 2)
+ def filter(application):
+ return middleware(application)
+ return filter
+
+def make_gzip_middleware(app, global_conf, compress_level=6):
+ """
+ Wrap the middleware, so that it applies gzipping to a response
+ when it is supported by the browser and the content is of
+ type ``text/*`` or ``application/*``
+ """
+ compress_level = int(compress_level)
+ return middleware(app, compress_level=compress_level)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpexceptions.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpexceptions.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpexceptions.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,660 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Ian Bicking, Clark C. Evans and contributors
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# Some of this code was funded by http://prometheusresearch.com
+"""
+HTTP Exception Middleware
+
+This module processes Python exceptions that relate to HTTP exceptions
+by defining a set of exceptions, all subclasses of HTTPException, and a
+request handler (`middleware`) that catches these exceptions and turns
+them into proper responses.
+
+This module defines exceptions according to RFC 2068 [1]_ : codes with
+100-300 are not really errors; 400's are client errors, and 500's are
+server errors. According to the WSGI specification [2]_ , the application
+can call ``start_response`` more then once only under two conditions:
+(a) the response has not yet been sent, or (b) if the second and
+subsequent invocations of ``start_response`` have a valid ``exc_info``
+argument obtained from ``sys.exc_info()``. The WSGI specification then
+requires the server or gateway to handle the case where content has been
+sent and then an exception was encountered.
+
+Exceptions in the 5xx range and those raised after ``start_response``
+has been called are treated as serious errors and the ``exc_info`` is
+filled-in with information needed for a lower level module to generate a
+stack trace and log information.
+
+Exception
+ HTTPException
+ HTTPRedirection
+ * 300 - HTTPMultipleChoices
+ * 301 - HTTPMovedPermanently
+ * 302 - HTTPFound
+ * 303 - HTTPSeeOther
+ * 304 - HTTPNotModified
+ * 305 - HTTPUseProxy
+ * 306 - Unused (not implemented, obviously)
+ * 307 - HTTPTemporaryRedirect
+ HTTPError
+ HTTPClientError
+ * 400 - HTTPBadRequest
+ * 401 - HTTPUnauthorized
+ * 402 - HTTPPaymentRequired
+ * 403 - HTTPForbidden
+ * 404 - HTTPNotFound
+ * 405 - HTTPMethodNotAllowed
+ * 406 - HTTPNotAcceptable
+ * 407 - HTTPProxyAuthenticationRequired
+ * 408 - HTTPRequestTimeout
+ * 409 - HTTPConfict
+ * 410 - HTTPGone
+ * 411 - HTTPLengthRequired
+ * 412 - HTTPPreconditionFailed
+ * 413 - HTTPRequestEntityTooLarge
+ * 414 - HTTPRequestURITooLong
+ * 415 - HTTPUnsupportedMediaType
+ * 416 - HTTPRequestRangeNotSatisfiable
+ * 417 - HTTPExpectationFailed
+ HTTPServerError
+ * 500 - HTTPInternalServerError
+ * 501 - HTTPNotImplemented
+ * 502 - HTTPBadGateway
+ * 503 - HTTPServiceUnavailable
+ * 504 - HTTPGatewayTimeout
+ * 505 - HTTPVersionNotSupported
+
+References:
+
+.. [1] http://www.python.org/peps/pep-0333.html#error-handling
+.. [2] http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5
+
+"""
+
+import types
+from paste.wsgilib import catch_errors_app
+from paste.response import has_header, header_value, replace_header
+from paste.request import resolve_relative_url
+from paste.util.quoting import strip_html, html_quote, no_quote, comment_quote
+
+SERVER_NAME = 'WSGI Server'
+TEMPLATE = """\
+<html>\r
+ <head><title>%(title)s</title></head>\r
+ <body>\r
+ <h1>%(title)s</h1>\r
+ <p>%(body)s</p>\r
+ <hr noshade>\r
+ <div align="right">%(server)s</div>\r
+ </body>\r
+</html>\r
+"""
+
+class HTTPException(Exception):
+ """
+ the HTTP exception base class
+
+ This encapsulates an HTTP response that interrupts normal application
+ flow; but one which is not necessarly an error condition. For
+ example, codes in the 300's are exceptions in that they interrupt
+ normal processing; however, they are not considered errors.
+
+ This class is complicated by 4 factors:
+
+ 1. The content given to the exception may either be plain-text or
+ as html-text.
+
+ 2. The template may want to have string-substitutions taken from
+ the current ``environ`` or values from incoming headers. This
+ is especially troublesome due to case sensitivity.
+
+ 3. The final output may either be text/plain or text/html
+ mime-type as requested by the client application.
+
+ 4. Each exception has a default explanation, but those who
+ raise exceptions may want to provide additional detail.
+
+ Attributes:
+
+ ``code``
+ the HTTP status code for the exception
+
+ ``title``
+ remainder of the status line (stuff after the code)
+
+ ``explanation``
+ a plain-text explanation of the error message that is
+ not subject to environment or header substitutions;
+ it is accessible in the template via %(explanation)s
+
+ ``detail``
+ a plain-text message customization that is not subject
+ to environment or header substitutions; accessible in
+ the template via %(detail)s
+
+ ``template``
+ a content fragment (in HTML) used for environment and
+ header substitution; the default template includes both
+ the explanation and further detail provided in the
+ message
+
+ ``required_headers``
+ a sequence of headers which are required for proper
+ construction of the exception
+
+ Parameters:
+
+ ``detail``
+ a plain-text override of the default ``detail``
+
+ ``headers``
+ a list of (k,v) header pairs
+
+ ``comment``
+ a plain-text additional information which is
+ usually stripped/hidden for end-users
+
+ To override the template (which is HTML content) or the plain-text
+ explanation, one must subclass the given exception; or customize it
+ after it has been created. This particular breakdown of a message
+ into explanation, detail and template allows both the creation of
+ plain-text and html messages for various clients as well as
+ error-free substitution of environment variables and headers.
+ """
+
+ code = None
+ title = None
+ explanation = ''
+ detail = ''
+ comment = ''
+ template = "%(explanation)s\r\n<br/>%(detail)s\r\n<!-- %(comment)s -->"
+ required_headers = ()
+
+ def __init__(self, detail=None, headers=None, comment=None):
+ assert self.code, "Do not directly instantiate abstract exceptions."
+ assert isinstance(headers, (type(None), list)), (
+ "headers must be None or a list: %r"
+ % headers)
+ assert isinstance(detail, (type(None), basestring)), (
+ "detail must be None or a string: %r" % detail)
+ assert isinstance(comment, (type(None), basestring)), (
+ "comment must be None or a string: %r" % comment)
+ self.headers = headers or tuple()
+ for req in self.required_headers:
+ assert headers and has_header(headers, req), (
+ "Exception %s must be passed the header %r "
+ "(got headers: %r)"
+ % (self.__class__.__name__, req, headers))
+ if detail is not None:
+ self.detail = detail
+ if comment is not None:
+ self.comment = comment
+ Exception.__init__(self,"%s %s\n%s\n%s\n" % (
+ self.code, self.title, self.explanation, self.detail))
+
+ def make_body(self, environ, template, escfunc, comment_escfunc=None):
+ comment_escfunc = comment_escfunc or escfunc
+ args = {'explanation': escfunc(self.explanation),
+ 'detail': escfunc(self.detail),
+ 'comment': comment_escfunc(self.comment)}
+ if HTTPException.template != self.template:
+ for (k, v) in environ.items():
+ args[k] = escfunc(v)
+ if self.headers:
+ for (k, v) in self.headers:
+ args[k.lower()] = escfunc(v)
+ for key, value in args.items():
+ if isinstance(value, unicode):
+ args[key] = value.encode('utf8', 'xmlcharrefreplace')
+ return template % args
+
+ def plain(self, environ):
+ """ text/plain representation of the exception """
+ body = self.make_body(environ, strip_html(self.template), no_quote, comment_quote)
+ return ('%s %s\r\n%s\r\n' % (self.code, self.title, body))
+
+ def html(self, environ):
+ """ text/html representation of the exception """
+ body = self.make_body(environ, self.template, html_quote, comment_quote)
+ return TEMPLATE % {
+ 'title': self.title,
+ 'code': self.code,
+ 'server': SERVER_NAME,
+ 'body': body }
+
+ def prepare_content(self, environ):
+ if self.headers:
+ headers = list(self.headers)
+ else:
+ headers = []
+ if 'html' in environ.get('HTTP_ACCEPT','') or \
+ '*/*' in environ.get('HTTP_ACCEPT',''):
+ replace_header(headers, 'content-type', 'text/html')
+ content = self.html(environ)
+ else:
+ replace_header(headers, 'content-type', 'text/plain')
+ content = self.plain(environ)
+ if isinstance(content, unicode):
+ content = content.encode('utf8')
+ cur_content_type = (
+ header_value(headers, 'content-type')
+ or 'text/html')
+ replace_header(
+ headers, 'content-type',
+ cur_content_type + '; charset=utf8')
+ return headers, content
+
+ def response(self, environ):
+ from paste.wsgiwrappers import WSGIResponse
+ headers, content = self.prepare_content(environ)
+ resp = WSGIResponse(code=self.code, content=content)
+ resp.headers = resp.headers.fromlist(headers)
+ return resp
+
+ def wsgi_application(self, environ, start_response, exc_info=None):
+ """
+ This exception as a WSGI application
+ """
+ headers, content = self.prepare_content(environ)
+ start_response('%s %s' % (self.code, self.title),
+ headers,
+ exc_info)
+ return [content]
+
+ __call__ = wsgi_application
+
+ def __repr__(self):
+ return '<%s %s; code=%s>' % (self.__class__.__name__,
+ self.title, self.code)
+
+class HTTPError(HTTPException):
+ """
+ base class for status codes in the 400's and 500's
+
+ This is an exception which indicates that an error has occurred,
+ and that any work in progress should not be committed. These are
+ typically results in the 400's and 500's.
+ """
+
+#
+# 3xx Redirection
+#
+# This class of status code indicates that further action needs to be
+# taken by the user agent in order to fulfill the request. The action
+# required MAY be carried out by the user agent without interaction with
+# the user if and only if the method used in the second request is GET or
+# HEAD. A client SHOULD detect infinite redirection loops, since such
+# loops generate network traffic for each redirection.
+#
+
+class HTTPRedirection(HTTPException):
+ """
+ base class for 300's status code (redirections)
+
+ This is an abstract base class for 3xx redirection. It indicates
+ that further action needs to be taken by the user agent in order
+ to fulfill the request. It does not necessarly signal an error
+ condition.
+ """
+
+class _HTTPMove(HTTPRedirection):
+ """
+ redirections which require a Location field
+
+ Since a 'Location' header is a required attribute of 301, 302, 303,
+ 305 and 307 (but not 304), this base class provides the mechanics to
+ make this easy. While this has the same parameters as HTTPException,
+ if a location is not provided in the headers; it is assumed that the
+ detail _is_ the location (this for backward compatibility, otherwise
+ we'd add a new attribute).
+ """
+ required_headers = ('location',)
+ explanation = 'The resource has been moved to'
+ template = (
+ '%(explanation)s <a href="%(location)s">%(location)s</a>;\r\n'
+ 'you should be redirected automatically.\r\n'
+ '%(detail)s\r\n<!-- %(comment)s -->')
+
+ def __init__(self, detail=None, headers=None, comment=None):
+ assert isinstance(headers, (type(None), list))
+ headers = headers or []
+ location = header_value(headers,'location')
+ if not location:
+ location = detail
+ detail = ''
+ headers.append(('location', location))
+ assert location, ("HTTPRedirection specified neither a "
+ "location in the headers nor did it "
+ "provide a detail argument.")
+ HTTPRedirection.__init__(self, location, headers, comment)
+ if detail is not None:
+ self.detail = detail
+
+ def relative_redirect(cls, dest_uri, environ, detail=None, headers=None, comment=None):
+ """
+ Create a redirect object with the dest_uri, which may be relative,
+ considering it relative to the uri implied by the given environ.
+ """
+ location = resolve_relative_url(dest_uri, environ)
+ headers = headers or []
+ headers.append(('Location', location))
+ return cls(detail=detail, headers=headers, comment=comment)
+
+ relative_redirect = classmethod(relative_redirect)
+
+ def location(self):
+ for name, value in self.headers:
+ if name.lower() == 'location':
+ return value
+ else:
+ raise KeyError("No location set for %s" % self)
+
+class HTTPMultipleChoices(_HTTPMove):
+ code = 300
+ title = 'Multiple Choices'
+
+class HTTPMovedPermanently(_HTTPMove):
+ code = 301
+ title = 'Moved Permanently'
+
+class HTTPFound(_HTTPMove):
+ code = 302
+ title = 'Found'
+ explanation = 'The resource was found at'
+
+# This one is safe after a POST (the redirected location will be
+# retrieved with GET):
+class HTTPSeeOther(_HTTPMove):
+ code = 303
+ title = 'See Other'
+
+class HTTPNotModified(HTTPRedirection):
+ # @@: but not always (HTTP section 14.18.1)...?
+ # @@: Removed 'date' requirement, as its not required for an ETag
+ # @@: FIXME: This should require either an ETag or a date header
+ code = 304
+ title = 'Not Modified'
+ message = ''
+ # @@: should include date header, optionally other headers
+ # @@: should not return a content body
+ def plain(self, environ):
+ return ''
+ def html(self, environ):
+ """ text/html representation of the exception """
+ return ''
+
+class HTTPUseProxy(_HTTPMove):
+ # @@: OK, not a move, but looks a little like one
+ code = 305
+ title = 'Use Proxy'
+ explanation = (
+ 'The resource must be accessed through a proxy '
+ 'located at')
+
+class HTTPTemporaryRedirect(_HTTPMove):
+ code = 307
+ title = 'Temporary Redirect'
+
+#
+# 4xx Client Error
+#
+# The 4xx class of status code is intended for cases in which the client
+# seems to have erred. Except when responding to a HEAD request, the
+# server SHOULD include an entity containing an explanation of the error
+# situation, and whether it is a temporary or permanent condition. These
+# status codes are applicable to any request method. User agents SHOULD
+# display any included entity to the user.
+#
+
+class HTTPClientError(HTTPError):
+ """
+ base class for the 400's, where the client is in-error
+
+ This is an error condition in which the client is presumed to be
+ in-error. This is an expected problem, and thus is not considered
+ a bug. A server-side traceback is not warranted. Unless specialized,
+ this is a '400 Bad Request'
+ """
+ code = 400
+ title = 'Bad Request'
+ explanation = ('The server could not comply with the request since\r\n'
+ 'it is either malformed or otherwise incorrect.\r\n')
+
+class HTTPBadRequest(HTTPClientError):
+ pass
+
+class HTTPUnauthorized(HTTPClientError):
+ code = 401
+ title = 'Unauthorized'
+ explanation = (
+ 'This server could not verify that you are authorized to\r\n'
+ 'access the document you requested. Either you supplied the\r\n'
+ 'wrong credentials (e.g., bad password), or your browser\r\n'
+ 'does not understand how to supply the credentials required.\r\n')
+
+class HTTPPaymentRequired(HTTPClientError):
+ code = 402
+ title = 'Payment Required'
+ explanation = ('Access was denied for financial reasons.')
+
+class HTTPForbidden(HTTPClientError):
+ code = 403
+ title = 'Forbidden'
+ explanation = ('Access was denied to this resource.')
+
+class HTTPNotFound(HTTPClientError):
+ code = 404
+ title = 'Not Found'
+ explanation = ('The resource could not be found.')
+
+class HTTPMethodNotAllowed(HTTPClientError):
+ required_headers = ('allow',)
+ code = 405
+ title = 'Method Not Allowed'
+ # override template since we need an environment variable
+ template = ('The method %(REQUEST_METHOD)s is not allowed for '
+ 'this resource.\r\n%(detail)s')
+
+class HTTPNotAcceptable(HTTPClientError):
+ code = 406
+ title = 'Not Acceptable'
+ # override template since we need an environment variable
+ template = ('The resource could not be generated that was '
+ 'acceptable to your browser (content\r\nof type '
+ '%(HTTP_ACCEPT)s).\r\n%(detail)s')
+
+class HTTPProxyAuthenticationRequired(HTTPClientError):
+ code = 407
+ title = 'Proxy Authentication Required'
+ explanation = ('Authentication /w a local proxy is needed.')
+
+class HTTPRequestTimeout(HTTPClientError):
+ code = 408
+ title = 'Request Timeout'
+ explanation = ('The server has waited too long for the request to '
+ 'be sent by the client.')
+
+class HTTPConflict(HTTPClientError):
+ code = 409
+ title = 'Conflict'
+ explanation = ('There was a conflict when trying to complete '
+ 'your request.')
+
+class HTTPGone(HTTPClientError):
+ code = 410
+ title = 'Gone'
+ explanation = ('This resource is no longer available. No forwarding '
+ 'address is given.')
+
+class HTTPLengthRequired(HTTPClientError):
+ code = 411
+ title = 'Length Required'
+ explanation = ('Content-Length header required.')
+
+class HTTPPreconditionFailed(HTTPClientError):
+ code = 412
+ title = 'Precondition Failed'
+ explanation = ('Request precondition failed.')
+
+class HTTPRequestEntityTooLarge(HTTPClientError):
+ code = 413
+ title = 'Request Entity Too Large'
+ explanation = ('The body of your request was too large for this server.')
+
+class HTTPRequestURITooLong(HTTPClientError):
+ code = 414
+ title = 'Request-URI Too Long'
+ explanation = ('The request URI was too long for this server.')
+
+class HTTPUnsupportedMediaType(HTTPClientError):
+ code = 415
+ title = 'Unsupported Media Type'
+ # override template since we need an environment variable
+ template = ('The request media type %(CONTENT_TYPE)s is not '
+ 'supported by this server.\r\n%(detail)s')
+
+class HTTPRequestRangeNotSatisfiable(HTTPClientError):
+ code = 416
+ title = 'Request Range Not Satisfiable'
+ explanation = ('The Range requested is not available.')
+
+class HTTPExpectationFailed(HTTPClientError):
+ code = 417
+ title = 'Expectation Failed'
+ explanation = ('Expectation failed.')
+
+#
+# 5xx Server Error
+#
+# Response status codes beginning with the digit "5" indicate cases in
+# which the server is aware that it has erred or is incapable of
+# performing the request. Except when responding to a HEAD request, the
+# server SHOULD include an entity containing an explanation of the error
+# situation, and whether it is a temporary or permanent condition. User
+# agents SHOULD display any included entity to the user. These response
+# codes are applicable to any request method.
+#
+
+class HTTPServerError(HTTPError):
+ """
+ base class for the 500's, where the server is in-error
+
+ This is an error condition in which the server is presumed to be
+ in-error. This is usually unexpected, and thus requires a traceback;
+ ideally, opening a support ticket for the customer. Unless specialized,
+ this is a '500 Internal Server Error'
+ """
+ code = 500
+ title = 'Internal Server Error'
+ explanation = (
+ 'The server has either erred or is incapable of performing\r\n'
+ 'the requested operation.\r\n')
+
+class HTTPInternalServerError(HTTPServerError):
+ pass
+
+class HTTPNotImplemented(HTTPServerError):
+ code = 501
+ title = 'Not Implemented'
+ # override template since we need an environment variable
+ template = ('The request method %(REQUEST_METHOD)s is not implemented '
+ 'for this server.\r\n%(detail)s')
+
+class HTTPBadGateway(HTTPServerError):
+ code = 502
+ title = 'Bad Gateway'
+ explanation = ('Bad gateway.')
+
+class HTTPServiceUnavailable(HTTPServerError):
+ code = 503
+ title = 'Service Unavailable'
+ explanation = ('The server is currently unavailable. '
+ 'Please try again at a later time.')
+
+class HTTPGatewayTimeout(HTTPServerError):
+ code = 504
+ title = 'Gateway Timeout'
+ explanation = ('The gateway has timed out.')
+
+class HTTPVersionNotSupported(HTTPServerError):
+ code = 505
+ title = 'HTTP Version Not Supported'
+ explanation = ('The HTTP version is not supported.')
+
+# abstract HTTP related exceptions
+__all__ = ['HTTPException', 'HTTPRedirection', 'HTTPError' ]
+
+_exceptions = {}
+for name, value in globals().items():
+ if (isinstance(value, (type, types.ClassType)) and
+ issubclass(value, HTTPException) and
+ value.code):
+ _exceptions[value.code] = value
+ __all__.append(name)
+
+def get_exception(code):
+ return _exceptions[code]
+
+############################################################
+## Middleware implementation:
+############################################################
+
+class HTTPExceptionHandler(object):
+ """
+ catches exceptions and turns them into proper HTTP responses
+
+ This middleware catches any exceptions (which are subclasses of
+ ``HTTPException``) and turns them into proper HTTP responses.
+ Note if the headers have already been sent, the stack trace is
+ always maintained as this indicates a programming error.
+
+ Note that you must raise the exception before returning the
+ app_iter, and you cannot use this with generator apps that don't
+ raise an exception until after their app_iter is iterated over.
+ """
+
+ def __init__(self, application, warning_level=None):
+ assert not warning_level or ( warning_level > 99 and
+ warning_level < 600)
+ if warning_level is not None:
+ import warnings
+ warnings.warn('The warning_level parameter is not used or supported',
+ DeprecationWarning, 2)
+ self.warning_level = warning_level or 500
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ environ['paste.httpexceptions'] = self
+ environ.setdefault('paste.expected_exceptions',
+ []).append(HTTPException)
+ try:
+ return self.application(environ, start_response)
+ except HTTPException, exc:
+ return exc(environ, start_response)
+
+def middleware(*args, **kw):
+ import warnings
+ # deprecated 13 dec 2005
+ warnings.warn('httpexceptions.middleware is deprecated; use '
+ 'make_middleware or HTTPExceptionHandler instead',
+ DeprecationWarning, 2)
+ return make_middleware(*args, **kw)
+
+def make_middleware(app, global_conf=None, warning_level=None):
+ """
+ ``httpexceptions`` middleware; this catches any
+ ``paste.httpexceptions.HTTPException`` exceptions (exceptions like
+ ``HTTPNotFound``, ``HTTPMovedPermanently``, etc) and turns them
+ into proper HTTP responses.
+
+ ``warning_level`` can be an integer corresponding to an HTTP code.
+ Any code over that value will be passed 'up' the chain, potentially
+ reported on by another piece of middleware.
+ """
+ if warning_level:
+ warning_level = int(warning_level)
+ return HTTPExceptionHandler(app, warning_level=warning_level)
+
+__all__.extend(['HTTPExceptionHandler', 'get_exception'])
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpheaders.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpheaders.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpheaders.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1097 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Ian Bicking, Clark C. Evans and contributors
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# Some of this code was funded by: http://prometheusresearch.com
+"""
+HTTP Message Header Fields (see RFC 4229)
+
+This contains general support for HTTP/1.1 message headers [1]_ in a
+manner that supports WSGI ``environ`` [2]_ and ``response_headers``
+[3]_. Specifically, this module defines a ``HTTPHeader`` class whose
+instances correspond to field-name items. The actual field-content for
+the message-header is stored in the appropriate WSGI collection (either
+the ``environ`` for requests, or ``response_headers`` for responses).
+
+Each ``HTTPHeader`` instance is a callable (defining ``__call__``)
+that takes one of the following:
+
+ - an ``environ`` dictionary, returning the corresponding header
+ value by according to the WSGI's ``HTTP_`` prefix mechanism, e.g.,
+ ``USER_AGENT(environ)`` returns ``environ.get('HTTP_USER_AGENT')``
+
+ - a ``response_headers`` list, giving a comma-delimited string for
+ each corresponding ``header_value`` tuple entries (see below).
+
+ - a sequence of string ``*args`` that are comma-delimited into
+ a single string value: ``CONTENT_TYPE("text/html","text/plain")``
+ returns ``"text/html, text/plain"``
+
+ - a set of ``**kwargs`` keyword arguments that are used to create
+ a header value, in a manner dependent upon the particular header in
+ question (to make value construction easier and error-free):
+ ``CONTENT_DISPOSITION(max_age=CONTENT_DISPOSITION.ONEWEEK)``
+ returns ``"public, max-age=60480"``
+
+Each ``HTTPHeader`` instance also provides several methods to act on
+a WSGI collection, for removing and setting header values.
+
+ ``delete(collection)``
+
+ This method removes all entries of the corresponding header from
+ the given collection (``environ`` or ``response_headers``), e.g.,
+ ``USER_AGENT.delete(environ)`` deletes the 'HTTP_USER_AGENT' entry
+ from the ``environ``.
+
+ ``update(collection, *args, **kwargs)``
+
+ This method does an in-place replacement of the given header entry,
+ for example: ``CONTENT_LENGTH(response_headers,len(body))``
+
+ The first argument is a valid ``environ`` dictionary or
+ ``response_headers`` list; remaining arguments are passed on to
+ ``__call__(*args, **kwargs)`` for value construction.
+
+ ``apply(collection, **kwargs)``
+
+ This method is similar to update, only that it may affect other
+ headers. For example, according to recommendations in RFC 2616,
+ certain Cache-Control configurations should also set the
+ ``Expires`` header for HTTP/1.0 clients. By default, ``apply()``
+ is simply ``update()`` but limited to keyword arguments.
+
+This particular approach to managing headers within a WSGI collection
+has several advantages:
+
+ 1. Typos in the header name are easily detected since they become a
+ ``NameError`` when executed. The approach of using header strings
+ directly can be problematic; for example, the following should
+ return ``None`` : ``environ.get("HTTP_ACCEPT_LANGUAGES")``
+
+ 2. For specific headers with validation, using ``__call__`` will
+ result in an automatic header value check. For example, the
+ _ContentDisposition header will reject a value having ``maxage``
+ or ``max_age`` (the appropriate parameter is ``max-age`` ).
+
+ 3. When appending/replacing headers, the field-name has the suggested
+ RFC capitalization (e.g. ``Content-Type`` or ``ETag``) for
+ user-agents that incorrectly use case-sensitive matches.
+
+ 4. Some headers (such as ``Content-Type``) are 0, that is,
+ only one entry of this type may occur in a given set of
+ ``response_headers``. This module knows about those cases and
+ enforces this cardinality constraint.
+
+ 5. The exact details of WSGI header management are abstracted so
+ the programmer need not worry about operational differences
+ between ``environ`` dictionary or ``response_headers`` list.
+
+ 6. Sorting of ``HTTPHeaders`` is done following the RFC suggestion
+ that general-headers come first, followed by request and response
+ headers, and finishing with entity-headers.
+
+ 7. Special care is given to exceptional cases such as Set-Cookie
+ which violates the RFC's recommendation about combining header
+ content into a single entry using comma separation.
+
+A particular difficulty with HTTP message headers is a categorization
+of sorts as described in section 4.2:
+
+ Multiple message-header fields with the same field-name MAY be
+ present in a message if and only if the entire field-value for
+ that header field is defined as a comma-separated list [i.e.,
+ #(values)]. It MUST be possible to combine the multiple header
+ fields into one "field-name: field-value" pair, without changing
+ the semantics of the message, by appending each subsequent
+ field-value to the first, each separated by a comma.
+
+This creates three fundamentally different kinds of headers:
+
+ - Those that do not have a #(values) production, and hence are
+ singular and may only occur once in a set of response fields;
+ this case is handled by the ``_SingleValueHeader`` subclass.
+
+ - Those which have the #(values) production and follow the
+ combining rule outlined above; our ``_MultiValueHeader`` case.
+
+ - Those which are multi-valued, but cannot be combined (such as the
+ ``Set-Cookie`` header due to its ``Expires`` parameter); or where
+ combining them into a single header entry would cause common
+ user-agents to fail (``WWW-Authenticate``, ``Warning``) since
+ they fail to handle dates even when properly quoted. This case
+ is handled by ``_MultiEntryHeader``.
+
+Since this project does not have time to provide rigorous support
+and validation for all headers, it does a basic construction of
+headers listed in RFC 2616 (plus a few others) so that they can
+be obtained by simply doing ``from paste.httpheaders import *``;
+the name of the header instance is the "common name" less any
+dashes to give CamelCase style names.
+
+.. [1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+.. [2] http://www.python.org/peps/pep-0333.html#environ-variables
+.. [3] http://www.python.org/peps/pep-0333.html#the-start-response-callable
+
+"""
+import mimetypes
+import urllib2
+import re
+from rfc822 import formatdate, parsedate_tz, mktime_tz
+from time import time as now
+from httpexceptions import HTTPBadRequest
+
+__all__ = ['get_header', 'list_headers', 'normalize_headers',
+ 'HTTPHeader', 'EnvironVariable' ]
+
+class EnvironVariable(str):
+ """
+ a CGI ``environ`` variable as described by WSGI
+
+ This is a helper object so that standard WSGI ``environ`` variables
+ can be extracted w/o syntax error possibility.
+ """
+ def __call__(self, environ):
+ return environ.get(self,'')
+ def __repr__(self):
+ return '<EnvironVariable %s>' % self
+ def update(self, environ, value):
+ environ[self] = value
+REMOTE_USER = EnvironVariable("REMOTE_USER")
+REMOTE_SESSION = EnvironVariable("REMOTE_SESSION")
+AUTH_TYPE = EnvironVariable("AUTH_TYPE")
+REQUEST_METHOD = EnvironVariable("REQUEST_METHOD")
+SCRIPT_NAME = EnvironVariable("SCRIPT_NAME")
+PATH_INFO = EnvironVariable("PATH_INFO")
+
+for _name, _obj in globals().items():
+ if isinstance(_obj, EnvironVariable):
+ __all__.append(_name)
+
+_headers = {}
+
+class HTTPHeader(object):
+ """
+ an HTTP header
+
+ HTTPHeader instances represent a particular ``field-name`` of an
+ HTTP message header. They do not hold a field-value, but instead
+ provide operations that work on is corresponding values. Storage
+ of the actual field values is done with WSGI ``environ`` or
+ ``response_headers`` as appropriate. Typically, a sub-classes that
+ represent a specific HTTP header, such as _ContentDisposition, are
+ 0. Once constructed the HTTPHeader instances themselves
+ are immutable and stateless.
+
+ For purposes of documentation a "container" refers to either a
+ WSGI ``environ`` dictionary, or a ``response_headers`` list.
+
+ Member variables (and correspondingly constructor arguments).
+
+ ``name``
+
+ the ``field-name`` of the header, in "common form"
+ as presented in RFC 2616; e.g. 'Content-Type'
+
+ ``category``
+
+ one of 'general', 'request', 'response', or 'entity'
+
+ ``version``
+
+ version of HTTP (informational) with which the header should
+ be recognized
+
+ ``sort_order``
+
+ sorting order to be applied before sorting on
+ field-name when ordering headers in a response
+
+ Special Methods:
+
+ ``__call__``
+
+ The primary method of the HTTPHeader instance is to make
+ it a callable, it takes either a collection, a string value,
+ or keyword arguments and attempts to find/construct a valid
+ field-value
+
+ ``__lt__``
+
+ This method is used so that HTTPHeader objects can be
+ sorted in a manner suggested by RFC 2616.
+
+ ``__str__``
+
+ The string-value for instances of this class is
+ the ``field-name``.
+
+ Primary Methods:
+
+ ``delete()``
+
+ remove the all occurrences (if any) of the given
+ header in the collection provided
+
+ ``update()``
+
+ replaces (if they exist) all field-value items
+ in the given collection with the value provided
+
+ ``tuples()``
+
+ returns a set of (field-name, field-value) tuples
+ 5 for extending ``response_headers``
+
+ Custom Methods (these may not be implemented):
+
+ ``apply()``
+
+ similar to ``update``, but with two differences; first,
+ only keyword arguments can be used, and second, specific
+ sub-classes may introduce side-effects
+
+ ``parse()``
+
+ converts a string value of the header into a more usable
+ form, such as time in seconds for a date header, etc.
+
+ The collected versions of initialized header instances are immediately
+ registered and accessible through the ``get_header`` function. Do not
+ inherit from this directly, use one of ``_SingleValueHeader``,
+ ``_MultiValueHeader``, or ``_MultiEntryHeader`` as appropriate.
+ """
+
+ #
+ # Things which can be customized
+ #
+ version = '1.1'
+ category = 'general'
+ reference = ''
+ extensions = {}
+
+ def compose(self, **kwargs):
+ """
+ build header value from keyword arguments
+
+ This method is used to build the corresponding header value when
+ keyword arguments (or no arguments) were provided. The result
+ should be a sequence of values. For example, the ``Expires``
+ header takes a keyword argument ``time`` (e.g. time.time()) from
+ which it returns a the corresponding date.
+ """
+ raise NotImplementedError()
+
+ def parse(self, *args, **kwargs):
+ """
+ convert raw header value into more usable form
+
+ This method invokes ``values()`` with the arguments provided,
+ parses the header results, and then returns a header-specific
+ data structure corresponding to the header. For example, the
+ ``Expires`` header returns seconds (as returned by time.time())
+ """
+ raise NotImplementedError()
+
+ def apply(self, collection, **kwargs):
+ """
+ update the collection /w header value (may have side effects)
+
+ This method is similar to ``update`` only that usage may result
+ in other headers being changed as recommended by the corresponding
+ specification. The return value is defined by the particular
+ sub-class. For example, the ``_CacheControl.apply()`` sets the
+ ``Expires`` header in addition to its normal behavior.
+ """
+ self.update(collection, **kwargs)
+
+ #
+ # Things which are standardized (mostly)
+ #
+ def __new__(cls, name, category=None, reference=None, version=None):
+ """
+ construct a new ``HTTPHeader`` instance
+
+ We use the ``__new__`` operator to ensure that only one
+ ``HTTPHeader`` instance exists for each field-name, and to
+ register the header so that it can be found/enumerated.
+ """
+ self = get_header(name, raiseError=False)
+ if self:
+ # Allow the registration to happen again, but assert
+ # that everything is identical.
+ assert self.name == name, \
+ "duplicate registration with different capitalization"
+ assert self.category == category, \
+ "duplicate registration with different category"
+ assert cls == self.__class__, \
+ "duplicate registration with different class"
+ return self
+
+ self = object.__new__(cls)
+ self.name = name
+ assert isinstance(self.name, str)
+ self.category = category or self.category
+ self.version = version or self.version
+ self.reference = reference or self.reference
+ _headers[self.name.lower()] = self
+ self.sort_order = {'general': 1, 'request': 2,
+ 'response': 3, 'entity': 4 }[self.category]
+ self._environ_name = getattr(self, '_environ_name',
+ 'HTTP_'+ self.name.upper().replace("-","_"))
+ self._headers_name = getattr(self, '_headers_name',
+ self.name.lower())
+ assert self.version in ('1.1', '1.0', '0.9')
+ return self
+
+ def __str__(self):
+ return self.name
+
+ def __lt__(self, other):
+ """
+ sort header instances as specified by RFC 2616
+
+ Re-define sorting so that general headers are first, followed
+ by request/response headers, and then entity headers. The
+ list.sort() methods use the less-than operator for this purpose.
+ """
+ if isinstance(other, HTTPHeader):
+ if self.sort_order != other.sort_order:
+ return self.sort_order < other.sort_order
+ return self.name < other.name
+ return False
+
+ def __repr__(self):
+ ref = self.reference and (' (%s)' % self.reference) or ''
+ return '<%s %s%s>' % (self.__class__.__name__, self.name, ref)
+
+ def values(self, *args, **kwargs):
+ """
+ find/construct field-value(s) for the given header
+
+ Resolution is done according to the following arguments:
+
+ - If only keyword arguments are given, then this is equivalent
+ to ``compose(**kwargs)``.
+
+ - If the first (and only) argument is a dict, it is assumed
+ to be a WSGI ``environ`` and the result of the corresponding
+ ``HTTP_`` entry is returned.
+
+ - If the first (and only) argument is a list, it is assumed
+ to be a WSGI ``response_headers`` and the field-value(s)
+ for this header are collected and returned.
+
+ - In all other cases, the arguments are collected, checked that
+ they are string values, possibly verified by the header's
+ logic, and returned.
+
+ At this time it is an error to provide keyword arguments if args
+ is present (this might change). It is an error to provide both
+ a WSGI object and also string arguments. If no arguments are
+ provided, then ``compose()`` is called to provide a default
+ value for the header; if there is not default it is an error.
+ """
+ if not args:
+ return self.compose(**kwargs)
+ if list == type(args[0]):
+ assert 1 == len(args)
+ result = []
+ name = self.name.lower()
+ for value in [value for header, value in args[0]
+ if header.lower() == name]:
+ result.append(value)
+ return result
+ if dict == type(args[0]):
+ assert 1 == len(args) and 'wsgi.version' in args[0]
+ value = args[0].get(self._environ_name)
+ if not value:
+ return ()
+ return (value,)
+ for item in args:
+ assert not type(item) in (dict, list)
+ return args
+
+ def __call__(self, *args, **kwargs):
+ """
+ converts ``values()`` into a string value
+
+ This method converts the results of ``values()`` into a string
+ value for common usage. By default, it is asserted that only
+ one value exists; if you need to access all values then either
+ call ``values()`` directly, or inherit ``_MultiValueHeader``
+ which overrides this method to return a comma separated list of
+ values as described by section 4.2 of RFC 2616.
+ """
+ values = self.values(*args, **kwargs)
+ assert isinstance(values, (tuple, list))
+ if not values:
+ return ''
+ assert len(values) == 1, "more than one value: %s" % repr(values)
+ return str(values[0]).strip()
+
+ def delete(self, collection):
+ """
+ removes all occurances of the header from the collection provided
+ """
+ if type(collection) == dict:
+ if self._environ_name in collection:
+ del collection[self._environ_name]
+ return self
+ assert list == type(collection)
+ i = 0
+ while i < len(collection):
+ if collection[i][0].lower() == self._headers_name:
+ del collection[i]
+ continue
+ i += 1
+
+ def update(self, collection, *args, **kwargs):
+ """
+ updates the collection with the provided header value
+
+ This method replaces (in-place when possible) all occurrences of
+ the given header with the provided value. If no value is
+ provided, this is the same as ``remove`` (note that this case
+ can only occur if the target is a collection w/o a corresponding
+ header value). The return value is the new header value (which
+ could be a list for ``_MultiEntryHeader`` instances).
+ """
+ value = self.__call__(*args, **kwargs)
+ if not value:
+ self.delete(collection)
+ return
+ if type(collection) == dict:
+ collection[self._environ_name] = value
+ return
+ assert list == type(collection)
+ i = 0
+ found = False
+ while i < len(collection):
+ if collection[i][0].lower() == self._headers_name:
+ if found:
+ del collection[i]
+ continue
+ collection[i] = (self.name, value)
+ found = True
+ i += 1
+ if not found:
+ collection.append((self.name, value))
+
+ def tuples(self, *args, **kwargs):
+ value = self.__call__(*args, **kwargs)
+ if not value:
+ return ()
+ return [(self.name, value)]
+
+class _SingleValueHeader(HTTPHeader):
+ """
+ a ``HTTPHeader`` with exactly a single value
+
+ This is the default behavior of ``HTTPHeader`` where returning a
+ the string-value of headers via ``__call__`` assumes that only
+ a single value exists.
+ """
+ pass
+
+class _MultiValueHeader(HTTPHeader):
+ """
+ a ``HTTPHeader`` with one or more values
+
+ The field-value for these header instances is is allowed to be more
+ than one value; whereby the ``__call__`` method returns a comma
+ separated list as described by section 4.2 of RFC 2616.
+ """
+
+ def __call__(self, *args, **kwargs):
+ results = self.values(*args, **kwargs)
+ if not results:
+ return ''
+ return ", ".join([str(v).strip() for v in results])
+
+ def parse(self, *args, **kwargs):
+ value = self.__call__(*args, **kwargs)
+ values = value.split(',')
+ return [
+ v.strip() for v in values
+ if v.strip()]
+
+class _MultiEntryHeader(HTTPHeader):
+ """
+ a multi-value ``HTTPHeader`` where items cannot be combined with a comma
+
+ This header is multi-valued, but the values should not be combined
+ with a comma since the header is not in compliance with RFC 2616
+ (Set-Cookie due to Expires parameter) or which common user-agents do
+ not behave well when the header values are combined.
+ """
+
+ def update(self, collection, *args, **kwargs):
+ assert list == type(collection), "``environ`` may not be updated"
+ self.delete(collection)
+ collection.extend(self.tuples(*args, **kwargs))
+
+ def tuples(self, *args, **kwargs):
+ values = self.values(*args, **kwargs)
+ if not values:
+ return ()
+ return [(self.name, value.strip()) for value in values]
+
+def get_header(name, raiseError=True):
+ """
+ find the given ``HTTPHeader`` instance
+
+ This function finds the corresponding ``HTTPHeader`` for the
+ ``name`` provided. So that python-style names can be used,
+ underscores are converted to dashes before the lookup.
+ """
+ retval = _headers.get(str(name).strip().lower().replace("_","-"))
+ if not retval and raiseError:
+ raise AssertionError("'%s' is an unknown header" % name)
+ return retval
+
+def list_headers(general=None, request=None, response=None, entity=None):
+ " list all headers for a given category "
+ if not (general or request or response or entity):
+ general = request = response = entity = True
+ search = []
+ for (bool, strval) in ((general, 'general'), (request, 'request'),
+ (response, 'response'), (entity, 'entity')):
+ if bool:
+ search.append(strval)
+ return [head for head in _headers.values() if head.category in search]
+
+def normalize_headers(response_headers, strict=True):
+ """
+ sort headers as suggested by RFC 2616
+
+ This alters the underlying response_headers to use the common
+ name for each header; as well as sorting them with general
+ headers first, followed by request/response headers, then
+ entity headers, and unknown headers last.
+ """
+ category = {}
+ for idx in range(len(response_headers)):
+ (key, val) = response_headers[idx]
+ head = get_header(key, strict)
+ if not head:
+ newhead = '-'.join([x.capitalize() for x in
+ key.replace("_","-").split("-")])
+ response_headers[idx] = (newhead, val)
+ category[newhead] = 4
+ continue
+ response_headers[idx] = (str(head), val)
+ category[str(head)] = head.sort_order
+ def compare(a, b):
+ ac = category[a[0]]
+ bc = category[b[0]]
+ if ac == bc:
+ return cmp(a[0], b[0])
+ return cmp(ac, bc)
+ response_headers.sort(compare)
+
+class _DateHeader(_SingleValueHeader):
+ """
+ handle date-based headers
+
+ This extends the ``_SingleValueHeader`` object with specific
+ treatment of time values:
+
+ - It overrides ``compose`` to provide a sole keyword argument
+ ``time`` which is an offset in seconds from the current time.
+
+ - A ``time`` method is provided which parses the given value
+ and returns the current time value.
+ """
+
+ def compose(self, time=None, delta=None):
+ time = time or now()
+ if delta:
+ assert type(delta) == int
+ time += delta
+ return (formatdate(time),)
+
+ def parse(self, *args, **kwargs):
+ """ return the time value (in seconds since 1970) """
+ value = self.__call__(*args, **kwargs)
+ if value:
+ try:
+ return mktime_tz(parsedate_tz(value))
+ except (TypeError, OverflowError):
+ raise HTTPBadRequest((
+ "Received an ill-formed timestamp for %s: %s\r\n") %
+ (self.name, value))
+
+#
+# Following are specific HTTP headers. Since these classes are mostly
+# singletons, there is no point in keeping the class around once it has
+# been instantiated, so we use the same name.
+#
+
+class _CacheControl(_MultiValueHeader):
+ """
+ Cache-Control, RFC 2616 14.9 (use ``CACHE_CONTROL``)
+
+ This header can be constructed (using keyword arguments), by
+ first specifying one of the following mechanisms:
+
+ ``public``
+
+ if True, this argument specifies that the
+ response, as a whole, may be cashed.
+
+ ``private``
+
+ if True, this argument specifies that the response, as a
+ whole, may be cashed; this implementation does not support
+ the enumeration of private fields
+
+ ``no_cache``
+
+ if True, this argument specifies that the response, as a
+ whole, may not be cashed; this implementation does not
+ support the enumeration of private fields
+
+ In general, only one of the above three may be True, the other 2
+ must then be False or None. If all three are None, then the cache
+ is assumed to be ``public``. Following one of these mechanism
+ specifiers are various modifiers:
+
+ ``no_store``
+
+ indicates if content may be stored on disk;
+ otherwise cache is limited to memory (note:
+ users can still save the data, this applies
+ to intermediate caches)
+
+ ``max_age``
+
+ the maximum duration (in seconds) for which
+ the content should be cached; if ``no-cache``
+ is specified, this defaults to 0 seconds
+
+ ``s_maxage``
+
+ the maximum duration (in seconds) for which the
+ content should be allowed in a shared cache.
+
+ ``no_transform``
+
+ specifies that an intermediate cache should
+ not convert the content from one type to
+ another (e.g. transform a BMP to a PNG).
+
+ ``extensions``
+
+ gives additional cache-control extensions,
+ such as items like, community="UCI" (14.9.6)
+
+ The usage of ``apply()`` on this header has side-effects. As
+ recommended by RFC 2616, if ``max_age`` is provided, then then the
+ ``Expires`` header is also calculated for HTTP/1.0 clients and
+ proxies (this is done at the time ``apply()`` is called). For
+ ``no-cache`` and for ``private`` cases, we either do not want the
+ response cached or do not want any response accidently returned to
+ other users; so to prevent this case, we set the ``Expires`` header
+ to the time of the request, signifying to HTTP/1.0 transports that
+ the content isn't to be cached. If you are using SSL, your
+ communication is already "private", so to work with HTTP/1.0
+ browsers over SSL, consider specifying your cache as ``public`` as
+ the distinction between public and private is moot.
+ """
+
+ # common values for max-age; "good enough" approximates
+ ONE_HOUR = 60*60
+ ONE_DAY = ONE_HOUR * 24
+ ONE_WEEK = ONE_DAY * 7
+ ONE_MONTH = ONE_DAY * 30
+ ONE_YEAR = ONE_WEEK * 52
+
+ def _compose(self, public=None, private=None, no_cache=None,
+ no_store=False, max_age=None, s_maxage=None,
+ no_transform=False, **extensions):
+ assert isinstance(max_age, (type(None), int))
+ assert isinstance(s_maxage, (type(None), int))
+ expires = 0
+ result = []
+ if private is True:
+ assert not public and not no_cache and not s_maxage
+ result.append('private')
+ elif no_cache is True:
+ assert not public and not private and not max_age
+ result.append('no-cache')
+ else:
+ assert public is None or public is True
+ assert not private and not no_cache
+ expires = max_age
+ result.append('public')
+ if no_store:
+ result.append('no-store')
+ if no_transform:
+ result.append('no-transform')
+ if max_age is not None:
+ result.append('max-age=%d' % max_age)
+ if s_maxage is not None:
+ result.append('s-maxage=%d' % s_maxage)
+ for (k, v) in extensions.items():
+ if k not in self.extensions:
+ raise AssertionError("unexpected extension used: '%s'" % k)
+ result.append('%s="%s"' % (k.replace("_", "-"), v))
+ return (result, expires)
+
+ def compose(self, **kwargs):
+ (result, expires) = self._compose(**kwargs)
+ return result
+
+ def apply(self, collection, **kwargs):
+ """ returns the offset expiration in seconds """
+ (result, expires) = self._compose(**kwargs)
+ if expires is not None:
+ EXPIRES.update(collection, delta=expires)
+ self.update(collection, *result)
+ return expires
+
+_CacheControl('Cache-Control', 'general', 'RFC 2616, 14.9')
+
+class _ContentType(_SingleValueHeader):
+ """
+ Content-Type, RFC 2616 section 14.17
+
+ Unlike other headers, use the CGI variable instead.
+ """
+ version = '1.0'
+ _environ_name = 'CONTENT_TYPE'
+
+ # common mimetype constants
+ UNKNOWN = 'application/octet-stream'
+ TEXT_PLAIN = 'text/plain'
+ TEXT_HTML = 'text/html'
+ TEXT_XML = 'text/xml'
+
+ def compose(self, major=None, minor=None, charset=None):
+ if not major:
+ if minor in ('plain', 'html', 'xml'):
+ major = 'text'
+ else:
+ assert not minor and not charset
+ return (self.UNKNOWN,)
+ if not minor:
+ minor = "*"
+ result = "%s/%s" % (major, minor)
+ if charset:
+ result += "; charset=%s" % charset
+ return (result,)
+
+_ContentType('Content-Type', 'entity', 'RFC 2616, 14.17')
+
+class _ContentLength(_SingleValueHeader):
+ """
+ Content-Length, RFC 2616 section 14.13
+
+ Unlike other headers, use the CGI variable instead.
+ """
+ version = "1.0"
+ _environ_name = 'CONTENT_LENGTH'
+
+_ContentLength('Content-Length', 'entity', 'RFC 2616, 14.13')
+
+class _ContentDisposition(_SingleValueHeader):
+ """
+ Content-Disposition, RFC 2183 (use ``CONTENT_DISPOSITION``)
+
+ This header can be constructed (using keyword arguments),
+ by first specifying one of the following mechanisms:
+
+ ``attachment``
+
+ if True, this specifies that the content should not be
+ shown in the browser and should be handled externally,
+ even if the browser could render the content
+
+ ``inline``
+
+ exclusive with attachment; indicates that the content
+ should be rendered in the browser if possible, but
+ otherwise it should be handled externally
+
+ Only one of the above 2 may be True. If both are None, then
+ the disposition is assumed to be an ``attachment``. These are
+ distinct fields since support for field enumeration may be
+ added in the future.
+
+ ``filename``
+
+ the filename parameter, if any, to be reported; if
+ this is None, then the current object's filename
+ attribute is used
+
+ The usage of ``apply()`` on this header has side-effects. If
+ filename is provided, and Content-Type is not set or is
+ 'application/octet-stream', then the mimetypes.guess is used to
+ upgrade the Content-Type setting.
+ """
+
+ def _compose(self, attachment=None, inline=None, filename=None):
+ result = []
+ if inline is True:
+ assert not attachment
+ result.append('inline')
+ else:
+ assert not inline
+ result.append('attachment')
+ if filename:
+ assert '"' not in filename
+ filename = filename.split("/")[-1]
+ filename = filename.split("\\")[-1]
+ result.append('filename="%s"' % filename)
+ return (("; ".join(result),), filename)
+
+ def compose(self, **kwargs):
+ (result, mimetype) = self._compose(**kwargs)
+ return result
+
+ def apply(self, collection, **kwargs):
+ """ return the new Content-Type side-effect value """
+ (result, filename) = self._compose(**kwargs)
+ mimetype = CONTENT_TYPE(collection)
+ if filename and (not mimetype or CONTENT_TYPE.UNKNOWN == mimetype):
+ mimetype, _ = mimetypes.guess_type(filename)
+ if mimetype and CONTENT_TYPE.UNKNOWN != mimetype:
+ CONTENT_TYPE.update(collection, mimetype)
+ self.update(collection, *result)
+ return mimetype
+
+_ContentDisposition('Content-Disposition', 'entity', 'RFC 2183')
+
+class _IfModifiedSince(_DateHeader):
+ """
+ If-Modified-Since, RFC 2616 section 14.25
+ """
+ version = '1.0'
+
+ def __call__(self, *args, **kwargs):
+ """
+ Split the value on ';' incase the header includes extra attributes. E.g.
+ IE 6 is known to send:
+ If-Modified-Since: Sun, 25 Jun 2006 20:36:35 GMT; length=1506
+ """
+ return _DateHeader.__call__(self, *args, **kwargs).split(';', 1)[0]
+
+ def parse(self, *args, **kwargs):
+ value = _DateHeader.parse(self, *args, **kwargs)
+ if value and value > now():
+ raise HTTPBadRequest((
+ "Please check your system clock.\r\n"
+ "According to this server, the time provided in the\r\n"
+ "%s header is in the future.\r\n") % self.name)
+ return value
+_IfModifiedSince('If-Modified-Since', 'request', 'RFC 2616, 14.25')
+
+class _Range(_MultiValueHeader):
+ """
+ Range, RFC 2616 14.35 (use ``RANGE``)
+
+ According to section 14.16, the response to this message should be a
+ 206 Partial Content and that if multiple non-overlapping byte ranges
+ are requested (it is an error to request multiple overlapping
+ ranges) the result should be sent as multipart/byteranges mimetype.
+
+ The server should respond with '416 Requested Range Not Satisfiable'
+ if the requested ranges are out-of-bounds. The specification also
+ indicates that a syntax error in the Range request should result in
+ the header being ignored rather than a '400 Bad Request'.
+ """
+
+ def parse(self, *args, **kwargs):
+ """
+ Returns a tuple (units, list), where list is a sequence of
+ (begin, end) tuples; and end is None if it was not provided.
+ """
+ value = self.__call__(*args, **kwargs)
+ if not value:
+ return None
+ ranges = []
+ last_end = -1
+ try:
+ (units, range) = value.split("=", 1)
+ units = units.strip().lower()
+ for item in range.split(","):
+ (begin, end) = item.split("-")
+ if not begin.strip():
+ begin = 0
+ else:
+ begin = int(begin)
+ if begin <= last_end:
+ raise ValueError()
+ if not end.strip():
+ end = None
+ else:
+ end = int(end)
+ last_end = end
+ ranges.append((begin, end))
+ except ValueError:
+ # In this case where the Range header is malformed,
+ # section 14.16 says to treat the request as if the
+ # Range header was not present. How do I log this?
+ return None
+ return (units, ranges)
+_Range('Range', 'request', 'RFC 2616, 14.35')
+
+class _AcceptLanguage(_MultiValueHeader):
+ """
+ Accept-Language, RFC 2616 section 14.4
+ """
+
+ def parse(self, *args, **kwargs):
+ """
+ Return a list of language tags sorted by their "q" values. For example,
+ "en-us,en;q=0.5" should return ``["en-us", "en"]``. If there is no
+ ``Accept-Language`` header present, default to ``[]``.
+ """
+ header = self.__call__(*args, **kwargs)
+ if header is None:
+ return []
+ langs = [v for v in header.split(",") if v]
+ qs = []
+ for lang in langs:
+ pieces = lang.split(";")
+ lang, params = pieces[0].strip().lower(), pieces[1:]
+ q = 1
+ for param in params:
+ if '=' not in param:
+ # Malformed request; probably a bot, we'll ignore
+ continue
+ lvalue, rvalue = param.split("=")
+ lvalue = lvalue.strip().lower()
+ rvalue = rvalue.strip()
+ if lvalue == "q":
+ q = float(rvalue)
+ qs.append((lang, q))
+ qs.sort(lambda a, b: -cmp(a[1], b[1]))
+ return [lang for (lang, q) in qs]
+_AcceptLanguage('Accept-Language', 'request', 'RFC 2616, 14.4')
+
+class _AcceptRanges(_MultiValueHeader):
+ """
+ Accept-Ranges, RFC 2616 section 14.5
+ """
+ def compose(self, none=None, bytes=None):
+ if bytes:
+ return ('bytes',)
+ return ('none',)
+_AcceptRanges('Accept-Ranges', 'response', 'RFC 2616, 14.5')
+
+class _ContentRange(_SingleValueHeader):
+ """
+ Content-Range, RFC 2616 section 14.6
+ """
+ def compose(self, first_byte=None, last_byte=None, total_length=None):
+ retval = "bytes %d-%d/%d" % (first_byte, last_byte, total_length)
+ assert last_byte == -1 or first_byte <= last_byte
+ assert last_byte < total_length
+ return (retval,)
+_ContentRange('Content-Range', 'entity', 'RFC 2616, 14.6')
+
+class _Authorization(_SingleValueHeader):
+ """
+ Authorization, RFC 2617 (RFC 2616, 14.8)
+ """
+ def compose(self, digest=None, basic=None, username=None, password=None,
+ challenge=None, path=None, method=None):
+ assert username and password
+ if basic or not challenge:
+ assert not digest
+ userpass = "%s:%s" % (username.strip(), password.strip())
+ return "Basic %s" % userpass.encode('base64').strip()
+ assert challenge and not basic
+ path = path or "/"
+ (_, realm) = challenge.split('realm="')
+ (realm, _) = realm.split('"', 1)
+ auth = urllib2.AbstractDigestAuthHandler()
+ auth.add_password(realm, path, username, password)
+ (token, challenge) = challenge.split(' ', 1)
+ chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge))
+ class FakeRequest(object):
+ def get_full_url(self):
+ return path
+ def has_data(self):
+ return False
+ def get_method(self):
+ return method or "GET"
+ get_selector = get_full_url
+ retval = "Digest %s" % auth.get_authorization(FakeRequest(), chal)
+ return (retval,)
+_Authorization('Authorization', 'request', 'RFC 2617')
+
+#
+# For now, construct a minimalistic version of the field-names; at a
+# later date more complicated headers may sprout content constructors.
+# The items commented out have concrete variants.
+#
+for (name, category, version, style, comment) in \
+(("Accept" ,'request' ,'1.1','multi-value','RFC 2616, 14.1' )
+,("Accept-Charset" ,'request' ,'1.1','multi-value','RFC 2616, 14.2' )
+,("Accept-Encoding" ,'request' ,'1.1','multi-value','RFC 2616, 14.3' )
+#,("Accept-Language" ,'request' ,'1.1','multi-value','RFC 2616, 14.4' )
+#,("Accept-Ranges" ,'response','1.1','multi-value','RFC 2616, 14.5' )
+,("Age" ,'response','1.1','singular' ,'RFC 2616, 14.6' )
+,("Allow" ,'entity' ,'1.0','multi-value','RFC 2616, 14.7' )
+#,("Authorization" ,'request' ,'1.0','singular' ,'RFC 2616, 14.8' )
+#,("Cache-Control" ,'general' ,'1.1','multi-value','RFC 2616, 14.9' )
+,("Cookie" ,'request' ,'1.0','multi-value','RFC 2109/Netscape')
+,("Connection" ,'general' ,'1.1','multi-value','RFC 2616, 14.10')
+,("Content-Encoding" ,'entity' ,'1.0','multi-value','RFC 2616, 14.11')
+#,("Content-Disposition",'entity' ,'1.1','multi-value','RFC 2616, 15.5' )
+,("Content-Language" ,'entity' ,'1.1','multi-value','RFC 2616, 14.12')
+#,("Content-Length" ,'entity' ,'1.0','singular' ,'RFC 2616, 14.13')
+,("Content-Location" ,'entity' ,'1.1','singular' ,'RFC 2616, 14.14')
+,("Content-MD5" ,'entity' ,'1.1','singular' ,'RFC 2616, 14.15')
+#,("Content-Range" ,'entity' ,'1.1','singular' ,'RFC 2616, 14.16')
+#,("Content-Type" ,'entity' ,'1.0','singular' ,'RFC 2616, 14.17')
+,("Date" ,'general' ,'1.0','date-header','RFC 2616, 14.18')
+,("ETag" ,'response','1.1','singular' ,'RFC 2616, 14.19')
+,("Expect" ,'request' ,'1.1','multi-value','RFC 2616, 14.20')
+,("Expires" ,'entity' ,'1.0','date-header','RFC 2616, 14.21')
+,("From" ,'request' ,'1.0','singular' ,'RFC 2616, 14.22')
+,("Host" ,'request' ,'1.1','singular' ,'RFC 2616, 14.23')
+,("If-Match" ,'request' ,'1.1','multi-value','RFC 2616, 14.24')
+#,("If-Modified-Since" ,'request' ,'1.0','date-header','RFC 2616, 14.25')
+,("If-None-Match" ,'request' ,'1.1','multi-value','RFC 2616, 14.26')
+,("If-Range" ,'request' ,'1.1','singular' ,'RFC 2616, 14.27')
+,("If-Unmodified-Since",'request' ,'1.1','date-header' ,'RFC 2616, 14.28')
+,("Last-Modified" ,'entity' ,'1.0','date-header','RFC 2616, 14.29')
+,("Location" ,'response','1.0','singular' ,'RFC 2616, 14.30')
+,("Max-Forwards" ,'request' ,'1.1','singular' ,'RFC 2616, 14.31')
+,("Pragma" ,'general' ,'1.0','multi-value','RFC 2616, 14.32')
+,("Proxy-Authenticate" ,'response','1.1','multi-value','RFC 2616, 14.33')
+,("Proxy-Authorization",'request' ,'1.1','singular' ,'RFC 2616, 14.34')
+#,("Range" ,'request' ,'1.1','multi-value','RFC 2616, 14.35')
+,("Referer" ,'request' ,'1.0','singular' ,'RFC 2616, 14.36')
+,("Retry-After" ,'response','1.1','singular' ,'RFC 2616, 14.37')
+,("Server" ,'response','1.0','singular' ,'RFC 2616, 14.38')
+,("Set-Cookie" ,'response','1.0','multi-entry','RFC 2109/Netscape')
+,("TE" ,'request' ,'1.1','multi-value','RFC 2616, 14.39')
+,("Trailer" ,'general' ,'1.1','multi-value','RFC 2616, 14.40')
+,("Transfer-Encoding" ,'general' ,'1.1','multi-value','RFC 2616, 14.41')
+,("Upgrade" ,'general' ,'1.1','multi-value','RFC 2616, 14.42')
+,("User-Agent" ,'request' ,'1.0','singular' ,'RFC 2616, 14.43')
+,("Vary" ,'response','1.1','multi-value','RFC 2616, 14.44')
+,("Via" ,'general' ,'1.1','multi-value','RFC 2616, 14.45')
+,("Warning" ,'general' ,'1.1','multi-entry','RFC 2616, 14.46')
+,("WWW-Authenticate" ,'response','1.0','multi-entry','RFC 2616, 14.47')):
+ klass = {'multi-value': _MultiValueHeader,
+ 'multi-entry': _MultiEntryHeader,
+ 'date-header': _DateHeader,
+ 'singular' : _SingleValueHeader}[style]
+ klass(name, category, comment, version).__doc__ = comment
+ del klass
+
+for head in _headers.values():
+ headname = head.name.replace("-","_").upper()
+ locals()[headname] = head
+ __all__.append(headname)
+
+__pudge_all__ = __all__[:]
+for _name, _obj in globals().items():
+ if isinstance(_obj, type) and issubclass(_obj, HTTPHeader):
+ __pudge_all__.append(_name)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpserver.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpserver.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/httpserver.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1411 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+WSGI HTTP Server
+
+This is a minimalistic WSGI server using Python's built-in BaseHTTPServer;
+if pyOpenSSL is installed, it also provides SSL capabilities.
+"""
+
+# @@: add in protection against HTTP/1.0 clients who claim to
+# be 1.1 but do not send a Content-Length
+
+# @@: add support for chunked encoding, this is not a 1.1 server
+# till this is completed.
+
+import atexit
+import traceback
+import socket, sys, threading, urlparse, Queue, urllib
+import posixpath
+import time
+import thread
+import os
+from itertools import count
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SocketServer import ThreadingMixIn
+from paste.util import converters
+import logging
+try:
+ from paste.util import killthread
+except ImportError:
+ # Not available, probably no ctypes
+ killthread = None
+
+__all__ = ['WSGIHandlerMixin', 'WSGIServer', 'WSGIHandler', 'serve']
+__version__ = "0.5"
+
+class ContinueHook(object):
+ """
+ When a client request includes a 'Expect: 100-continue' header, then
+ it is the responsibility of the server to send 100 Continue when it
+ is ready for the content body. This allows authentication, access
+ levels, and other exceptions to be detected *before* bandwith is
+ spent on the request body.
+
+ This is a rfile wrapper that implements this functionality by
+ sending 100 Continue to the client immediately after the user
+ requests the content via a read() operation on the rfile stream.
+ After this response is sent, it becomes a pass-through object.
+ """
+
+ def __init__(self, rfile, write):
+ self._ContinueFile_rfile = rfile
+ self._ContinueFile_write = write
+ for attr in ('close', 'closed', 'fileno', 'flush',
+ 'mode', 'bufsize', 'softspace'):
+ if hasattr(rfile, attr):
+ setattr(self, attr, getattr(rfile, attr))
+ for attr in ('read', 'readline', 'readlines'):
+ if hasattr(rfile, attr):
+ setattr(self, attr, getattr(self, '_ContinueFile_' + attr))
+
+ def _ContinueFile_send(self):
+ self._ContinueFile_write("HTTP/1.1 100 Continue\r\n\r\n")
+ rfile = self._ContinueFile_rfile
+ for attr in ('read', 'readline', 'readlines'):
+ if hasattr(rfile, attr):
+ setattr(self, attr, getattr(rfile, attr))
+
+ def _ContinueFile_read(self, size=-1):
+ self._ContinueFile_send()
+ return self._ContinueFile_rfile.read(size)
+
+ def _ContinueFile_readline(self, size=-1):
+ self._ContinueFile_send()
+ return self._ContinueFile_rfile.readline(size)
+
+ def _ContinueFile_readlines(self, sizehint=0):
+ self._ContinueFile_send()
+ return self._ContinueFile_rfile.readlines(sizehint)
+
+class WSGIHandlerMixin:
+ """
+ WSGI mix-in for HTTPRequestHandler
+
+ This class is a mix-in to provide WSGI functionality to any
+ HTTPRequestHandler derivative (as provided in Python's BaseHTTPServer).
+ This assumes a ``wsgi_application`` handler on ``self.server``.
+ """
+ lookup_addresses = True
+
+ def log_request(self, *args, **kwargs):
+ """ disable success request logging
+
+ Logging transactions should not be part of a WSGI server,
+ if you want logging; look at paste.translogger
+ """
+ pass
+
+ def log_message(self, *args, **kwargs):
+ """ disable error message logging
+
+ Logging transactions should not be part of a WSGI server,
+ if you want logging; look at paste.translogger
+ """
+ pass
+
+ def version_string(self):
+ """ behavior that BaseHTTPServer should have had """
+ if not self.sys_version:
+ return self.server_version
+ else:
+ return self.server_version + ' ' + self.sys_version
+
+ def wsgi_write_chunk(self, chunk):
+ """
+ Write a chunk of the output stream; send headers if they
+ have not already been sent.
+ """
+ if not self.wsgi_headers_sent and not self.wsgi_curr_headers:
+ raise RuntimeError(
+ "Content returned before start_response called")
+ if not self.wsgi_headers_sent:
+ self.wsgi_headers_sent = True
+ (status, headers) = self.wsgi_curr_headers
+ code, message = status.split(" ", 1)
+ self.send_response(int(code), message)
+ #
+ # HTTP/1.1 compliance; either send Content-Length or
+ # signal that the connection is being closed.
+ #
+ send_close = True
+ for (k, v) in headers:
+ lk = k.lower()
+ if 'content-length' == lk:
+ send_close = False
+ if 'connection' == lk:
+ if 'close' == v.lower():
+ self.close_connection = 1
+ send_close = False
+ self.send_header(k, v)
+ if send_close:
+ self.close_connection = 1
+ self.send_header('Connection', 'close')
+
+ self.end_headers()
+ self.wfile.write(chunk)
+
+ def wsgi_start_response(self, status, response_headers, exc_info=None):
+ if exc_info:
+ try:
+ if self.wsgi_headers_sent:
+ raise exc_info[0], exc_info[1], exc_info[2]
+ else:
+ # In this case, we're going to assume that the
+ # higher-level code is currently handling the
+ # issue and returning a resonable response.
+ # self.log_error(repr(exc_info))
+ pass
+ finally:
+ exc_info = None
+ elif self.wsgi_curr_headers:
+ assert 0, "Attempt to set headers a second time w/o an exc_info"
+ self.wsgi_curr_headers = (status, response_headers)
+ return self.wsgi_write_chunk
+
+ def wsgi_setup(self, environ=None):
+ """
+ Setup the member variables used by this WSGI mixin, including
+ the ``environ`` and status member variables.
+
+ After the basic environment is created; the optional ``environ``
+ argument can be used to override any settings.
+ """
+
+ (scheme, netloc, path, query, fragment) = urlparse.urlsplit(self.path)
+ path = urllib.unquote(path)
+ endslash = path.endswith('/')
+ path = posixpath.normpath(path)
+ if endslash and path != '/':
+ # Put the slash back...
+ path += '/'
+ (server_name, server_port) = self.server.server_address[:2]
+
+ rfile = self.rfile
+ if 'HTTP/1.1' == self.protocol_version and \
+ '100-continue' == self.headers.get('Expect','').lower():
+ rfile = ContinueHook(rfile, self.wfile.write)
+ else:
+ # We can put in the protection to keep from over-reading the
+ # file
+ try:
+ content_length = int(self.headers.get('Content-Length', '0'))
+ except ValueError:
+ content_length = 0
+ if not hasattr(self.connection, 'get_context'):
+ # @@: LimitedLengthFile is currently broken in connection
+ # with SSL (sporatic errors that are diffcult to trace, but
+ # ones that go away when you don't use LimitedLengthFile)
+ rfile = LimitedLengthFile(rfile, content_length)
+
+ remote_address = self.client_address[0]
+ self.wsgi_environ = {
+ 'wsgi.version': (1,0)
+ ,'wsgi.url_scheme': 'http'
+ ,'wsgi.input': rfile
+ ,'wsgi.errors': sys.stderr
+ ,'wsgi.multithread': True
+ ,'wsgi.multiprocess': False
+ ,'wsgi.run_once': False
+ # CGI variables required by PEP-333
+ ,'REQUEST_METHOD': self.command
+ ,'SCRIPT_NAME': '' # application is root of server
+ ,'PATH_INFO': path
+ ,'QUERY_STRING': query
+ ,'CONTENT_TYPE': self.headers.get('Content-Type', '')
+ ,'CONTENT_LENGTH': self.headers.get('Content-Length', '0')
+ ,'SERVER_NAME': server_name
+ ,'SERVER_PORT': str(server_port)
+ ,'SERVER_PROTOCOL': self.request_version
+ # CGI not required by PEP-333
+ ,'REMOTE_ADDR': remote_address
+ }
+ if scheme:
+ self.wsgi_environ['paste.httpserver.proxy.scheme'] = scheme
+ if netloc:
+ self.wsgi_environ['paste.httpserver.proxy.host'] = netloc
+
+ if self.lookup_addresses:
+ # @@: make lookup_addreses actually work, at this point
+ # it has been address_string() is overriden down in
+ # file and hence is a noop
+ if remote_address.startswith("192.168.") \
+ or remote_address.startswith("10.") \
+ or remote_address.startswith("172.16."):
+ pass
+ else:
+ address_string = None # self.address_string()
+ if address_string:
+ self.wsgi_environ['REMOTE_HOST'] = address_string
+
+ if hasattr(self.server, 'thread_pool'):
+ # Now that we know what the request was for, we should
+ # tell the thread pool what its worker is working on
+ self.server.thread_pool.worker_tracker[thread.get_ident()][1] = self.wsgi_environ
+ self.wsgi_environ['paste.httpserver.thread_pool'] = self.server.thread_pool
+
+ for k, v in self.headers.items():
+ key = 'HTTP_' + k.replace("-","_").upper()
+ if key in ('HTTP_CONTENT_TYPE','HTTP_CONTENT_LENGTH'):
+ continue
+ self.wsgi_environ[key] = ','.join(self.headers.getheaders(k))
+
+ if hasattr(self.connection,'get_context'):
+ self.wsgi_environ['wsgi.url_scheme'] = 'https'
+ # @@: extract other SSL parameters from pyOpenSSL at...
+ # http://www.modssl.org/docs/2.8/ssl_reference.html#ToC25
+
+ if environ:
+ assert isinstance(environ, dict)
+ self.wsgi_environ.update(environ)
+ if 'on' == environ.get('HTTPS'):
+ self.wsgi_environ['wsgi.url_scheme'] = 'https'
+
+ self.wsgi_curr_headers = None
+ self.wsgi_headers_sent = False
+
+ def wsgi_connection_drop(self, exce, environ=None):
+ """
+ Override this if you're interested in socket exceptions, such
+ as when the user clicks 'Cancel' during a file download.
+ """
+ pass
+
+ def wsgi_execute(self, environ=None):
+ """
+ Invoke the server's ``wsgi_application``.
+ """
+
+ self.wsgi_setup(environ)
+
+ try:
+ result = self.server.wsgi_application(self.wsgi_environ,
+ self.wsgi_start_response)
+ try:
+ for chunk in result:
+ self.wsgi_write_chunk(chunk)
+ if not self.wsgi_headers_sent:
+ self.wsgi_write_chunk('')
+ finally:
+ if hasattr(result,'close'):
+ result.close()
+ result = None
+ except socket.error, exce:
+ self.wsgi_connection_drop(exce, environ)
+ return
+ except:
+ if not self.wsgi_headers_sent:
+ error_msg = "Internal Server Error\n"
+ self.wsgi_curr_headers = (
+ '500 Internal Server Error',
+ [('Content-type', 'text/plain'),
+ ('Content-length', str(len(error_msg)))])
+ self.wsgi_write_chunk("Internal Server Error\n")
+ raise
+
+#
+# SSL Functionality
+#
+# This implementation was motivated by Sebastien Martini's SSL example
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
+#
+try:
+ from OpenSSL import SSL, tsafe
+ SocketErrors = (socket.error, SSL.ZeroReturnError, SSL.SysCallError)
+except ImportError:
+ # Do not require pyOpenSSL to be installed, but disable SSL
+ # functionality in that case.
+ SSL = None
+ SocketErrors = (socket.error,)
+ class SecureHTTPServer(HTTPServer):
+ def __init__(self, server_address, RequestHandlerClass,
+ ssl_context=None, request_queue_size=None):
+ assert not ssl_context, "pyOpenSSL not installed"
+ HTTPServer.__init__(self, server_address, RequestHandlerClass)
+ if request_queue_size:
+ self.socket.listen(request_queue_size)
+else:
+
+ class _ConnFixer(object):
+ """ wraps a socket connection so it implements makefile """
+ def __init__(self, conn):
+ self.__conn = conn
+ def makefile(self, mode, bufsize):
+ return socket._fileobject(self.__conn, mode, bufsize)
+ def __getattr__(self, attrib):
+ return getattr(self.__conn, attrib)
+
+ class SecureHTTPServer(HTTPServer):
+ """
+ Provides SSL server functionality on top of the BaseHTTPServer
+ by overriding _private_ members of Python's standard
+ distribution. The interface for this instance only changes by
+ adding a an optional ssl_context attribute to the constructor:
+
+ cntx = SSL.Context(SSL.SSLv23_METHOD)
+ cntx.use_privatekey_file("host.pem")
+ cntx.use_certificate_file("host.pem")
+
+ """
+
+ def __init__(self, server_address, RequestHandlerClass,
+ ssl_context=None, request_queue_size=None):
+ # This overrides the implementation of __init__ in python's
+ # SocketServer.TCPServer (which BaseHTTPServer.HTTPServer
+ # does not override, thankfully).
+ HTTPServer.__init__(self, server_address, RequestHandlerClass)
+ self.socket = socket.socket(self.address_family,
+ self.socket_type)
+ self.ssl_context = ssl_context
+ if ssl_context:
+ class TSafeConnection(tsafe.Connection):
+ def settimeout(self, *args):
+ self._lock.acquire()
+ try:
+ return self._ssl_conn.settimeout(*args)
+ finally:
+ self._lock.release()
+ def gettimeout(self):
+ self._lock.acquire()
+ try:
+ return self._ssl_conn.gettimeout()
+ finally:
+ self._lock.release()
+ self.socket = TSafeConnection(ssl_context, self.socket)
+ self.server_bind()
+ if request_queue_size:
+ self.socket.listen(request_queue_size)
+ self.server_activate()
+
+ def get_request(self):
+ # The default SSL request object does not seem to have a
+ # ``makefile(mode, bufsize)`` method as expected by
+ # Socketserver.StreamRequestHandler.
+ (conn, info) = self.socket.accept()
+ if self.ssl_context:
+ conn = _ConnFixer(conn)
+ return (conn, info)
+
+ def _auto_ssl_context():
+ import OpenSSL, time, random
+ pkey = OpenSSL.crypto.PKey()
+ pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 768)
+
+ cert = OpenSSL.crypto.X509()
+
+ cert.set_serial_number(random.randint(0, sys.maxint))
+ cert.gmtime_adj_notBefore(0)
+ cert.gmtime_adj_notAfter(60 * 60 * 24 * 365)
+ cert.get_subject().CN = '*'
+ cert.get_subject().O = 'Dummy Certificate'
+ cert.get_issuer().CN = 'Untrusted Authority'
+ cert.get_issuer().O = 'Self-Signed'
+ cert.set_pubkey(pkey)
+ cert.sign(pkey, 'md5')
+
+ ctx = SSL.Context(SSL.SSLv23_METHOD)
+ ctx.use_privatekey(pkey)
+ ctx.use_certificate(cert)
+
+ return ctx
+
+class WSGIHandler(WSGIHandlerMixin, BaseHTTPRequestHandler):
+ """
+ A WSGI handler that overrides POST, GET and HEAD to delegate
+ requests to the server's ``wsgi_application``.
+ """
+ server_version = 'PasteWSGIServer/' + __version__
+
+ def handle_one_request(self):
+ """Handle a single HTTP request.
+
+ You normally don't need to override this method; see the class
+ __doc__ string for information on how to handle specific HTTP
+ commands such as GET and POST.
+
+ """
+ self.raw_requestline = self.rfile.readline()
+ if not self.raw_requestline:
+ self.close_connection = 1
+ return
+ if not self.parse_request(): # An error code has been sent, just exit
+ return
+ self.wsgi_execute()
+
+ def handle(self):
+ # don't bother logging disconnects while handling a request
+ try:
+ BaseHTTPRequestHandler.handle(self)
+ except SocketErrors, exce:
+ self.wsgi_connection_drop(exce)
+
+ def address_string(self):
+ """Return the client address formatted for logging.
+
+ This is overridden so that no hostname lookup is done.
+ """
+ return ''
+
+class LimitedLengthFile(object):
+ def __init__(self, file, length):
+ self.file = file
+ self.length = length
+ self._consumed = 0
+ if hasattr(self.file, 'seek'):
+ self.seek = self._seek
+
+ def __repr__(self):
+ base_repr = repr(self.file)
+ return base_repr[:-1] + ' length=%s>' % self.length
+
+ def read(self, length=None):
+ left = self.length - self._consumed
+ if length is None:
+ length = left
+ else:
+ length = min(length, left)
+ # next two lines are hnecessary only if read(0) blocks
+ if not left:
+ return ''
+ data = self.file.read(length)
+ self._consumed += len(data)
+ return data
+
+ def readline(self, *args):
+ max_read = self.length - self._consumed
+ if len(args):
+ max_read = min(args[0], max_read)
+ data = self.file.readline(max_read)
+ self._consumed += len(data)
+ return data
+
+ def readlines(self, hint=None):
+ data = self.file.readlines(hint)
+ for chunk in data:
+ self._consumed += len(chunk)
+ return data
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.length - self._consumed <= 0:
+ raise StopIteration
+ return self.readline()
+
+ ## Optional methods ##
+
+ def _seek(self, place):
+ self.file.seek(place)
+ self._consumed = place
+
+ def tell(self):
+ if hasattr(self.file, 'tell'):
+ return self.file.tell()
+ else:
+ return self._consumed
+
+class ThreadPool(object):
+ """
+ Generic thread pool with a queue of callables to consume.
+
+ Keeps a notion of the status of its worker threads:
+
+ idle: worker thread with nothing to do
+
+ busy: worker thread doing its job
+
+ hung: worker thread that's been doing a job for too long
+
+ dying: a hung thread that has been killed, but hasn't died quite
+ yet.
+
+ zombie: what was a worker thread that we've tried to kill but
+ isn't dead yet.
+
+ At any time you can call track_threads, to get a dictionary with
+ these keys and lists of thread_ids that fall in that status. All
+ keys will be present, even if they point to emty lists.
+
+ hung threads are threads that have been busy more than
+ hung_thread_limit seconds. Hung threads are killed when they live
+ longer than kill_thread_limit seconds. A thread is then
+ considered dying for dying_limit seconds, if it is still alive
+ after that it is considered a zombie.
+
+ When there are no idle workers and a request comes in, another
+ worker *may* be spawned. If there are less than spawn_if_under
+ threads in the busy state, another thread will be spawned. So if
+ the limit is 5, and there are 4 hung threads and 6 busy threads,
+ no thread will be spawned.
+
+ When there are more than max_zombie_threads_before_die zombie
+ threads, a SystemExit exception will be raised, stopping the
+ server. Use 0 or None to never raise this exception. Zombie
+ threads *should* get cleaned up, but killing threads is no
+ necessarily reliable. This is turned off by default, since it is
+ only a good idea if you've deployed the server with some process
+ watching from above (something similar to daemontools or zdaemon).
+
+ Each worker thread only processes ``max_requests`` tasks before it
+ dies and replaces itself with a new worker thread.
+ """
+
+
+ SHUTDOWN = object()
+
+ def __init__(
+ self, nworkers, name="ThreadPool", daemon=False,
+ max_requests=100, # threads are killed after this many requests
+ hung_thread_limit=30, # when a thread is marked "hung"
+ kill_thread_limit=1800, # when you kill that hung thread
+ dying_limit=300, # seconds that a kill should take to go into effect (longer than this and the thread is a "zombie")
+ spawn_if_under=5, # spawn if there's too many hung threads
+ max_zombie_threads_before_die=0, # when to give up on the process
+ hung_check_period=100, # every 100 requests check for hung workers
+ logger=None, # Place to log messages to
+ error_email=None, # Person(s) to notify if serious problem occurs
+ ):
+ """
+ Create thread pool with `nworkers` worker threads.
+ """
+ self.nworkers = nworkers
+ self.max_requests = max_requests
+ self.name = name
+ self.queue = Queue.Queue()
+ self.workers = []
+ self.daemon = daemon
+ if logger is None:
+ logger = logging.getLogger('paste.httpserver.ThreadPool')
+ if isinstance(logger, basestring):
+ logger = logging.getLogger(logger)
+ self.logger = logger
+ self.error_email = error_email
+ self._worker_count = count()
+
+ assert (not kill_thread_limit
+ or kill_thread_limit >= hung_thread_limit), (
+ "kill_thread_limit (%s) should be higher than hung_thread_limit (%s)"
+ % (kill_thread_limit, hung_thread_limit))
+ if not killthread:
+ kill_thread_limit = 0
+ self.logger.info(
+ "Cannot use kill_thread_limit as ctypes/killthread is not available")
+ self.kill_thread_limit = kill_thread_limit
+ self.dying_limit = dying_limit
+ self.hung_thread_limit = hung_thread_limit
+ assert spawn_if_under <= nworkers, (
+ "spawn_if_under (%s) should be less than nworkers (%s)"
+ % (spawn_if_under, nworkers))
+ self.spawn_if_under = spawn_if_under
+ self.max_zombie_threads_before_die = max_zombie_threads_before_die
+ self.hung_check_period = hung_check_period
+ self.requests_since_last_hung_check = 0
+ # Used to keep track of what worker is doing what:
+ self.worker_tracker = {}
+ # Used to keep track of the workers not doing anything:
+ self.idle_workers = []
+ # Used to keep track of threads that have been killed, but maybe aren't dead yet:
+ self.dying_threads = {}
+ # This is used to track when we last had to add idle workers;
+ # we shouldn't cull extra workers until some time has passed
+ # (hung_thread_limit) since workers were added:
+ self._last_added_new_idle_workers = 0
+ if not daemon:
+ atexit.register(self.shutdown)
+ for i in range(self.nworkers):
+ self.add_worker_thread(message='Initial worker pool')
+
+ def add_task(self, task):
+ """
+ Add a task to the queue
+ """
+ self.logger.debug('Added task (%i tasks queued)', self.queue.qsize())
+ if self.hung_check_period:
+ self.requests_since_last_hung_check += 1
+ if self.requests_since_last_hung_check > self.hung_check_period:
+ self.requests_since_last_hung_check = 0
+ self.kill_hung_threads()
+ if not self.idle_workers and self.spawn_if_under:
+ # spawn_if_under can come into effect...
+ busy = 0
+ now = time.time()
+ self.logger.debug('No idle workers for task; checking if we need to make more workers')
+ for worker in self.workers:
+ if not hasattr(worker, 'thread_id'):
+ # Not initialized
+ continue
+ time_started, info = self.worker_tracker.get(worker.thread_id,
+ (None, None))
+ if time_started is not None:
+ if now - time_started < self.hung_thread_limit:
+ busy += 1
+ if busy < self.spawn_if_under:
+ self.logger.info(
+ 'No idle tasks, and only %s busy tasks; adding %s more '
+ 'workers', busy, self.spawn_if_under-busy)
+ self._last_added_new_idle_workers = time.time()
+ for i in range(self.spawn_if_under - busy):
+ self.add_worker_thread(message='Response to lack of idle workers')
+ else:
+ self.logger.debug(
+ 'No extra workers needed (%s busy workers)',
+ busy)
+ if (len(self.workers) > self.nworkers
+ and len(self.idle_workers) > 3
+ and time.time()-self._last_added_new_idle_workers > self.hung_thread_limit):
+ # We've spawned worers in the past, but they aren't needed
+ # anymore; kill off some
+ self.logger.info(
+ 'Culling %s extra workers (%s idle workers present)',
+ len(self.workers)-self.nworkers, len(self.idle_workers))
+ self.logger.debug(
+ 'Idle workers: %s', self.idle_workers)
+ for i in range(len(self.workers) - self.nworkers):
+ self.queue.put(self.SHUTDOWN)
+ self.queue.put(task)
+
+ def track_threads(self):
+ """
+ Return a dict summarizing the threads in the pool (as
+ described in the ThreadPool docstring).
+ """
+ result = dict(idle=[], busy=[], hung=[], dying=[], zombie=[])
+ now = time.time()
+ for worker in self.workers:
+ if not hasattr(worker, 'thread_id'):
+ # The worker hasn't fully started up, we should just
+ # ignore it
+ continue
+ time_started, info = self.worker_tracker.get(worker.thread_id,
+ (None, None))
+ if time_started is not None:
+ if now - time_started > self.hung_thread_limit:
+ result['hung'].append(worker)
+ else:
+ result['busy'].append(worker)
+ else:
+ result['idle'].append(worker)
+ for thread_id, (time_killed, worker) in self.dying_threads.items():
+ if not self.thread_exists(thread_id):
+ # Cull dying threads that are actually dead and gone
+ self.logger.info('Killed thread %s no longer around',
+ thread_id)
+ try:
+ del self.dying_threads[thread_id]
+ except KeyError:
+ pass
+ continue
+ if now - time_killed > self.dying_limit:
+ result['zombie'].append(worker)
+ else:
+ result['dying'].append(worker)
+ return result
+
+ def kill_worker(self, thread_id):
+ """
+ Removes the worker with the given thread_id from the pool, and
+ replaces it with a new worker thread.
+
+ This should only be done for mis-behaving workers.
+ """
+ if killthread is None:
+ raise RuntimeError(
+ "Cannot kill worker; killthread/ctypes not available")
+ thread_obj = threading._active.get(thread_id)
+ killthread.async_raise(thread_id, SystemExit)
+ try:
+ del self.worker_tracker[thread_id]
+ except KeyError:
+ pass
+ self.logger.info('Killing thread %s', thread_id)
+ if thread_obj in self.workers:
+ self.workers.remove(thread_obj)
+ self.dying_threads[thread_id] = (time.time(), thread_obj)
+ self.add_worker_thread(message='Replacement for killed thread %s' % thread_id)
+
+ def thread_exists(self, thread_id):
+ """
+ Returns true if a thread with this id is still running
+ """
+ return thread_id in threading._active
+
+ def add_worker_thread(self, *args, **kwargs):
+ index = self._worker_count.next()
+ worker = threading.Thread(target=self.worker_thread_callback,
+ args=args, kwargs=kwargs,
+ name=("worker %d" % index))
+ worker.setDaemon(self.daemon)
+ worker.start()
+
+ def kill_hung_threads(self):
+ """
+ Tries to kill any hung threads
+ """
+ if not self.kill_thread_limit:
+ # No killing should occur
+ return
+ now = time.time()
+ max_time = 0
+ total_time = 0
+ idle_workers = 0
+ starting_workers = 0
+ working_workers = 0
+ killed_workers = 0
+ for worker in self.workers:
+ if not hasattr(worker, 'thread_id'):
+ # Not setup yet
+ starting_workers += 1
+ continue
+ time_started, info = self.worker_tracker.get(worker.thread_id,
+ (None, None))
+ if time_started is None:
+ # Must be idle
+ idle_workers += 1
+ continue
+ working_workers += 1
+ max_time = max(max_time, now-time_started)
+ total_time += now-time_started
+ if now - time_started > self.kill_thread_limit:
+ self.logger.warning(
+ 'Thread %s hung (working on task for %i seconds)',
+ worker.thread_id, now - time_started)
+ try:
+ import pprint
+ info_desc = pprint.pformat(info)
+ except:
+ out = StringIO()
+ traceback.print_exc(file=out)
+ info_desc = 'Error:\n%s' % out.getvalue()
+ self.notify_problem(
+ "Killing worker thread (id=%(thread_id)s) because it has been \n"
+ "working on task for %(time)s seconds (limit is %(limit)s)\n"
+ "Info on task:\n"
+ "%(info)s"
+ % dict(thread_id=worker.thread_id,
+ time=now - time_started,
+ limit=self.kill_thread_limit,
+ info=info_desc))
+ self.kill_worker(worker.thread_id)
+ killed_workers += 1
+ if working_workers:
+ ave_time = float(total_time) / working_workers
+ ave_time = '%.2fsec' % ave_time
+ else:
+ ave_time = 'N/A'
+ self.logger.info(
+ "kill_hung_threads status: %s threads (%s working, %s idle, %s starting) "
+ "ave time %s, max time %.2fsec, killed %s workers"
+ % (idle_workers + starting_workers + working_workers,
+ working_workers, idle_workers, starting_workers,
+ ave_time, max_time, killed_workers))
+ self.check_max_zombies()
+
+ def check_max_zombies(self):
+ """
+ Check if we've reached max_zombie_threads_before_die; if so
+ then kill the entire process.
+ """
+ if not self.max_zombie_threads_before_die:
+ return
+ found = []
+ now = time.time()
+ for thread_id, (time_killed, worker) in self.dying_threads.items():
+ if not self.thread_exists(thread_id):
+ # Cull dying threads that are actually dead and gone
+ try:
+ del self.dying_threads[thread_id]
+ except KeyError:
+ pass
+ continue
+ if now - time_killed > self.dying_limit:
+ found.append(thread_id)
+ if found:
+ self.logger.info('Found %s zombie threads', found)
+ if len(found) > self.max_zombie_threads_before_die:
+ self.logger.fatal(
+ 'Exiting process because %s zombie threads is more than %s limit',
+ len(found), self.max_zombie_threads_before_die)
+ self.notify_problem(
+ "Exiting process because %(found)s zombie threads "
+ "(more than limit of %(limit)s)\n"
+ "Bad threads (ids):\n"
+ " %(ids)s\n"
+ % dict(found=len(found),
+ limit=self.max_zombie_threads_before_die,
+ ids="\n ".join(map(str, found))),
+ subject="Process restart (too many zombie threads)")
+ self.shutdown(10)
+ print 'Shutting down', threading.currentThread()
+ raise ServerExit(3)
+
+ def worker_thread_callback(self, message=None):
+ """
+ Worker thread should call this method to get and process queued
+ callables.
+ """
+ thread_obj = threading.currentThread()
+ thread_id = thread_obj.thread_id = thread.get_ident()
+ self.workers.append(thread_obj)
+ self.idle_workers.append(thread_id)
+ requests_processed = 0
+ add_replacement_worker = False
+ self.logger.debug('Started new worker %s: %s', thread_id, message)
+ try:
+ while True:
+ if self.max_requests and self.max_requests < requests_processed:
+ # Replace this thread then die
+ self.logger.debug('Thread %s processed %i requests (limit %s); stopping thread'
+ % (thread_id, requests_processed, self.max_requests))
+ add_replacement_worker = True
+ break
+ runnable = self.queue.get()
+ if runnable is ThreadPool.SHUTDOWN:
+ self.logger.debug('Worker %s asked to SHUTDOWN', thread_id)
+ break
+ try:
+ self.idle_workers.remove(thread_id)
+ except ValueError:
+ pass
+ self.worker_tracker[thread_id] = [time.time(), None]
+ requests_processed += 1
+ try:
+ try:
+ runnable()
+ except:
+ # We are later going to call sys.exc_clear(),
+ # removing all remnants of any exception, so
+ # we should log it now. But ideally no
+ # exception should reach this level
+ print >> sys.stderr, (
+ 'Unexpected exception in worker %r' % runnable)
+ traceback.print_exc()
+ if thread_id in self.dying_threads:
+ # That last exception was intended to kill me
+ break
+ finally:
+ try:
+ del self.worker_tracker[thread_id]
+ except KeyError:
+ pass
+ sys.exc_clear()
+ self.idle_workers.append(thread_id)
+ finally:
+ try:
+ del self.worker_tracker[thread_id]
+ except KeyError:
+ pass
+ try:
+ self.idle_workers.remove(thread_id)
+ except ValueError:
+ pass
+ try:
+ self.workers.remove(thread_obj)
+ except ValueError:
+ pass
+ try:
+ del self.dying_threads[thread_id]
+ except KeyError:
+ pass
+ if add_replacement_worker:
+ self.add_worker_thread(message='Voluntary replacement for thread %s' % thread_id)
+
+ def shutdown(self, force_quit_timeout=0):
+ """
+ Shutdown the queue (after finishing any pending requests).
+ """
+ self.logger.info('Shutting down threadpool')
+ # Add a shutdown request for every worker
+ for i in range(len(self.workers)):
+ self.queue.put(ThreadPool.SHUTDOWN)
+ # Wait for each thread to terminate
+ hung_workers = []
+ for worker in self.workers:
+ worker.join(0.5)
+ if worker.isAlive():
+ hung_workers.append(worker)
+ zombies = []
+ for thread_id in self.dying_threads:
+ if self.thread_exists(thread_id):
+ zombies.append(thread_id)
+ if hung_workers or zombies:
+ self.logger.info("%s workers didn't stop properly, and %s zombies",
+ len(hung_workers), len(zombies))
+ if hung_workers:
+ for worker in hung_workers:
+ self.kill_worker(worker.thread_id)
+ self.logger.info('Workers killed forcefully')
+ if force_quit_timeout:
+ hung = []
+ timed_out = False
+ need_force_quit = bool(zombies)
+ for workers in self.workers:
+ if not timed_out and worker.isAlive():
+ timed_out = True
+ worker.join(force_quit_timeout)
+ if worker.isAlive():
+ print "Worker %s won't die" % worker
+ need_force_quit = True
+ if need_force_quit:
+ import atexit
+ # Remove the threading atexit callback
+ for callback in list(atexit._exithandlers):
+ func = getattr(callback[0], 'im_func', None)
+ if not func:
+ continue
+ globs = getattr(func, 'func_globals', {})
+ mod = globs.get('__name__')
+ if mod == 'threading':
+ atexit._exithandlers.remove(callback)
+ atexit._run_exitfuncs()
+ print 'Forcefully exiting process'
+ os._exit(3)
+ else:
+ self.logger.info('All workers eventually killed')
+ else:
+ self.logger.info('All workers stopped')
+
+ def notify_problem(self, msg, subject=None, spawn_thread=True):
+ """
+ Called when there's a substantial problem. msg contains the
+ body of the notification, subject the summary.
+
+ If spawn_thread is true, then the email will be send in
+ another thread (so this doesn't block).
+ """
+ if not self.error_email:
+ return
+ if spawn_thread:
+ t = threading.Thread(
+ target=self.notify_problem,
+ args=(msg, subject, False))
+ t.start()
+ return
+ from_address = 'errors at localhost'
+ if not subject:
+ subject = msg.strip().splitlines()[0]
+ subject = subject[:50]
+ subject = '[http threadpool] %s' % subject
+ headers = [
+ "To: %s" % self.error_email,
+ "From: %s" % from_address,
+ "Subject: %s" % subject,
+ ]
+ try:
+ system = ' '.join(os.uname())
+ except:
+ system = '(unknown)'
+ body = (
+ "An error has occurred in the paste.httpserver.ThreadPool\n"
+ "Error:\n"
+ " %(msg)s\n"
+ "Occurred at: %(time)s\n"
+ "PID: %(pid)s\n"
+ "System: %(system)s\n"
+ "Server .py file: %(file)s\n"
+ % dict(msg=msg,
+ time=time.strftime("%c"),
+ pid=os.getpid(),
+ system=system,
+ file=os.path.abspath(__file__),
+ ))
+ message = '\n'.join(headers) + "\n\n" + body
+ import smtplib
+ server = smtplib.SMTP('localhost')
+ error_emails = [
+ e.strip() for e in self.error_email.split(",")
+ if e.strip()]
+ server.sendmail(from_address, error_emails, message)
+ server.quit()
+ print 'email sent to', error_emails, message
+
+class ThreadPoolMixIn(object):
+ """
+ Mix-in class to process requests from a thread pool
+ """
+ def __init__(self, nworkers, daemon=False, **threadpool_options):
+ # Create and start the workers
+ self.running = True
+ assert nworkers > 0, "ThreadPoolMixIn servers must have at least one worker"
+ self.thread_pool = ThreadPool(
+ nworkers,
+ "ThreadPoolMixIn HTTP server on %s:%d"
+ % (self.server_name, self.server_port),
+ daemon,
+ **threadpool_options)
+
+ def process_request(self, request, client_address):
+ """
+ Queue the request to be processed by on of the thread pool threads
+ """
+ # This sets the socket to blocking mode (and no timeout) since it
+ # may take the thread pool a little while to get back to it. (This
+ # is the default but since we set a timeout on the parent socket so
+ # that we can trap interrupts we need to restore this,.)
+ request.setblocking(1)
+ # Queue processing of the request
+ self.thread_pool.add_task(
+ lambda: self.process_request_in_thread(request, client_address))
+
+ def handle_error(self, request, client_address):
+ exc_class, exc, tb = sys.exc_info()
+ if exc_class is ServerExit:
+ # This is actually a request to stop the server
+ raise
+ return super(ThreadPoolMixIn, self).handle_error(request, client_address)
+
+ def process_request_in_thread(self, request, client_address):
+ """
+ The worker thread should call back here to do the rest of the
+ request processing. Error handling normaller done in 'handle_request'
+ must be done here.
+ """
+ try:
+ self.finish_request(request, client_address)
+ self.close_request(request)
+ except:
+ self.handle_error(request, client_address)
+ self.close_request(request)
+ exc = sys.exc_info()[1]
+ if isinstance(exc, (MemoryError, KeyboardInterrupt)):
+ raise
+
+ def serve_forever(self):
+ """
+ Overrides `serve_forever` to shut the threadpool down cleanly.
+ """
+ try:
+ while self.running:
+ try:
+ self.handle_request()
+ except socket.timeout:
+ # Timeout is expected, gives interrupts a chance to
+ # propogate, just keep handling
+ pass
+ finally:
+ self.thread_pool.shutdown()
+
+ def server_activate(self):
+ """
+ Overrides server_activate to set timeout on our listener socket.
+ """
+ # We set the timeout here so that we can trap interrupts on windows
+ self.socket.settimeout(1)
+
+ def server_close(self):
+ """
+ Finish pending requests and shutdown the server.
+ """
+ self.running = False
+ self.socket.close()
+ self.thread_pool.shutdown(60)
+
+class WSGIServerBase(SecureHTTPServer):
+ def __init__(self, wsgi_application, server_address,
+ RequestHandlerClass=None, ssl_context=None,
+ request_queue_size=None):
+ SecureHTTPServer.__init__(self, server_address,
+ RequestHandlerClass, ssl_context,
+ request_queue_size=request_queue_size)
+ self.wsgi_application = wsgi_application
+ self.wsgi_socket_timeout = None
+
+ def get_request(self):
+ # If there is a socket_timeout, set it on the accepted
+ (conn,info) = SecureHTTPServer.get_request(self)
+ if self.wsgi_socket_timeout:
+ conn.settimeout(self.wsgi_socket_timeout)
+ return (conn, info)
+
+class WSGIServer(ThreadingMixIn, WSGIServerBase):
+ daemon_threads = False
+
+class WSGIThreadPoolServer(ThreadPoolMixIn, WSGIServerBase):
+ def __init__(self, wsgi_application, server_address,
+ RequestHandlerClass=None, ssl_context=None,
+ nworkers=10, daemon_threads=False,
+ threadpool_options=None, request_queue_size=None):
+ WSGIServerBase.__init__(self, wsgi_application, server_address,
+ RequestHandlerClass, ssl_context,
+ request_queue_size=request_queue_size)
+ if threadpool_options is None:
+ threadpool_options = {}
+ ThreadPoolMixIn.__init__(self, nworkers, daemon_threads,
+ **threadpool_options)
+
+class ServerExit(SystemExit):
+ """
+ Raised to tell the server to really exit (SystemExit is normally
+ caught)
+ """
+
+def serve(application, host=None, port=None, handler=None, ssl_pem=None,
+ ssl_context=None, server_version=None, protocol_version=None,
+ start_loop=True, daemon_threads=None, socket_timeout=None,
+ use_threadpool=None, threadpool_workers=10,
+ threadpool_options=None, request_queue_size=5):
+ """
+ Serves your ``application`` over HTTP(S) via WSGI interface
+
+ ``host``
+
+ This is the ipaddress to bind to (or a hostname if your
+ nameserver is properly configured). This defaults to
+ 127.0.0.1, which is not a public interface.
+
+ ``port``
+
+ The port to run on, defaults to 8080 for HTTP, or 4443 for
+ HTTPS. This can be a string or an integer value.
+
+ ``handler``
+
+ This is the HTTP request handler to use, it defaults to
+ ``WSGIHandler`` in this module.
+
+ ``ssl_pem``
+
+ This an optional SSL certificate file (via OpenSSL). You can
+ supply ``*`` and a development-only certificate will be
+ created for you, or you can generate a self-signed test PEM
+ certificate file as follows::
+
+ $ openssl genrsa 1024 > host.key
+ $ chmod 400 host.key
+ $ openssl req -new -x509 -nodes -sha1 -days 365 \\
+ -key host.key > host.cert
+ $ cat host.cert host.key > host.pem
+ $ chmod 400 host.pem
+
+ ``ssl_context``
+
+ This an optional SSL context object for the server. A SSL
+ context will be automatically constructed for you if you supply
+ ``ssl_pem``. Supply this to use a context of your own
+ construction.
+
+ ``server_version``
+
+ The version of the server as reported in HTTP response line. This
+ defaults to something like "PasteWSGIServer/0.5". Many servers
+ hide their code-base identity with a name like 'Amnesiac/1.0'
+
+ ``protocol_version``
+
+ This sets the protocol used by the server, by default
+ ``HTTP/1.0``. There is some support for ``HTTP/1.1``, which
+ defaults to nicer keep-alive connections. This server supports
+ ``100 Continue``, but does not yet support HTTP/1.1 Chunked
+ Encoding. Hence, if you use HTTP/1.1, you're somewhat in error
+ since chunked coding is a mandatory requirement of a HTTP/1.1
+ server. If you specify HTTP/1.1, every response *must* have a
+ ``Content-Length`` and you must be careful not to read past the
+ end of the socket.
+
+ ``start_loop``
+
+ This specifies if the server loop (aka ``server.serve_forever()``)
+ should be called; it defaults to ``True``.
+
+ ``daemon_threads``
+
+ This flag specifies if when your webserver terminates all
+ in-progress client connections should be droppped. It defaults
+ to ``False``. You might want to set this to ``True`` if you
+ are using ``HTTP/1.1`` and don't set a ``socket_timeout``.
+
+ ``socket_timeout``
+
+ This specifies the maximum amount of time that a connection to a
+ given client will be kept open. At this time, it is a rude
+ disconnect, but at a later time it might follow the RFC a bit
+ more closely.
+
+ ``use_threadpool``
+
+ Server requests from a pool of worker threads (``threadpool_workers``)
+ rather than creating a new thread for each request. This can
+ substantially reduce latency since there is a high cost associated
+ with thread creation.
+
+ ``threadpool_workers``
+
+ Number of worker threads to create when ``use_threadpool`` is true. This
+ can be a string or an integer value.
+
+ ``threadpool_options``
+
+ A dictionary of options to be used when instantiating the
+ threadpool. See paste.httpserver.ThreadPool for specific
+ options (``threadpool_workers`` is a specific option that can
+ also go here).
+
+ ``request_queue_size``
+
+ The 'backlog' argument to socket.listen(); specifies the
+ maximum number of queued connections.
+
+ """
+ is_ssl = False
+ if ssl_pem or ssl_context:
+ assert SSL, "pyOpenSSL is not installed"
+ is_ssl = True
+ port = int(port or 4443)
+ if not ssl_context:
+ if ssl_pem == '*':
+ ssl_context = _auto_ssl_context()
+ else:
+ ssl_context = SSL.Context(SSL.SSLv23_METHOD)
+ ssl_context.use_privatekey_file(ssl_pem)
+ ssl_context.use_certificate_chain_file(ssl_pem)
+
+ host = host or '127.0.0.1'
+ if port is None:
+ if ':' in host:
+ host, port = host.split(':', 1)
+ else:
+ port = 8080
+ server_address = (host, int(port))
+
+ if not handler:
+ handler = WSGIHandler
+ if server_version:
+ handler.server_version = server_version
+ handler.sys_version = None
+ if protocol_version:
+ assert protocol_version in ('HTTP/0.9', 'HTTP/1.0', 'HTTP/1.1')
+ handler.protocol_version = protocol_version
+
+ if use_threadpool is None:
+ use_threadpool = True
+
+ if converters.asbool(use_threadpool):
+ server = WSGIThreadPoolServer(application, server_address, handler,
+ ssl_context, int(threadpool_workers),
+ daemon_threads,
+ threadpool_options=threadpool_options,
+ request_queue_size=request_queue_size)
+ else:
+ server = WSGIServer(application, server_address, handler, ssl_context,
+ request_queue_size=request_queue_size)
+ if daemon_threads:
+ server.daemon_threads = daemon_threads
+
+ if socket_timeout:
+ server.wsgi_socket_timeout = int(socket_timeout)
+
+ if converters.asbool(start_loop):
+ protocol = is_ssl and 'https' or 'http'
+ host, port = server.server_address[:2]
+ if host == '0.0.0.0':
+ print 'serving on 0.0.0.0:%s view at %s://127.0.0.1:%s' % \
+ (port, protocol, port)
+ else:
+ print "serving on %s://%s:%s" % (protocol, host, port)
+ try:
+ server.serve_forever()
+ except KeyboardInterrupt:
+ # allow CTRL+C to shutdown
+ pass
+ return server
+
+# For paste.deploy server instantiation (egg:Paste#http)
+# Note: this gets a separate function because it has to expect string
+# arguments (though that's not much of an issue yet, ever?)
+def server_runner(wsgi_app, global_conf, **kwargs):
+ from paste.deploy.converters import asbool
+ for name in ['port', 'socket_timeout', 'threadpool_workers',
+ 'threadpool_hung_thread_limit',
+ 'threadpool_kill_thread_limit',
+ 'threadpool_dying_limit', 'threadpool_spawn_if_under',
+ 'threadpool_max_zombie_threads_before_die',
+ 'threadpool_hung_check_period',
+ 'threadpool_max_requests', 'request_queue_size']:
+ if name in kwargs:
+ kwargs[name] = int(kwargs[name])
+ for name in ['use_threadpool', 'daemon_threads']:
+ if name in kwargs:
+ kwargs[name] = asbool(kwargs[name])
+ threadpool_options = {}
+ for name, value in kwargs.items():
+ if name.startswith('threadpool_') and name != 'threadpool_workers':
+ threadpool_options[name[len('threadpool_'):]] = value
+ del kwargs[name]
+ if ('error_email' not in threadpool_options
+ and 'error_email' in global_conf):
+ threadpool_options['error_email'] = global_conf['error_email']
+ kwargs['threadpool_options'] = threadpool_options
+ serve(wsgi_app, **kwargs)
+
+server_runner.__doc__ = (serve.__doc__ or '') + """
+
+ You can also set these threadpool options:
+
+ ``threadpool_max_requests``:
+
+ The maximum number of requests a worker thread will process
+ before dying (and replacing itself with a new worker thread).
+ Default 100.
+
+ ``threadpool_hung_thread_limit``:
+
+ The number of seconds a thread can work on a task before it is
+ considered hung (stuck). Default 30 seconds.
+
+ ``threadpool_kill_thread_limit``:
+
+ The number of seconds a thread can work before you should kill it
+ (assuming it will never finish). Default 600 seconds (10 minutes).
+
+ ``threadpool_dying_limit``:
+
+ The length of time after killing a thread that it should actually
+ disappear. If it lives longer than this, it is considered a
+ "zombie". Note that even in easy situations killing a thread can
+ be very slow. Default 300 seconds (5 minutes).
+
+ ``threadpool_spawn_if_under``:
+
+ If there are no idle threads and a request comes in, and there are
+ less than this number of *busy* threads, then add workers to the
+ pool. Busy threads are threads that have taken less than
+ ``threadpool_hung_thread_limit`` seconds so far. So if you get
+ *lots* of requests but they complete in a reasonable amount of time,
+ the requests will simply queue up (adding more threads probably
+ wouldn't speed them up). But if you have lots of hung threads and
+ one more request comes in, this will add workers to handle it.
+ Default 5.
+
+ ``threadpool_max_zombie_threads_before_die``:
+
+ If there are more zombies than this, just kill the process. This is
+ only good if you have a monitor that will automatically restart
+ the server. This can clean up the mess. Default 0 (disabled).
+
+ `threadpool_hung_check_period``:
+
+ Every X requests, check for hung threads that need to be killed,
+ or for zombie threads that should cause a restart. Default 100
+ requests.
+
+ ``threadpool_logger``:
+
+ Logging messages will go the logger named here.
+
+ ``threadpool_error_email`` (or global ``error_email`` setting):
+
+ When threads are killed or the process restarted, this email
+ address will be contacted (using an SMTP server on localhost).
+
+"""
+
+
+if __name__ == '__main__':
+ from paste.wsgilib import dump_environ
+ #serve(dump_environ, ssl_pem="test.pem")
+ serve(dump_environ, server_version="Wombles/1.0",
+ protocol_version="HTTP/1.1", port="8888")
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/lint.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/lint.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/lint.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,436 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# Also licenced under the Apache License, 2.0: http://opensource.org/licenses/apache2.0.php
+# Licensed to PSF under a Contributor Agreement
+"""
+Middleware to check for obedience to the WSGI specification.
+
+Some of the things this checks:
+
+* Signature of the application and start_response (including that
+ keyword arguments are not used).
+
+* Environment checks:
+
+ - Environment is a dictionary (and not a subclass).
+
+ - That all the required keys are in the environment: REQUEST_METHOD,
+ SERVER_NAME, SERVER_PORT, wsgi.version, wsgi.input, wsgi.errors,
+ wsgi.multithread, wsgi.multiprocess, wsgi.run_once
+
+ - That HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH are not in the
+ environment (these headers should appear as CONTENT_LENGTH and
+ CONTENT_TYPE).
+
+ - Warns if QUERY_STRING is missing, as the cgi module acts
+ unpredictably in that case.
+
+ - That CGI-style variables (that don't contain a .) have
+ (non-unicode) string values
+
+ - That wsgi.version is a tuple
+
+ - That wsgi.url_scheme is 'http' or 'https' (@@: is this too
+ restrictive?)
+
+ - Warns if the REQUEST_METHOD is not known (@@: probably too
+ restrictive).
+
+ - That SCRIPT_NAME and PATH_INFO are empty or start with /
+
+ - That at least one of SCRIPT_NAME or PATH_INFO are set.
+
+ - That CONTENT_LENGTH is a positive integer.
+
+ - That SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
+ be '/').
+
+ - That wsgi.input has the methods read, readline, readlines, and
+ __iter__
+
+ - That wsgi.errors has the methods flush, write, writelines
+
+* The status is a string, contains a space, starts with an integer,
+ and that integer is in range (> 100).
+
+* That the headers is a list (not a subclass, not another kind of
+ sequence).
+
+* That the items of the headers are tuples of strings.
+
+* That there is no 'status' header (that is used in CGI, but not in
+ WSGI).
+
+* That the headers don't contain newlines or colons, end in _ or -, or
+ contain characters codes below 037.
+
+* That Content-Type is given if there is content (CGI often has a
+ default content type, but WSGI does not).
+
+* That no Content-Type is given when there is no content (@@: is this
+ too restrictive?)
+
+* That the exc_info argument to start_response is a tuple or None.
+
+* That all calls to the writer are with strings, and no other methods
+ on the writer are accessed.
+
+* That wsgi.input is used properly:
+
+ - .read() is called with zero or one argument
+
+ - That it returns a string
+
+ - That readline, readlines, and __iter__ return strings
+
+ - That .close() is not called
+
+ - No other methods are provided
+
+* That wsgi.errors is used properly:
+
+ - .write() and .writelines() is called with a string
+
+ - That .close() is not called, and no other methods are provided.
+
+* The response iterator:
+
+ - That it is not a string (it should be a list of a single string; a
+ string will work, but perform horribly).
+
+ - That .next() returns a string
+
+ - That the iterator is not iterated over until start_response has
+ been called (that can signal either a server or application
+ error).
+
+ - That .close() is called (doesn't raise exception, only prints to
+ sys.stderr, because we only know it isn't called when the object
+ is garbage collected).
+"""
+
+import re
+import sys
+from types import DictType, StringType, TupleType, ListType
+import warnings
+
+header_re = re.compile(r'^[a-zA-Z][a-zA-Z0-9\-_]*$')
+bad_header_value_re = re.compile(r'[\000-\037]')
+
+class WSGIWarning(Warning):
+ """
+ Raised in response to WSGI-spec-related warnings
+ """
+
+def middleware(application, global_conf=None):
+
+ """
+ When applied between a WSGI server and a WSGI application, this
+ middleware will check for WSGI compliancy on a number of levels.
+ This middleware does not modify the request or response in any
+ way, but will throw an AssertionError if anything seems off
+ (except for a failure to close the application iterator, which
+ will be printed to stderr -- there's no way to throw an exception
+ at that point).
+ """
+
+ def lint_app(*args, **kw):
+ assert len(args) == 2, "Two arguments required"
+ assert not kw, "No keyword arguments allowed"
+ environ, start_response = args
+
+ check_environ(environ)
+
+ # We use this to check if the application returns without
+ # calling start_response:
+ start_response_started = []
+
+ def start_response_wrapper(*args, **kw):
+ assert len(args) == 2 or len(args) == 3, (
+ "Invalid number of arguments: %s" % args)
+ assert not kw, "No keyword arguments allowed"
+ status = args[0]
+ headers = args[1]
+ if len(args) == 3:
+ exc_info = args[2]
+ else:
+ exc_info = None
+
+ check_status(status)
+ check_headers(headers)
+ check_content_type(status, headers)
+ check_exc_info(exc_info)
+
+ start_response_started.append(None)
+ return WriteWrapper(start_response(*args))
+
+ environ['wsgi.input'] = InputWrapper(environ['wsgi.input'])
+ environ['wsgi.errors'] = ErrorWrapper(environ['wsgi.errors'])
+
+ iterator = application(environ, start_response_wrapper)
+ assert iterator is not None and iterator != False, (
+ "The application must return an iterator, if only an empty list")
+
+ check_iterator(iterator)
+
+ return IteratorWrapper(iterator, start_response_started)
+
+ return lint_app
+
+class InputWrapper(object):
+
+ def __init__(self, wsgi_input):
+ self.input = wsgi_input
+
+ def read(self, *args):
+ assert len(args) <= 1
+ v = self.input.read(*args)
+ assert type(v) is type("")
+ return v
+
+ def readline(self, *args):
+ v = self.input.readline(*args)
+ assert type(v) is type("")
+ return v
+
+ def readlines(self, *args):
+ assert len(args) <= 1
+ lines = self.input.readlines(*args)
+ assert type(lines) is type([])
+ for line in lines:
+ assert type(line) is type("")
+ return lines
+
+ def __iter__(self):
+ while 1:
+ line = self.readline()
+ if not line:
+ return
+ yield line
+
+ def close(self):
+ assert 0, "input.close() must not be called"
+
+class ErrorWrapper(object):
+
+ def __init__(self, wsgi_errors):
+ self.errors = wsgi_errors
+
+ def write(self, s):
+ assert type(s) is type("")
+ self.errors.write(s)
+
+ def flush(self):
+ self.errors.flush()
+
+ def writelines(self, seq):
+ for line in seq:
+ self.write(line)
+
+ def close(self):
+ assert 0, "errors.close() must not be called"
+
+class WriteWrapper(object):
+
+ def __init__(self, wsgi_writer):
+ self.writer = wsgi_writer
+
+ def __call__(self, s):
+ assert type(s) is type("")
+ self.writer(s)
+
+class PartialIteratorWrapper(object):
+
+ def __init__(self, wsgi_iterator):
+ self.iterator = wsgi_iterator
+
+ def __iter__(self):
+ # We want to make sure __iter__ is called
+ return IteratorWrapper(self.iterator)
+
+class IteratorWrapper(object):
+
+ def __init__(self, wsgi_iterator, check_start_response):
+ self.original_iterator = wsgi_iterator
+ self.iterator = iter(wsgi_iterator)
+ self.closed = False
+ self.check_start_response = check_start_response
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ assert not self.closed, (
+ "Iterator read after closed")
+ v = self.iterator.next()
+ if self.check_start_response is not None:
+ assert self.check_start_response, (
+ "The application returns and we started iterating over its body, but start_response has not yet been called")
+ self.check_start_response = None
+ return v
+
+ def close(self):
+ self.closed = True
+ if hasattr(self.original_iterator, 'close'):
+ self.original_iterator.close()
+
+ def __del__(self):
+ if not self.closed:
+ sys.stderr.write(
+ "Iterator garbage collected without being closed")
+ assert self.closed, (
+ "Iterator garbage collected without being closed")
+
+def check_environ(environ):
+ assert type(environ) is DictType, (
+ "Environment is not of the right type: %r (environment: %r)"
+ % (type(environ), environ))
+
+ for key in ['REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT',
+ 'wsgi.version', 'wsgi.input', 'wsgi.errors',
+ 'wsgi.multithread', 'wsgi.multiprocess',
+ 'wsgi.run_once']:
+ assert key in environ, (
+ "Environment missing required key: %r" % key)
+
+ for key in ['HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH']:
+ assert key not in environ, (
+ "Environment should not have the key: %s "
+ "(use %s instead)" % (key, key[5:]))
+
+ if 'QUERY_STRING' not in environ:
+ warnings.warn(
+ 'QUERY_STRING is not in the WSGI environment; the cgi '
+ 'module will use sys.argv when this variable is missing, '
+ 'so application errors are more likely',
+ WSGIWarning)
+
+ for key in environ.keys():
+ if '.' in key:
+ # Extension, we don't care about its type
+ continue
+ assert type(environ[key]) is StringType, (
+ "Environmental variable %s is not a string: %r (value: %r)"
+ % (key, type(environ[key]), environ[key]))
+
+ assert type(environ['wsgi.version']) is TupleType, (
+ "wsgi.version should be a tuple (%r)" % environ['wsgi.version'])
+ assert environ['wsgi.url_scheme'] in ('http', 'https'), (
+ "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme'])
+
+ check_input(environ['wsgi.input'])
+ check_errors(environ['wsgi.errors'])
+
+ # @@: these need filling out:
+ if environ['REQUEST_METHOD'] not in (
+ 'GET', 'HEAD', 'POST', 'OPTIONS','PUT','DELETE','TRACE'):
+ warnings.warn(
+ "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD'],
+ WSGIWarning)
+
+ assert (not environ.get('SCRIPT_NAME')
+ or environ['SCRIPT_NAME'].startswith('/')), (
+ "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME'])
+ assert (not environ.get('PATH_INFO')
+ or environ['PATH_INFO'].startswith('/')), (
+ "PATH_INFO doesn't start with /: %r" % environ['PATH_INFO'])
+ if environ.get('CONTENT_LENGTH'):
+ assert int(environ['CONTENT_LENGTH']) >= 0, (
+ "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH'])
+
+ if not environ.get('SCRIPT_NAME'):
+ assert environ.has_key('PATH_INFO'), (
+ "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO "
+ "should at least be '/' if SCRIPT_NAME is empty)")
+ assert environ.get('SCRIPT_NAME') != '/', (
+ "SCRIPT_NAME cannot be '/'; it should instead be '', and "
+ "PATH_INFO should be '/'")
+
+def check_input(wsgi_input):
+ for attr in ['read', 'readline', 'readlines', '__iter__']:
+ assert hasattr(wsgi_input, attr), (
+ "wsgi.input (%r) doesn't have the attribute %s"
+ % (wsgi_input, attr))
+
+def check_errors(wsgi_errors):
+ for attr in ['flush', 'write', 'writelines']:
+ assert hasattr(wsgi_errors, attr), (
+ "wsgi.errors (%r) doesn't have the attribute %s"
+ % (wsgi_errors, attr))
+
+def check_status(status):
+ assert type(status) is StringType, (
+ "Status must be a string (not %r)" % status)
+ # Implicitly check that we can turn it into an integer:
+ status_code = status.split(None, 1)[0]
+ assert len(status_code) == 3, (
+ "Status codes must be three characters: %r" % status_code)
+ status_int = int(status_code)
+ assert status_int >= 100, "Status code is invalid: %r" % status_int
+ if len(status) < 4 or status[3] != ' ':
+ warnings.warn(
+ "The status string (%r) should be a three-digit integer "
+ "followed by a single space and a status explanation"
+ % status, WSGIWarning)
+
+def check_headers(headers):
+ assert type(headers) is ListType, (
+ "Headers (%r) must be of type list: %r"
+ % (headers, type(headers)))
+ header_names = {}
+ for item in headers:
+ assert type(item) is TupleType, (
+ "Individual headers (%r) must be of type tuple: %r"
+ % (item, type(item)))
+ assert len(item) == 2
+ name, value = item
+ assert name.lower() != 'status', (
+ "The Status header cannot be used; it conflicts with CGI "
+ "script, and HTTP status is not given through headers "
+ "(value: %r)." % value)
+ header_names[name.lower()] = None
+ assert '\n' not in name and ':' not in name, (
+ "Header names may not contain ':' or '\\n': %r" % name)
+ assert header_re.search(name), "Bad header name: %r" % name
+ assert not name.endswith('-') and not name.endswith('_'), (
+ "Names may not end in '-' or '_': %r" % name)
+ assert not bad_header_value_re.search(value), (
+ "Bad header value: %r (bad char: %r)"
+ % (value, bad_header_value_re.search(value).group(0)))
+
+def check_content_type(status, headers):
+ code = int(status.split(None, 1)[0])
+ # @@: need one more person to verify this interpretation of RFC 2616
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+ NO_MESSAGE_BODY = (204, 304)
+ NO_MESSAGE_TYPE = (204, 304)
+ for name, value in headers:
+ if name.lower() == 'content-type':
+ if code not in NO_MESSAGE_TYPE:
+ return
+ assert 0, (("Content-Type header found in a %s response, "
+ "which must not return content.") % code)
+ if code not in NO_MESSAGE_BODY:
+ assert 0, "No Content-Type header found in headers (%s)" % headers
+
+def check_exc_info(exc_info):
+ assert exc_info is None or type(exc_info) is type(()), (
+ "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info)))
+ # More exc_info checks?
+
+def check_iterator(iterator):
+ # Technically a string is legal, which is why it's a really bad
+ # idea, because it may cause the response to be returned
+ # character-by-character
+ assert not isinstance(iterator, str), (
+ "You should not return a string as your application iterator, "
+ "instead return a single-item list containing that string.")
+
+def make_middleware(application, global_conf):
+ # @@: global_conf should be taken out of the middleware function,
+ # and isolated here
+ return middleware(application)
+
+make_middleware.__doc__ = __doc__
+
+__all__ = ['middleware', 'make_middleware']
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/modpython.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/modpython.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/modpython.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,252 @@
+"""WSGI Paste wrapper for mod_python. Requires Python 2.2 or greater.
+
+
+Example httpd.conf section for a Paste app with an ini file::
+
+ <Location />
+ SetHandler python-program
+ PythonHandler paste.modpython
+ PythonOption paste.ini /some/location/your/pasteconfig.ini
+ </Location>
+
+Or if you want to load a WSGI application under /your/homedir in the module
+``startup`` and the WSGI app is ``app``::
+
+ <Location />
+ SetHandler python-program
+ PythonHandler paste.modpython
+ PythonPath "['/virtual/project/directory'] + sys.path"
+ PythonOption wsgi.application startup::app
+ </Location>
+
+
+If you'd like to use a virtual installation, make sure to add it in the path
+like so::
+
+ <Location />
+ SetHandler python-program
+ PythonHandler paste.modpython
+ PythonPath "['/virtual/project/directory', '/virtual/lib/python2.4/'] + sys.path"
+ PythonOption paste.ini /virtual/project/directory/pasteconfig.ini
+ </Location>
+
+Some WSGI implementations assume that the SCRIPT_NAME environ variable will
+always be equal to "the root URL of the app"; Apache probably won't act as
+you expect in that case. You can add another PythonOption directive to tell
+modpython_gateway to force that behavior:
+
+ PythonOption SCRIPT_NAME /mcontrol
+
+Some WSGI applications need to be cleaned up when Apache exits. You can
+register a cleanup handler with yet another PythonOption directive:
+
+ PythonOption wsgi.cleanup module::function
+
+The module.function will be called with no arguments on server shutdown,
+once for each child process or thread.
+
+This module highly based on Robert Brewer's, here:
+http://projects.amor.org/misc/svn/modpython_gateway.py
+"""
+
+import traceback
+
+try:
+ from mod_python import apache
+except:
+ pass
+from paste.deploy import loadapp
+
+class InputWrapper(object):
+
+ def __init__(self, req):
+ self.req = req
+
+ def close(self):
+ pass
+
+ def read(self, size=-1):
+ return self.req.read(size)
+
+ def readline(self, size=-1):
+ return self.req.readline(size)
+
+ def readlines(self, hint=-1):
+ return self.req.readlines(hint)
+
+ def __iter__(self):
+ line = self.readline()
+ while line:
+ yield line
+ # Notice this won't prefetch the next line; it only
+ # gets called if the generator is resumed.
+ line = self.readline()
+
+
+class ErrorWrapper(object):
+
+ def __init__(self, req):
+ self.req = req
+
+ def flush(self):
+ pass
+
+ def write(self, msg):
+ self.req.log_error(msg)
+
+ def writelines(self, seq):
+ self.write(''.join(seq))
+
+
+bad_value = ("You must provide a PythonOption '%s', either 'on' or 'off', "
+ "when running a version of mod_python < 3.1")
+
+
+class Handler(object):
+
+ def __init__(self, req):
+ self.started = False
+
+ options = req.get_options()
+
+ # Threading and forking
+ try:
+ q = apache.mpm_query
+ threaded = q(apache.AP_MPMQ_IS_THREADED)
+ forked = q(apache.AP_MPMQ_IS_FORKED)
+ except AttributeError:
+ threaded = options.get('multithread', '').lower()
+ if threaded == 'on':
+ threaded = True
+ elif threaded == 'off':
+ threaded = False
+ else:
+ raise ValueError(bad_value % "multithread")
+
+ forked = options.get('multiprocess', '').lower()
+ if forked == 'on':
+ forked = True
+ elif forked == 'off':
+ forked = False
+ else:
+ raise ValueError(bad_value % "multiprocess")
+
+ env = self.environ = dict(apache.build_cgi_env(req))
+
+ if 'SCRIPT_NAME' in options:
+ # Override SCRIPT_NAME and PATH_INFO if requested.
+ env['SCRIPT_NAME'] = options['SCRIPT_NAME']
+ env['PATH_INFO'] = req.uri[len(options['SCRIPT_NAME']):]
+ else:
+ env['SCRIPT_NAME'] = ''
+ env['PATH_INFO'] = req.uri
+
+ env['wsgi.input'] = InputWrapper(req)
+ env['wsgi.errors'] = ErrorWrapper(req)
+ env['wsgi.version'] = (1, 0)
+ env['wsgi.run_once'] = False
+ if env.get("HTTPS") in ('yes', 'on', '1'):
+ env['wsgi.url_scheme'] = 'https'
+ else:
+ env['wsgi.url_scheme'] = 'http'
+ env['wsgi.multithread'] = threaded
+ env['wsgi.multiprocess'] = forked
+
+ self.request = req
+
+ def run(self, application):
+ try:
+ result = application(self.environ, self.start_response)
+ for data in result:
+ self.write(data)
+ if not self.started:
+ self.request.set_content_length(0)
+ if hasattr(result, 'close'):
+ result.close()
+ except:
+ traceback.print_exc(None, self.environ['wsgi.errors'])
+ if not self.started:
+ self.request.status = 500
+ self.request.content_type = 'text/plain'
+ data = "A server error occurred. Please contact the administrator."
+ self.request.set_content_length(len(data))
+ self.request.write(data)
+
+ def start_response(self, status, headers, exc_info=None):
+ if exc_info:
+ try:
+ if self.started:
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ exc_info = None
+
+ self.request.status = int(status[:3])
+
+ for key, val in headers:
+ if key.lower() == 'content-length':
+ self.request.set_content_length(int(val))
+ elif key.lower() == 'content-type':
+ self.request.content_type = val
+ else:
+ self.request.headers_out.add(key, val)
+
+ return self.write
+
+ def write(self, data):
+ if not self.started:
+ self.started = True
+ self.request.write(data)
+
+
+startup = None
+cleanup = None
+wsgiapps = {}
+
+def handler(req):
+ options = req.get_options()
+ # Run a startup function if requested.
+ global startup
+ if 'wsgi.startup' in options and not startup:
+ func = options['wsgi.startup']
+ if func:
+ module_name, object_str = func.split('::', 1)
+ module = __import__(module_name, globals(), locals(), [''])
+ startup = apache.resolve_object(module, object_str)
+ startup(req)
+
+ # Register a cleanup function if requested.
+ global cleanup
+ if 'wsgi.cleanup' in options and not cleanup:
+ func = options['wsgi.cleanup']
+ if func:
+ module_name, object_str = func.split('::', 1)
+ module = __import__(module_name, globals(), locals(), [''])
+ cleanup = apache.resolve_object(module, object_str)
+ def cleaner(data):
+ cleanup()
+ try:
+ # apache.register_cleanup wasn't available until 3.1.4.
+ apache.register_cleanup(cleaner)
+ except AttributeError:
+ req.server.register_cleanup(req, cleaner)
+
+ # Import the wsgi 'application' callable and pass it to Handler.run
+ global wsgiapps
+ appini = options.get('paste.ini')
+ app = None
+ if appini:
+ if appini not in wsgiapps:
+ wsgiapps[appini] = loadapp("config:%s" % appini)
+ app = wsgiapps[appini]
+
+ # Import the wsgi 'application' callable and pass it to Handler.run
+ appwsgi = options.get('wsgi.application')
+ if appwsgi and not appini:
+ modname, objname = appwsgi.split('::', 1)
+ module = __import__(modname, globals(), locals(), [''])
+ app = getattr(module, objname)
+
+ Handler(req).run(app)
+
+ # status was set in Handler; always return apache.OK
+ return apache.OK
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/pony.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/pony.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/pony.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,57 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+We have a pony and/or a unicorn.
+"""
+from paste.request import construct_url
+
+PONY = """
+eJyFkkFuxCAMRfdzCisbJxK2D5D2JpbMrlI3XXQZDt9PCG0ySgcWIMT79rcN0XClUJlZRB9jVmci
+FmV19khjgRFl0RzrKmqzvY8lRUWFlXvCrD7UbAQR/17NUvGhypAF9og16vWtkC8DzUayS6pN3/dR
+ki0OnpzKjUBFpmlC7zVFRNL1rwoq6PWXXQSnIm9WoTzlM2//ke21o5g/l1ckRhiPbkDZXsKIR7l1
+36hF9uMhnRiVjI8UgYjlsIKCrXXpcA9iX5y7zMmtG0fUpW61Ssttipf6cp3WARfkMVoYFryi2a+w
+o/2dhW0OXfcMTnmh53oR9egzPs+qkpY9IKxdUVRP5wHO7UDAuI6moA2N+/z4vtc2k8B+AIBimVU=
+"""
+
+UNICORN = """
+eJyVVD1vhDAM3e9XeAtIxB5P6qlDx0OMXVBzSpZOHdsxP762E0JAnMgZ8Zn37OePAPC60eV1Dl5b
+SS7fB6DmQNGhtegpNlPIQS8HmkYGdSqNqDF9wcMYus4TuBYGsZwIPqXfEoNir5K+R3mbzhlR4JMW
+eGpikPpn9wHl2sDgEH1270guZwzKDRf3nTztMvfI5r3fJqEmNxdCyISBcWjNgjPG8Egg2hgT3mJi
+KBwNvmPB1hbWJ3TwBfMlqdTzxNyDE2H8zOD5HA4KkqJGPVY/TwnxmPA82kdSJNj7zs+R0d1pB+JO
+xn2DKgsdxAfFS2pfTSD0Fb6Uzv7dCQSvE5JmZQEQ90vNjBU1GPuGQpCPS8cGo+dQgjIKqxnJTXbw
+ucFzPFVIJXtzk6BXKGPnYsKzvFmGx7A0j6Zqvlvk5rETXbMWTGWj0RFc8QNPYVfhJfMMniCPazWJ
+lGtPZecIGJWW6oL2hpbWRZEkChe8eg5Wb7xx/MBZBFjxeZPEss+mRQ3Uhc8WQv684seSRO7i3nb4
+7HlKUg8sraz47LmXyh8S0somADvoUpoHjGWl+rUkF0H+EIf/gbyyMg58BBk6L634/fkHUCodMw==
+"""
+
+
+class PonyMiddleware(object):
+
+ def __init__(self, application):
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ path_info = environ.get('PATH_INFO', '')
+ if path_info == '/pony':
+ url = construct_url(environ, with_query_string=False)
+ if 'horn' in environ.get('QUERY_STRING', ''):
+ data = UNICORN
+ link = 'remove horn!'
+ else:
+ data = PONY
+ url += '?horn'
+ link = 'add horn!'
+ msg = data.decode('base64').decode('zlib')
+ msg = '<pre>%s\n<a href="%s">%s</a></pre>' % (
+ msg, url, link)
+ start_response('200 OK', [('content-type', 'text/html')])
+ return [msg]
+ else:
+ return self.application(environ, start_response)
+
+def make_pony(app, global_conf):
+ """
+ Adds pony power to any application, at /pony
+ """
+ return PonyMiddleware(app)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/progress.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/progress.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/progress.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,222 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Upload Progress Monitor
+
+This is a WSGI middleware component which monitors the status of files
+being uploaded. It includes a small query application which will return
+a list of all files being uploaded by particular session/user.
+
+>>> from paste.httpserver import serve
+>>> from paste.urlmap import URLMap
+>>> from paste.auth.basic import AuthBasicHandler
+>>> from paste.debug.debugapp import SlowConsumer, SimpleApplication
+>>> # from paste.progress import *
+>>> realm = 'Test Realm'
+>>> def authfunc(username, password):
+... return username == password
+>>> map = URLMap({})
+>>> ups = UploadProgressMonitor(map, threshold=1024)
+>>> map['/upload'] = SlowConsumer()
+>>> map['/simple'] = SimpleApplication()
+>>> map['/report'] = UploadProgressReporter(ups)
+>>> serve(AuthBasicHandler(ups, realm, authfunc))
+serving on...
+
+.. note::
+
+ This is experimental, and will change in the future.
+"""
+import time
+from paste.wsgilib import catch_errors
+
+DEFAULT_THRESHOLD = 1024 * 1024 # one megabyte
+DEFAULT_TIMEOUT = 60*5 # five minutes
+ENVIRON_RECEIVED = 'paste.bytes_received'
+REQUEST_STARTED = 'paste.request_started'
+REQUEST_FINISHED = 'paste.request_finished'
+
+class _ProgressFile(object):
+ """
+ This is the input-file wrapper used to record the number of
+ ``paste.bytes_received`` for the given request.
+ """
+
+ def __init__(self, environ, rfile):
+ self._ProgressFile_environ = environ
+ self._ProgressFile_rfile = rfile
+ self.flush = rfile.flush
+ self.write = rfile.write
+ self.writelines = rfile.writelines
+
+ def __iter__(self):
+ environ = self._ProgressFile_environ
+ riter = iter(self._ProgressFile_rfile)
+ def iterwrap():
+ for chunk in riter:
+ environ[ENVIRON_RECEIVED] += len(chunk)
+ yield chunk
+ return iter(iterwrap)
+
+ def read(self, size=-1):
+ chunk = self._ProgressFile_rfile.read(size)
+ self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
+ return chunk
+
+ def readline(self):
+ chunk = self._ProgressFile_rfile.readline()
+ self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
+ return chunk
+
+ def readlines(self, hint=None):
+ chunk = self._ProgressFile_rfile.readlines(hint)
+ self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
+ return chunk
+
+class UploadProgressMonitor(object):
+ """
+ monitors and reports on the status of uploads in progress
+
+ Parameters:
+
+ ``application``
+
+ This is the next application in the WSGI stack.
+
+ ``threshold``
+
+ This is the size in bytes that is needed for the
+ upload to be included in the monitor.
+
+ ``timeout``
+
+ This is the amount of time (in seconds) that a upload
+ remains in the monitor after it has finished.
+
+ Methods:
+
+ ``uploads()``
+
+ This returns a list of ``environ`` dict objects for each
+ upload being currently monitored, or finished but whose time
+ has not yet expired.
+
+ For each request ``environ`` that is monitored, there are several
+ variables that are stored:
+
+ ``paste.bytes_received``
+
+ This is the total number of bytes received for the given
+ request; it can be compared with ``CONTENT_LENGTH`` to
+ build a percentage complete. This is an integer value.
+
+ ``paste.request_started``
+
+ This is the time (in seconds) when the request was started
+ as obtained from ``time.time()``. One would want to format
+ this for presentation to the user, if necessary.
+
+ ``paste.request_finished``
+
+ This is the time (in seconds) when the request was finished,
+ canceled, or otherwise disconnected. This is None while
+ the given upload is still in-progress.
+
+ TODO: turn monitor into a queue and purge queue of finished
+ requests that have passed the timeout period.
+ """
+ def __init__(self, application, threshold=None, timeout=None):
+ self.application = application
+ self.threshold = threshold or DEFAULT_THRESHOLD
+ self.timeout = timeout or DEFAULT_TIMEOUT
+ self.monitor = []
+
+ def __call__(self, environ, start_response):
+ length = environ.get('CONTENT_LENGTH', 0)
+ if length and int(length) > self.threshold:
+ # replace input file object
+ self.monitor.append(environ)
+ environ[ENVIRON_RECEIVED] = 0
+ environ[REQUEST_STARTED] = time.time()
+ environ[REQUEST_FINISHED] = None
+ environ['wsgi.input'] = \
+ _ProgressFile(environ, environ['wsgi.input'])
+ def finalizer(exc_info=None):
+ environ[REQUEST_FINISHED] = time.time()
+ return catch_errors(self.application, environ,
+ start_response, finalizer, finalizer)
+ return self.application(environ, start_response)
+
+ def uploads(self):
+ return self.monitor
+
+class UploadProgressReporter(object):
+ """
+ reports on the progress of uploads for a given user
+
+ This reporter returns a JSON file (for use in AJAX) listing the
+ uploads in progress for the given user. By default, this reporter
+ uses the ``REMOTE_USER`` environment to compare between the current
+ request and uploads in-progress. If they match, then a response
+ record is formed.
+
+ ``match()``
+
+ This member function can be overriden to provide alternative
+ matching criteria. It takes two environments, the first
+ is the current request, the second is a current upload.
+
+ ``report()``
+
+ This member function takes an environment and builds a
+ ``dict`` that will be used to create a JSON mapping for
+ the given upload. By default, this just includes the
+ percent complete and the request url.
+
+ """
+ def __init__(self, monitor):
+ self.monitor = monitor
+
+ def match(self, search_environ, upload_environ):
+ if search_environ.get('REMOTE_USER', None) == \
+ upload_environ.get('REMOTE_USER', 0):
+ return True
+ return False
+
+ def report(self, environ):
+ retval = { 'started': time.strftime("%Y-%m-%d %H:%M:%S",
+ time.gmtime(environ[REQUEST_STARTED])),
+ 'finished': '',
+ 'content_length': environ.get('CONTENT_LENGTH'),
+ 'bytes_received': environ[ENVIRON_RECEIVED],
+ 'path_info': environ.get('PATH_INFO',''),
+ 'query_string': environ.get('QUERY_STRING','')}
+ finished = environ[REQUEST_FINISHED]
+ if finished:
+ retval['finished'] = time.strftime("%Y:%m:%d %H:%M:%S",
+ time.gmtime(finished))
+ return retval
+
+ def __call__(self, environ, start_response):
+ body = []
+ for map in [self.report(env) for env in self.monitor.uploads()
+ if self.match(environ, env)]:
+ parts = []
+ for k, v in map.items():
+ v = str(v).replace("\\", "\\\\").replace('"', '\\"')
+ parts.append('%s: "%s"' % (k, v))
+ body.append("{ %s }" % ", ".join(parts))
+ body = "[ %s ]" % ", ".join(body)
+ start_response("200 OK", [('Content-Type', 'text/plain'),
+ ('Content-Length', len(body))])
+ return [body]
+
+__all__ = ['UploadProgressMonitor', 'UploadProgressReporter']
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/proxy.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/proxy.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/proxy.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,283 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+An application that proxies WSGI requests to a remote server.
+
+TODO:
+
+* Send ``Via`` header? It's not clear to me this is a Via in the
+ style of a typical proxy.
+
+* Other headers or metadata? I put in X-Forwarded-For, but that's it.
+
+* Signed data of non-HTTP keys? This would be for things like
+ REMOTE_USER.
+
+* Something to indicate what the original URL was? The original host,
+ scheme, and base path.
+
+* Rewriting ``Location`` headers? mod_proxy does this.
+
+* Rewriting body? (Probably not on this one -- that can be done with
+ a different middleware that wraps this middleware)
+
+* Example::
+
+ use = egg:Paste#proxy
+ address = http://server3:8680/exist/rest/db/orgs/sch/config/
+ allowed_request_methods = GET
+
+"""
+
+import httplib
+import urlparse
+import urllib
+
+from paste import httpexceptions
+from paste.util.converters import aslist
+
+# Remove these headers from response (specify lower case header
+# names):
+filtered_headers = (
+ 'transfer-encoding',
+ 'connection',
+ 'keep-alive',
+ 'proxy-authenticate',
+ 'proxy-authorization',
+ 'te',
+ 'trailers',
+ 'upgrade',
+)
+
+class Proxy(object):
+
+ def __init__(self, address, allowed_request_methods=(),
+ suppress_http_headers=()):
+ self.address = address
+ self.parsed = urlparse.urlsplit(address)
+ self.scheme = self.parsed[0].lower()
+ self.host = self.parsed[1]
+ self.path = self.parsed[2]
+ self.allowed_request_methods = [
+ x.lower() for x in allowed_request_methods if x]
+
+ self.suppress_http_headers = [
+ x.lower() for x in suppress_http_headers if x]
+
+ def __call__(self, environ, start_response):
+ if (self.allowed_request_methods and
+ environ['REQUEST_METHOD'].lower() not in self.allowed_request_methods):
+ return httpexceptions.HTTPBadRequest("Disallowed")(environ, start_response)
+
+ if self.scheme == 'http':
+ ConnClass = httplib.HTTPConnection
+ elif self.scheme == 'https':
+ ConnClass = httplib.HTTPSConnection
+ else:
+ raise ValueError(
+ "Unknown scheme for %r: %r" % (self.address, self.scheme))
+ conn = ConnClass(self.host)
+ headers = {}
+ for key, value in environ.items():
+ if key.startswith('HTTP_'):
+ key = key[5:].lower().replace('_', '-')
+ if key == 'host' or key in self.suppress_http_headers:
+ continue
+ headers[key] = value
+ headers['host'] = self.host
+ if 'REMOTE_ADDR' in environ:
+ headers['x-forwarded-for'] = environ['REMOTE_ADDR']
+ if environ.get('CONTENT_TYPE'):
+ headers['content-type'] = environ['CONTENT_TYPE']
+ if environ.get('CONTENT_LENGTH'):
+ if environ['CONTENT_LENGTH'] == '-1':
+ # This is a special case, where the content length is basically undetermined
+ body = environ['wsgi.input'].read(-1)
+ headers['content-length'] = str(len(body))
+ else:
+ headers['content-length'] = environ['CONTENT_LENGTH']
+ length = int(environ['CONTENT_LENGTH'])
+ body = environ['wsgi.input'].read(length)
+ else:
+ body = ''
+
+ path_info = urllib.quote(environ['PATH_INFO'])
+ if self.path:
+ request_path = path_info
+ if request_path and request_path[0] == '/':
+ request_path = request_path[1:]
+
+ path = urlparse.urljoin(self.path, request_path)
+ else:
+ path = path_info
+ if environ.get('QUERY_STRING'):
+ path += '?' + environ['QUERY_STRING']
+
+ conn.request(environ['REQUEST_METHOD'],
+ path,
+ body, headers)
+ res = conn.getresponse()
+ headers_out = parse_headers(res.msg)
+
+ status = '%s %s' % (res.status, res.reason)
+ start_response(status, headers_out)
+ # @@: Default?
+ length = res.getheader('content-length')
+ if length is not None:
+ body = res.read(int(length))
+ else:
+ body = res.read()
+ conn.close()
+ return [body]
+
+def make_proxy(global_conf, address, allowed_request_methods="",
+ suppress_http_headers=""):
+ """
+ Make a WSGI application that proxies to another address:
+
+ ``address``
+ the full URL ending with a trailing ``/``
+
+ ``allowed_request_methods``:
+ a space seperated list of request methods (e.g., ``GET POST``)
+
+ ``suppress_http_headers``
+ a space seperated list of http headers (lower case, without
+ the leading ``http_``) that should not be passed on to target
+ host
+ """
+ allowed_request_methods = aslist(allowed_request_methods)
+ suppress_http_headers = aslist(suppress_http_headers)
+ return Proxy(
+ address,
+ allowed_request_methods=allowed_request_methods,
+ suppress_http_headers=suppress_http_headers)
+
+
+class TransparentProxy(object):
+
+ """
+ A proxy that sends the request just as it was given, including
+ respecting HTTP_HOST, wsgi.url_scheme, etc.
+
+ This is a way of translating WSGI requests directly to real HTTP
+ requests. All information goes in the environment; modify it to
+ modify the way the request is made.
+
+ If you specify ``force_host`` (and optionally ``force_scheme``)
+ then HTTP_HOST won't be used to determine where to connect to;
+ instead a specific host will be connected to, but the ``Host``
+ header in the request will remain intact.
+ """
+
+ def __init__(self, force_host=None,
+ force_scheme='http'):
+ self.force_host = force_host
+ self.force_scheme = force_scheme
+
+ def __repr__(self):
+ return '<%s %s force_host=%r force_scheme=%r>' % (
+ self.__class__.__name__,
+ hex(id(self)),
+ self.force_host, self.force_scheme)
+
+ def __call__(self, environ, start_response):
+ scheme = environ['wsgi.url_scheme']
+ if self.force_host is None:
+ conn_scheme = scheme
+ else:
+ conn_scheme = self.force_scheme
+ if conn_scheme == 'http':
+ ConnClass = httplib.HTTPConnection
+ elif conn_scheme == 'https':
+ ConnClass = httplib.HTTPSConnection
+ else:
+ raise ValueError(
+ "Unknown scheme %r" % scheme)
+ if 'HTTP_HOST' not in environ:
+ raise ValueError(
+ "WSGI environ must contain an HTTP_HOST key")
+ host = environ['HTTP_HOST']
+ if self.force_host is None:
+ conn_host = host
+ else:
+ conn_host = self.force_host
+ conn = ConnClass(conn_host)
+ headers = {}
+ for key, value in environ.items():
+ if key.startswith('HTTP_'):
+ key = key[5:].lower().replace('_', '-')
+ headers[key] = value
+ headers['host'] = host
+ if 'REMOTE_ADDR' in environ and 'HTTP_X_FORWARDED_FOR' not in environ:
+ headers['x-forwarded-for'] = environ['REMOTE_ADDR']
+ if environ.get('CONTENT_TYPE'):
+ headers['content-type'] = environ['CONTENT_TYPE']
+ if environ.get('CONTENT_LENGTH'):
+ length = int(environ['CONTENT_LENGTH'])
+ body = environ['wsgi.input'].read(length)
+ if length == -1:
+ environ['CONTENT_LENGTH'] = str(len(body))
+ elif 'CONTENT_LENGTH' not in environ:
+ body = ''
+ length = 0
+ else:
+ body = ''
+ length = 0
+
+ path = (environ.get('SCRIPT_NAME', '')
+ + environ.get('PATH_INFO', ''))
+ path = urllib.quote(path)
+ if 'QUERY_STRING' in environ:
+ path += '?' + environ['QUERY_STRING']
+ conn.request(environ['REQUEST_METHOD'],
+ path, body, headers)
+ res = conn.getresponse()
+ headers_out = parse_headers(res.msg)
+
+ status = '%s %s' % (res.status, res.reason)
+ start_response(status, headers_out)
+ # @@: Default?
+ length = res.getheader('content-length')
+ if length is not None:
+ body = res.read(int(length))
+ else:
+ body = res.read()
+ conn.close()
+ return [body]
+
+def parse_headers(message):
+ """
+ Turn a Message object into a list of WSGI-style headers.
+ """
+ headers_out = []
+ for full_header in message.headers:
+ if not full_header:
+ # Shouldn't happen, but we'll just ignore
+ continue
+ if full_header[0].isspace():
+ # Continuation line, add to the last header
+ if not headers_out:
+ raise ValueError(
+ "First header starts with a space (%r)" % full_header)
+ last_header, last_value = headers_out.pop()
+ value = last_value + ' ' + full_header.strip()
+ headers_out.append((last_header, value))
+ continue
+ try:
+ header, value = full_header.split(':', 1)
+ except:
+ raise ValueError("Invalid header: %r" % full_header)
+ value = value.strip()
+ if header.lower() not in filtered_headers:
+ headers_out.append((header, value))
+ return headers_out
+
+def make_transparent_proxy(
+ global_conf, force_host=None, force_scheme='http'):
+ """
+ Create a proxy that connects to a specific host, but does
+ absolutely no other filtering, including the Host header.
+ """
+ return TransparentProxy(force_host=force_host,
+ force_scheme=force_scheme)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/recursive.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/recursive.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/recursive.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,405 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware to make internal requests and forward requests internally.
+
+When applied, several keys are added to the environment that will allow
+you to trigger recursive redirects and forwards.
+
+ paste.recursive.include:
+ When you call
+ ``environ['paste.recursive.include'](new_path_info)`` a response
+ will be returned. The response has a ``body`` attribute, a
+ ``status`` attribute, and a ``headers`` attribute.
+
+ paste.recursive.script_name:
+ The ``SCRIPT_NAME`` at the point that recursive lives. Only
+ paths underneath this path can be redirected to.
+
+ paste.recursive.old_path_info:
+ A list of previous ``PATH_INFO`` values from previous redirects.
+
+Raise ``ForwardRequestException(new_path_info)`` to do a forward
+(aborting the current request).
+"""
+
+from cStringIO import StringIO
+import warnings
+
+__all__ = ['RecursiveMiddleware']
+__pudge_all__ = ['RecursiveMiddleware', 'ForwardRequestException']
+
+class RecursionLoop(AssertionError):
+ # Subclasses AssertionError for legacy reasons
+ """Raised when a recursion enters into a loop"""
+
+class CheckForRecursionMiddleware(object):
+ def __init__(self, app, env):
+ self.app = app
+ self.env = env
+
+ def __call__(self, environ, start_response):
+ path_info = environ.get('PATH_INFO','')
+ if path_info in self.env.get(
+ 'paste.recursive.old_path_info', []):
+ raise RecursionLoop(
+ "Forwarding loop detected; %r visited twice (internal "
+ "redirect path: %s)"
+ % (path_info, self.env['paste.recursive.old_path_info']))
+ old_path_info = self.env.setdefault('paste.recursive.old_path_info', [])
+ old_path_info.append(self.env.get('PATH_INFO', ''))
+ return self.app(environ, start_response)
+
+class RecursiveMiddleware(object):
+
+ """
+ A WSGI middleware that allows for recursive and forwarded calls.
+ All these calls go to the same 'application', but presumably that
+ application acts differently with different URLs. The forwarded
+ URLs must be relative to this container.
+
+ Interface is entirely through the ``paste.recursive.forward`` and
+ ``paste.recursive.include`` environmental keys.
+ """
+
+ def __init__(self, application, global_conf=None):
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ environ['paste.recursive.forward'] = Forwarder(
+ self.application,
+ environ,
+ start_response)
+ environ['paste.recursive.include'] = Includer(
+ self.application,
+ environ,
+ start_response)
+ environ['paste.recursive.include_app_iter'] = IncluderAppIter(
+ self.application,
+ environ,
+ start_response)
+ my_script_name = environ.get('SCRIPT_NAME', '')
+ environ['paste.recursive.script_name'] = my_script_name
+ try:
+ return self.application(environ, start_response)
+ except ForwardRequestException, e:
+ middleware = CheckForRecursionMiddleware(
+ e.factory(self), environ)
+ return middleware(environ, start_response)
+
+class ForwardRequestException(Exception):
+ """
+ Used to signal that a request should be forwarded to a different location.
+
+ ``url``
+ The URL to forward to starting with a ``/`` and relative to
+ ``RecursiveMiddleware``. URL fragments can also contain query strings
+ so ``/error?code=404`` would be a valid URL fragment.
+
+ ``environ``
+ An altertative WSGI environment dictionary to use for the forwarded
+ request. If specified is used *instead* of the ``url_fragment``
+
+ ``factory``
+ If specifed ``factory`` is used instead of ``url`` or ``environ``.
+ ``factory`` is a callable that takes a WSGI application object
+ as the first argument and returns an initialised WSGI middleware
+ which can alter the forwarded response.
+
+ Basic usage (must have ``RecursiveMiddleware`` present) :
+
+ .. code-block:: python
+
+ from paste.recursive import ForwardRequestException
+ def app(environ, start_response):
+ if environ['PATH_INFO'] == '/hello':
+ start_response("200 OK", [('Content-type', 'text/plain')])
+ return ['Hello World!']
+ elif environ['PATH_INFO'] == '/error':
+ start_response("404 Not Found", [('Content-type', 'text/plain')])
+ return ['Page not found']
+ else:
+ raise ForwardRequestException('/error')
+
+ from paste.recursive import RecursiveMiddleware
+ app = RecursiveMiddleware(app)
+
+ If you ran this application and visited ``/hello`` you would get a
+ ``Hello World!`` message. If you ran the application and visited
+ ``/not_found`` a ``ForwardRequestException`` would be raised and the caught
+ by the ``RecursiveMiddleware``. The ``RecursiveMiddleware`` would then
+ return the headers and response from the ``/error`` URL but would display
+ a ``404 Not found`` status message.
+
+ You could also specify an ``environ`` dictionary instead of a url. Using
+ the same example as before:
+
+ .. code-block:: python
+
+ def app(environ, start_response):
+ ... same as previous example ...
+ else:
+ new_environ = environ.copy()
+ new_environ['PATH_INFO'] = '/error'
+ raise ForwardRequestException(environ=new_environ)
+
+ Finally, if you want complete control over every aspect of the forward you
+ can specify a middleware factory. For example to keep the old status code
+ but use the headers and resposne body from the forwarded response you might
+ do this:
+
+ .. code-block:: python
+
+ from paste.recursive import ForwardRequestException
+ from paste.recursive import RecursiveMiddleware
+ from paste.errordocument import StatusKeeper
+
+ def app(environ, start_response):
+ if environ['PATH_INFO'] == '/hello':
+ start_response("200 OK", [('Content-type', 'text/plain')])
+ return ['Hello World!']
+ elif environ['PATH_INFO'] == '/error':
+ start_response("404 Not Found", [('Content-type', 'text/plain')])
+ return ['Page not found']
+ else:
+ def factory(app):
+ return StatusKeeper(app, status='404 Not Found', url='/error')
+ raise ForwardRequestException(factory=factory)
+
+ app = RecursiveMiddleware(app)
+ """
+
+ def __init__(
+ self,
+ url=None,
+ environ={},
+ factory=None,
+ path_info=None):
+ # Check no incompatible options have been chosen
+ if factory and url:
+ raise TypeError(
+ 'You cannot specify factory and a url in '
+ 'ForwardRequestException')
+ elif factory and environ:
+ raise TypeError(
+ 'You cannot specify factory and environ in '
+ 'ForwardRequestException')
+ if url and environ:
+ raise TypeError(
+ 'You cannot specify environ and url in '
+ 'ForwardRequestException')
+
+ # set the path_info or warn about its use.
+ if path_info:
+ if not url:
+ warnings.warn(
+ "ForwardRequestException(path_info=...) has been deprecated; please "
+ "use ForwardRequestException(url=...)",
+ DeprecationWarning, 2)
+ else:
+ raise TypeError('You cannot use url and path_info in ForwardRequestException')
+ self.path_info = path_info
+
+ # If the url can be treated as a path_info do that
+ if url and not '?' in str(url):
+ self.path_info = url
+
+ # Base middleware
+ class ForwardRequestExceptionMiddleware(object):
+ def __init__(self, app):
+ self.app = app
+
+ # Otherwise construct the appropriate middleware factory
+ if hasattr(self, 'path_info'):
+ p = self.path_info
+ def factory_(app):
+ class PathInfoForward(ForwardRequestExceptionMiddleware):
+ def __call__(self, environ, start_response):
+ environ['PATH_INFO'] = p
+ return self.app(environ, start_response)
+ return PathInfoForward(app)
+ self.factory = factory_
+ elif url:
+ def factory_(app):
+ class URLForward(ForwardRequestExceptionMiddleware):
+ def __call__(self, environ, start_response):
+ environ['PATH_INFO'] = url.split('?')[0]
+ environ['QUERY_STRING'] = url.split('?')[1]
+ return self.app(environ, start_response)
+ return URLForward(app)
+ self.factory = factory_
+ elif environ:
+ def factory_(app):
+ class EnvironForward(ForwardRequestExceptionMiddleware):
+ def __call__(self, environ_, start_response):
+ return self.app(environ, start_response)
+ return EnvironForward(app)
+ self.factory = factory_
+ else:
+ self.factory = factory
+
+class Recursive(object):
+
+ def __init__(self, application, environ, start_response):
+ self.application = application
+ self.original_environ = environ.copy()
+ self.previous_environ = environ
+ self.start_response = start_response
+
+ def __call__(self, path, extra_environ=None):
+ """
+ `extra_environ` is an optional dictionary that is also added
+ to the forwarded request. E.g., ``{'HTTP_HOST': 'new.host'}``
+ could be used to forward to a different virtual host.
+ """
+ environ = self.original_environ.copy()
+ if extra_environ:
+ environ.update(extra_environ)
+ environ['paste.recursive.previous_environ'] = self.previous_environ
+ base_path = self.original_environ.get('SCRIPT_NAME')
+ if path.startswith('/'):
+ assert path.startswith(base_path), (
+ "You can only forward requests to resources under the "
+ "path %r (not %r)" % (base_path, path))
+ path = path[len(base_path)+1:]
+ assert not path.startswith('/')
+ path_info = '/' + path
+ environ['PATH_INFO'] = path_info
+ environ['REQUEST_METHOD'] = 'GET'
+ environ['CONTENT_LENGTH'] = '0'
+ environ['CONTENT_TYPE'] = ''
+ environ['wsgi.input'] = StringIO('')
+ return self.activate(environ)
+
+ def activate(self, environ):
+ raise NotImplementedError
+
+ def __repr__(self):
+ return '<%s.%s from %s>' % (
+ self.__class__.__module__,
+ self.__class__.__name__,
+ self.original_environ.get('SCRIPT_NAME') or '/')
+
+class Forwarder(Recursive):
+
+ """
+ The forwarder will try to restart the request, except with
+ the new `path` (replacing ``PATH_INFO`` in the request).
+
+ It must not be called after and headers have been returned.
+ It returns an iterator that must be returned back up the call
+ stack, so it must be used like:
+
+ .. code-block:: python
+
+ return environ['paste.recursive.forward'](path)
+
+ Meaningful transformations cannot be done, since headers are
+ sent directly to the server and cannot be inspected or
+ rewritten.
+ """
+
+ def activate(self, environ):
+ warnings.warn(
+ "recursive.Forwarder has been deprecated; please use "
+ "ForwardRequestException",
+ DeprecationWarning, 2)
+ return self.application(environ, self.start_response)
+
+
+class Includer(Recursive):
+
+ """
+ Starts another request with the given path and adding or
+ overwriting any values in the `extra_environ` dictionary.
+ Returns an IncludeResponse object.
+ """
+
+ def activate(self, environ):
+ response = IncludedResponse()
+ def start_response(status, headers, exc_info=None):
+ if exc_info:
+ raise exc_info[0], exc_info[1], exc_info[2]
+ response.status = status
+ response.headers = headers
+ return response.write
+ app_iter = self.application(environ, start_response)
+ try:
+ for s in app_iter:
+ response.write(s)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ response.close()
+ return response
+
+class IncludedResponse(object):
+
+ def __init__(self):
+ self.headers = None
+ self.status = None
+ self.output = StringIO()
+ self.str = None
+
+ def close(self):
+ self.str = self.output.getvalue()
+ self.output.close()
+ self.output = None
+
+ def write(self, s):
+ assert self.output is not None, (
+ "This response has already been closed and no further data "
+ "can be written.")
+ self.output.write(s)
+
+ def __str__(self):
+ return self.body
+
+ def body__get(self):
+ if self.str is None:
+ return self.output.getvalue()
+ else:
+ return self.str
+ body = property(body__get)
+
+
+class IncluderAppIter(Recursive):
+ """
+ Like Includer, but just stores the app_iter response
+ (be sure to call close on the response!)
+ """
+
+ def activate(self, environ):
+ response = IncludedAppIterResponse()
+ def start_response(status, headers, exc_info=None):
+ if exc_info:
+ raise exc_info[0], exc_info[1], exc_info[2]
+ response.status = status
+ response.headers = headers
+ return response.write
+ app_iter = self.application(environ, start_response)
+ response.app_iter = app_iter
+ return response
+
+class IncludedAppIterResponse(object):
+
+ def __init__(self):
+ self.status = None
+ self.headers = None
+ self.accumulated = []
+ self.app_iter = None
+ self._closed = False
+
+ def close(self):
+ assert not self._closed, (
+ "Tried to close twice")
+ if hasattr(self.app_iter, 'close'):
+ self.app_iter.close()
+
+ def write(self, s):
+ self.accumulated.append
+
+def make_recursive_middleware(app, global_conf):
+ return RecursiveMiddleware(app)
+
+make_recursive_middleware.__doc__ = __doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,581 @@
+# (c) 2005 Ben Bangert
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""Registry for handling request-local module globals sanely
+
+Dealing with module globals in a thread-safe way is good if your
+application is the sole responder in a thread, however that approach fails
+to properly account for various scenarios that occur with WSGI applications
+and middleware.
+
+What is actually needed in the case where a module global is desired that
+is always set properly depending on the current request, is a stacked
+thread-local object. Such an object is popped or pushed during the request
+cycle so that it properly represents the object that should be active for
+the current request.
+
+To make it easy to deal with such variables, this module provides a special
+StackedObjectProxy class which you can instantiate and attach to your
+module where you'd like others to access it. The object you'd like this to
+actually "be" during the request is then registered with the
+RegistryManager middleware, which ensures that for the scope of the current
+WSGI application everything will work properly.
+
+Example:
+
+.. code-block:: python
+
+ #yourpackage/__init__.py
+
+ from paste.registry import RegistryManager, StackedObjectProxy
+ myglobal = StackedObjectProxy()
+
+ #wsgi app stack
+ app = RegistryManager(yourapp)
+
+ #inside your wsgi app
+ class yourapp(object):
+ def __call__(self, environ, start_response):
+ obj = someobject # The request-local object you want to access
+ # via yourpackage.myglobal
+ if environ.has_key('paste.registry'):
+ environ['paste.registry'].register(myglobal, obj)
+
+You will then be able to import yourpackage anywhere in your WSGI app or in
+the calling stack below it and be assured that it is using the object you
+registered with Registry.
+
+RegistryManager can be in the WSGI stack multiple times, each time it
+appears it registers a new request context.
+
+
+Performance
+===========
+
+The overhead of the proxy object is very minimal, however if you are using
+proxy objects extensively (Thousands of accesses per request or more), there
+are some ways to avoid them. A proxy object runs approximately 3-20x slower
+than direct access to the object, this is rarely your performance bottleneck
+when developing web applications.
+
+Should you be developing a system which may be accessing the proxy object
+thousands of times per request, the performance of the proxy will start to
+become more noticeable. In that circumstance, the problem can be avoided by
+getting at the actual object via the proxy with the ``_current_obj`` function:
+
+.. code-block:: python
+
+ #sessions.py
+ Session = StackedObjectProxy()
+ # ... initialization code, etc.
+
+ # somemodule.py
+ import sessions
+
+ def somefunc():
+ session = sessions.Session._current_obj()
+ # ... tons of session access
+
+This way the proxy is used only once to retrieve the object for the current
+context and the overhead is minimized while still making it easy to access
+the underlying object. The ``_current_obj`` function is preceded by an
+underscore to more likely avoid clashing with the contained object's
+attributes.
+
+**NOTE:** This is *highly* unlikely to be an issue in the vast majority of
+cases, and requires incredibly large amounts of proxy object access before
+one should consider the proxy object to be causing slow-downs. This section
+is provided solely in the extremely rare case that it is an issue so that a
+quick way to work around it is documented.
+
+"""
+import sys
+import paste.util.threadinglocal as threadinglocal
+
+__all__ = ['StackedObjectProxy', 'RegistryManager', 'StackedObjectRestorer',
+ 'restorer']
+
+class NoDefault(object): pass
+
+class StackedObjectProxy(object):
+ """Track an object instance internally using a stack
+
+ The StackedObjectProxy proxies access to an object internally using a
+ stacked thread-local. This makes it safe for complex WSGI environments
+ where access to the object may be desired in multiple places without
+ having to pass the actual object around.
+
+ New objects are added to the top of the stack with _push_object while
+ objects can be removed with _pop_object.
+
+ """
+ def __init__(self, default=NoDefault, name="Default"):
+ """Create a new StackedObjectProxy
+
+ If a default is given, its used in every thread if no other object
+ has been pushed on.
+
+ """
+ self.__dict__['____name__'] = name
+ self.__dict__['____local__'] = threadinglocal.local()
+ if default is not NoDefault:
+ self.__dict__['____default_object__'] = default
+
+ def __dir__(self):
+ """Return a list of the StackedObjectProxy's and proxied
+ object's (if one exists) names.
+ """
+ dir_list = dir(self.__class__) + self.__dict__.keys()
+ try:
+ dir_list.extend(dir(self._current_obj()))
+ except TypeError:
+ pass
+ dir_list.sort()
+ return dir_list
+
+ def __getattr__(self, attr):
+ return getattr(self._current_obj(), attr)
+
+ def __setattr__(self, attr, value):
+ setattr(self._current_obj(), attr, value)
+
+ def __delattr__(self, name):
+ delattr(self._current_obj(), name)
+
+ def __getitem__(self, key):
+ return self._current_obj()[key]
+
+ def __setitem__(self, key, value):
+ self._current_obj()[key] = value
+
+ def __delitem__(self, key):
+ del self._current_obj()[key]
+
+ def __call__(self, *args, **kw):
+ return self._current_obj()(*args, **kw)
+
+ def __repr__(self):
+ try:
+ return repr(self._current_obj())
+ except (TypeError, AttributeError):
+ return '<%s.%s object at 0x%x>' % (self.__class__.__module__,
+ self.__class__.__name__,
+ id(self))
+
+ def __iter__(self):
+ return iter(self._current_obj())
+
+ def __len__(self):
+ return len(self._current_obj())
+
+ def __contains__(self, key):
+ return key in self._current_obj()
+
+ def __nonzero__(self):
+ return bool(self._current_obj())
+
+ def _current_obj(self):
+ """Returns the current active object being proxied to
+
+ In the event that no object was pushed, the default object if
+ provided will be used. Otherwise, a TypeError will be raised.
+
+ """
+ try:
+ objects = self.____local__.objects
+ except AttributeError:
+ objects = None
+ if objects:
+ return objects[-1]
+ else:
+ obj = self.__dict__.get('____default_object__', NoDefault)
+ if obj is not NoDefault:
+ return obj
+ else:
+ raise TypeError(
+ 'No object (name: %s) has been registered for this '
+ 'thread' % self.____name__)
+
+ def _push_object(self, obj):
+ """Make ``obj`` the active object for this thread-local.
+
+ This should be used like:
+
+ .. code-block:: python
+
+ obj = yourobject()
+ module.glob = StackedObjectProxy()
+ module.glob._push_object(obj)
+ try:
+ ... do stuff ...
+ finally:
+ module.glob._pop_object(conf)
+
+ """
+ try:
+ self.____local__.objects.append(obj)
+ except AttributeError:
+ self.____local__.objects = []
+ self.____local__.objects.append(obj)
+
+ def _pop_object(self, obj=None):
+ """Remove a thread-local object.
+
+ If ``obj`` is given, it is checked against the popped object and an
+ error is emitted if they don't match.
+
+ """
+ try:
+ popped = self.____local__.objects.pop()
+ if obj and popped is not obj:
+ raise AssertionError(
+ 'The object popped (%s) is not the same as the object '
+ 'expected (%s)' % (popped, obj))
+ except AttributeError:
+ raise AssertionError('No object has been registered for this thread')
+
+ def _object_stack(self):
+ """Returns all of the objects stacked in this container
+
+ (Might return [] if there are none)
+ """
+ try:
+ try:
+ objs = self.____local__.objects
+ except AttributeError:
+ return []
+ return objs[:]
+ except AssertionError:
+ return []
+
+ # The following methods will be swapped for their original versions by
+ # StackedObjectRestorer when restoration is enabled. The original
+ # functions (e.g. _current_obj) will be available at _current_obj_orig
+
+ def _current_obj_restoration(self):
+ request_id = restorer.in_restoration()
+ if request_id:
+ return restorer.get_saved_proxied_obj(self, request_id)
+ return self._current_obj_orig()
+ _current_obj_restoration.__doc__ = \
+ ('%s\n(StackedObjectRestorer restoration enabled)' % \
+ _current_obj.__doc__)
+
+ def _push_object_restoration(self, obj):
+ if not restorer.in_restoration():
+ self._push_object_orig(obj)
+ _push_object_restoration.__doc__ = \
+ ('%s\n(StackedObjectRestorer restoration enabled)' % \
+ _push_object.__doc__)
+
+ def _pop_object_restoration(self, obj=None):
+ if not restorer.in_restoration():
+ self._pop_object_orig(obj)
+ _pop_object_restoration.__doc__ = \
+ ('%s\n(StackedObjectRestorer restoration enabled)' % \
+ _pop_object.__doc__)
+
+class Registry(object):
+ """Track objects and stacked object proxies for removal
+
+ The Registry object is instantiated a single time for the request no
+ matter how many times the RegistryManager is used in a WSGI stack. Each
+ RegistryManager must call ``prepare`` before continuing the call to
+ start a new context for object registering.
+
+ Each context is tracked with a dict inside a list. The last list
+ element is the currently executing context. Each context dict is keyed
+ by the id of the StackedObjectProxy instance being proxied, the value
+ is a tuple of the StackedObjectProxy instance and the object being
+ tracked.
+
+ """
+ def __init__(self):
+ """Create a new Registry object
+
+ ``prepare`` must still be called before this Registry object can be
+ used to register objects.
+
+ """
+ self.reglist = []
+
+ def prepare(self):
+ """Used to create a new registry context
+
+ Anytime a new RegistryManager is called, ``prepare`` needs to be
+ called on the existing Registry object. This sets up a new context
+ for registering objects.
+
+ """
+ self.reglist.append({})
+
+ def register(self, stacked, obj):
+ """Register an object with a StackedObjectProxy"""
+ myreglist = self.reglist[-1]
+ stacked_id = id(stacked)
+ if stacked_id in myreglist:
+ stacked._pop_object(myreglist[stacked_id][1])
+ del myreglist[stacked_id]
+ stacked._push_object(obj)
+ myreglist[stacked_id] = (stacked, obj)
+
+ def multiregister(self, stacklist):
+ """Register a list of tuples
+
+ Similar call semantics as register, except this registers
+ multiple objects at once.
+
+ Example::
+
+ registry.multiregister([(sop, obj), (anothersop, anotherobj)])
+
+ """
+ myreglist = self.reglist[-1]
+ for stacked, obj in stacklist:
+ stacked_id = id(stacked)
+ if stacked_id in myreglist:
+ stacked._pop_object(myreglist[stacked_id][1])
+ del myreglist[stacked_id]
+ stacked._push_object(obj)
+ myreglist[stacked_id] = (stacked, obj)
+
+ # Replace now does the same thing as register
+ replace = register
+
+ def cleanup(self):
+ """Remove all objects from all StackedObjectProxy instances that
+ were tracked at this Registry context"""
+ for stacked, obj in self.reglist[-1].itervalues():
+ stacked._pop_object(obj)
+ self.reglist.pop()
+
+class RegistryManager(object):
+ """Creates and maintains a Registry context
+
+ RegistryManager creates a new registry context for the registration of
+ StackedObjectProxy instances. Multiple RegistryManager's can be in a
+ WSGI stack and will manage the context so that the StackedObjectProxies
+ always proxy to the proper object.
+
+ The object being registered can be any object sub-class, list, or dict.
+
+ Registering objects is done inside a WSGI application under the
+ RegistryManager instance, using the ``environ['paste.registry']``
+ object which is a Registry instance.
+
+ """
+ def __init__(self, application, streaming=False):
+ self.application = application
+ self.streaming = streaming
+
+ def __call__(self, environ, start_response):
+ app_iter = None
+ reg = environ.setdefault('paste.registry', Registry())
+ reg.prepare()
+ if self.streaming:
+ return self.streaming_iter(reg, environ, start_response)
+
+ try:
+ app_iter = self.application(environ, start_response)
+ except Exception, e:
+ # Regardless of if the content is an iterable, generator, list
+ # or tuple, we clean-up right now. If its an iterable/generator
+ # care should be used to ensure the generator has its own ref
+ # to the actual object
+ if environ.get('paste.evalexception'):
+ # EvalException is present in the WSGI stack
+ expected = False
+ for expect in environ.get('paste.expected_exceptions', []):
+ if isinstance(e, expect):
+ expected = True
+ if not expected:
+ # An unexpected exception: save state for EvalException
+ restorer.save_registry_state(environ)
+ reg.cleanup()
+ raise
+ except:
+ # Save state for EvalException if it's present
+ if environ.get('paste.evalexception'):
+ restorer.save_registry_state(environ)
+ reg.cleanup()
+ raise
+ else:
+ reg.cleanup()
+
+ return app_iter
+
+ def streaming_iter(self, reg, environ, start_response):
+ try:
+ for item in self.application(environ, start_response):
+ yield item
+ except Exception, e:
+ # Regardless of if the content is an iterable, generator, list
+ # or tuple, we clean-up right now. If its an iterable/generator
+ # care should be used to ensure the generator has its own ref
+ # to the actual object
+ if environ.get('paste.evalexception'):
+ # EvalException is present in the WSGI stack
+ expected = False
+ for expect in environ.get('paste.expected_exceptions', []):
+ if isinstance(e, expect):
+ expected = True
+ if not expected:
+ # An unexpected exception: save state for EvalException
+ restorer.save_registry_state(environ)
+ reg.cleanup()
+ raise
+ except:
+ # Save state for EvalException if it's present
+ if environ.get('paste.evalexception'):
+ restorer.save_registry_state(environ)
+ reg.cleanup()
+ raise
+ else:
+ reg.cleanup()
+
+
+class StackedObjectRestorer(object):
+ """Track StackedObjectProxies and their proxied objects for automatic
+ restoration within EvalException's interactive debugger.
+
+ An instance of this class tracks all StackedObjectProxy state in existence
+ when unexpected exceptions are raised by WSGI applications housed by
+ EvalException and RegistryManager. Like EvalException, this information is
+ stored for the life of the process.
+
+ When an unexpected exception occurs and EvalException is present in the
+ WSGI stack, save_registry_state is intended to be called to store the
+ Registry state and enable automatic restoration on all currently registered
+ StackedObjectProxies.
+
+ With restoration enabled, those StackedObjectProxies' _current_obj
+ (overwritten by _current_obj_restoration) method's strategy is modified:
+ it will return its appropriate proxied object from the restorer when
+ a restoration context is active in the current thread.
+
+ The StackedObjectProxies' _push/pop_object methods strategies are also
+ changed: they no-op when a restoration context is active in the current
+ thread (because the pushing/popping work is all handled by the
+ Registry/restorer).
+
+ The request's Registry objects' reglists are restored from the restorer
+ when a restoration context begins, enabling the Registry methods to work
+ while their changes are tracked by the restorer.
+
+ The overhead of enabling restoration is negligible (another threadlocal
+ access for the changed StackedObjectProxy methods) for normal use outside
+ of a restoration context, but worth mentioning when combined with
+ StackedObjectProxies normal overhead. Once enabled it does not turn off,
+ however:
+
+ o Enabling restoration only occurs after an unexpected exception is
+ detected. The server is likely to be restarted shortly after the exception
+ is raised to fix the cause
+
+ o StackedObjectRestorer is only enabled when EvalException is enabled (not
+ on a production server) and RegistryManager exists in the middleware
+ stack"""
+ def __init__(self):
+ # Registries and their saved reglists by request_id
+ self.saved_registry_states = {}
+ self.restoration_context_id = threadinglocal.local()
+
+ def save_registry_state(self, environ):
+ """Save the state of this request's Registry (if it hasn't already been
+ saved) to the saved_registry_states dict, keyed by the request's unique
+ identifier"""
+ registry = environ.get('paste.registry')
+ if not registry or not len(registry.reglist) or \
+ self.get_request_id(environ) in self.saved_registry_states:
+ # No Registry, no state to save, or this request's state has
+ # already been saved
+ return
+
+ self.saved_registry_states[self.get_request_id(environ)] = \
+ (registry, registry.reglist[:])
+
+ # Tweak the StackedObjectProxies we want to save state for -- change
+ # their methods to act differently when a restoration context is active
+ # in the current thread
+ for reglist in registry.reglist:
+ for stacked, obj in reglist.itervalues():
+ self.enable_restoration(stacked)
+
+ def get_saved_proxied_obj(self, stacked, request_id):
+ """Retrieve the saved object proxied by the specified
+ StackedObjectProxy for the request identified by request_id"""
+ # All state for the request identified by request_id
+ reglist = self.saved_registry_states[request_id][1]
+
+ # The top of the stack was current when the exception occurred
+ stack_level = len(reglist) - 1
+ stacked_id = id(stacked)
+ while True:
+ if stack_level < 0:
+ # Nothing registered: Call _current_obj_orig to raise a
+ # TypeError
+ return stacked._current_obj_orig()
+ context = reglist[stack_level]
+ if stacked_id in context:
+ break
+ # This StackedObjectProxy may not have been registered by the
+ # RegistryManager that was active when the exception was raised --
+ # continue searching down the stack until it's found
+ stack_level -= 1
+ return context[stacked_id][1]
+
+ def enable_restoration(self, stacked):
+ """Replace the specified StackedObjectProxy's methods with their
+ respective restoration versions.
+
+ _current_obj_restoration forces recovery of the saved proxied object
+ when a restoration context is active in the current thread.
+
+ _push/pop_object_restoration avoid pushing/popping data
+ (pushing/popping is only done at the Registry level) when a restoration
+ context is active in the current thread"""
+ if '_current_obj_orig' in stacked.__dict__:
+ # Restoration already enabled
+ return
+
+ for func_name in ('_current_obj', '_push_object', '_pop_object'):
+ orig_func = getattr(stacked, func_name)
+ restoration_func = getattr(stacked, func_name + '_restoration')
+ stacked.__dict__[func_name + '_orig'] = orig_func
+ stacked.__dict__[func_name] = restoration_func
+
+ def get_request_id(self, environ):
+ """Return a unique identifier for the current request"""
+ from paste.evalexception.middleware import get_debug_count
+ return get_debug_count(environ)
+
+ def restoration_begin(self, request_id):
+ """Enable a restoration context in the current thread for the specified
+ request_id"""
+ if request_id in self.saved_registry_states:
+ # Restore the old Registry object's state
+ registry, reglist = self.saved_registry_states[request_id]
+ registry.reglist = reglist
+
+ self.restoration_context_id.request_id = request_id
+
+ def restoration_end(self):
+ """Register a restoration context as finished, if one exists"""
+ try:
+ del self.restoration_context_id.request_id
+ except AttributeError:
+ pass
+
+ def in_restoration(self):
+ """Determine if a restoration context is active for the current thread.
+ Returns the request_id it's active for if so, otherwise False"""
+ return getattr(self.restoration_context_id, 'request_id', False)
+
+restorer = StackedObjectRestorer()
+
+
+# Paste Deploy entry point
+def make_registry_manager(app, global_conf):
+ return RegistryManager(app)
+
+make_registry_manager.__doc__ = RegistryManager.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/reloader.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/reloader.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/reloader.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,178 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+A file monitor and server restarter.
+
+Use this like:
+
+..code-block:: Python
+
+ import reloader
+ reloader.install()
+
+Then make sure your server is installed with a shell script like::
+
+ err=3
+ while test "$err" -eq 3 ; do
+ python server.py
+ err="$?"
+ done
+
+or is run from this .bat file (if you use Windows)::
+
+ @echo off
+ :repeat
+ python server.py
+ if %errorlevel% == 3 goto repeat
+
+or run a monitoring process in Python (``paster serve --reload`` does
+this).
+
+Use the ``watch_file(filename)`` function to cause a reload/restart for
+other other non-Python files (e.g., configuration files). If you have
+a dynamic set of files that grows over time you can use something like::
+
+ def watch_config_files():
+ return CONFIG_FILE_CACHE.keys()
+ paste.reloader.add_file_callback(watch_config_files)
+
+Then every time the reloader polls files it will call
+``watch_config_files`` and check all the filenames it returns.
+"""
+
+import os
+import sys
+import time
+import threading
+import traceback
+from paste.util.classinstance import classinstancemethod
+
+def install(poll_interval=1):
+ """
+ Install the reloading monitor.
+
+ On some platforms server threads may not terminate when the main
+ thread does, causing ports to remain open/locked. The
+ ``raise_keyboard_interrupt`` option creates a unignorable signal
+ which causes the whole application to shut-down (rudely).
+ """
+ mon = Monitor(poll_interval=poll_interval)
+ t = threading.Thread(target=mon.periodic_reload)
+ t.setDaemon(True)
+ t.start()
+
+class Monitor(object):
+
+ instances = []
+ global_extra_files = []
+ global_file_callbacks = []
+
+ def __init__(self, poll_interval):
+ self.module_mtimes = {}
+ self.keep_running = True
+ self.poll_interval = poll_interval
+ self.extra_files = list(self.global_extra_files)
+ self.instances.append(self)
+ self.file_callbacks = list(self.global_file_callbacks)
+
+ def periodic_reload(self):
+ while True:
+ if not self.check_reload():
+ # use os._exit() here and not sys.exit() since within a
+ # thread sys.exit() just closes the given thread and
+ # won't kill the process; note os._exit does not call
+ # any atexit callbacks, nor does it do finally blocks,
+ # flush open files, etc. In otherwords, it is rude.
+ os._exit(3)
+ break
+ time.sleep(self.poll_interval)
+
+ def check_reload(self):
+ filenames = list(self.extra_files)
+ for file_callback in self.file_callbacks:
+ try:
+ filenames.extend(file_callback())
+ except:
+ print >> sys.stderr, "Error calling paste.reloader callback %r:" % file_callback
+ traceback.print_exc()
+ for module in sys.modules.values():
+ try:
+ filename = module.__file__
+ except (AttributeError, ImportError), exc:
+ continue
+ if filename is not None:
+ filenames.append(filename)
+ for filename in filenames:
+ try:
+ stat = os.stat(filename)
+ if stat:
+ mtime = stat.st_mtime
+ else:
+ mtime = 0
+ except (OSError, IOError):
+ continue
+ if filename.endswith('.pyc') and os.path.exists(filename[:-1]):
+ mtime = max(os.stat(filename[:-1]).st_mtime, mtime)
+ elif filename.endswith('$py.class') and \
+ os.path.exists(filename[:-9] + '.py'):
+ mtime = max(os.stat(filename[:-9] + '.py').st_mtime, mtime)
+ if not self.module_mtimes.has_key(filename):
+ self.module_mtimes[filename] = mtime
+ elif self.module_mtimes[filename] < mtime:
+ print >> sys.stderr, (
+ "%s changed; reloading..." % filename)
+ return False
+ return True
+
+ def watch_file(self, cls, filename):
+ """Watch the named file for changes"""
+ filename = os.path.abspath(filename)
+ if self is None:
+ for instance in cls.instances:
+ instance.watch_file(filename)
+ cls.global_extra_files.append(filename)
+ else:
+ self.extra_files.append(filename)
+
+ watch_file = classinstancemethod(watch_file)
+
+ def add_file_callback(self, cls, callback):
+ """Add a callback -- a function that takes no parameters -- that will
+ return a list of filenames to watch for changes."""
+ if self is None:
+ for instance in cls.instances:
+ instance.add_file_callback(callback)
+ cls.global_file_callbacks.append(callback)
+ else:
+ self.file_callbacks.append(callback)
+
+ add_file_callback = classinstancemethod(add_file_callback)
+
+if sys.platform.startswith('java'):
+ try:
+ from _systemrestart import SystemRestart
+ except ImportError:
+ pass
+ else:
+ class JythonMonitor(Monitor):
+
+ """
+ Monitor that utilizes Jython's special
+ ``_systemrestart.SystemRestart`` exception.
+
+ When raised from the main thread it causes Jython to reload
+ the interpreter in the existing Java process (avoiding
+ startup time).
+
+ Note that this functionality of Jython is experimental and
+ may change in the future.
+ """
+
+ def periodic_reload(self):
+ while True:
+ if not self.check_reload():
+ raise SystemRestart()
+ time.sleep(self.poll_interval)
+
+watch_file = Monitor.watch_file
+add_file_callback = Monitor.add_file_callback
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/request.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/request.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/request.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,411 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Ian Bicking and contributors
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+This module provides helper routines with work directly on a WSGI
+environment to solve common requirements.
+
+ * get_cookies(environ)
+ * parse_querystring(environ)
+ * parse_formvars(environ, include_get_vars=True)
+ * construct_url(environ, with_query_string=True, with_path_info=True,
+ script_name=None, path_info=None, querystring=None)
+ * path_info_split(path_info)
+ * path_info_pop(environ)
+ * resolve_relative_url(url, environ)
+
+"""
+import cgi
+from Cookie import SimpleCookie, CookieError
+from StringIO import StringIO
+import urlparse
+import urllib
+try:
+ from UserDict import DictMixin
+except ImportError:
+ from paste.util.UserDict24 import DictMixin
+from paste.util.multidict import MultiDict
+
+__all__ = ['get_cookies', 'get_cookie_dict', 'parse_querystring',
+ 'parse_formvars', 'construct_url', 'path_info_split',
+ 'path_info_pop', 'resolve_relative_url', 'EnvironHeaders']
+
+def get_cookies(environ):
+ """
+ Gets a cookie object (which is a dictionary-like object) from the
+ request environment; caches this value in case get_cookies is
+ called again for the same request.
+
+ """
+ header = environ.get('HTTP_COOKIE', '')
+ if environ.has_key('paste.cookies'):
+ cookies, check_header = environ['paste.cookies']
+ if check_header == header:
+ return cookies
+ cookies = SimpleCookie()
+ try:
+ cookies.load(header)
+ except CookieError:
+ pass
+ environ['paste.cookies'] = (cookies, header)
+ return cookies
+
+def get_cookie_dict(environ):
+ """Return a *plain* dictionary of cookies as found in the request.
+
+ Unlike ``get_cookies`` this returns a dictionary, not a
+ ``SimpleCookie`` object. For incoming cookies a dictionary fully
+ represents the information. Like ``get_cookies`` this caches and
+ checks the cache.
+ """
+ header = environ.get('HTTP_COOKIE')
+ if not header:
+ return {}
+ if environ.has_key('paste.cookies.dict'):
+ cookies, check_header = environ['paste.cookies.dict']
+ if check_header == header:
+ return cookies
+ cookies = SimpleCookie()
+ try:
+ cookies.load(header)
+ except CookieError:
+ pass
+ result = {}
+ for name in cookies:
+ result[name] = cookies[name].value
+ environ['paste.cookies.dict'] = (result, header)
+ return result
+
+def parse_querystring(environ):
+ """
+ Parses a query string into a list like ``[(name, value)]``.
+ Caches this value in case parse_querystring is called again
+ for the same request.
+
+ You can pass the result to ``dict()``, but be aware that keys that
+ appear multiple times will be lost (only the last value will be
+ preserved).
+
+ """
+ source = environ.get('QUERY_STRING', '')
+ if not source:
+ return []
+ if 'paste.parsed_querystring' in environ:
+ parsed, check_source = environ['paste.parsed_querystring']
+ if check_source == source:
+ return parsed
+ parsed = cgi.parse_qsl(source, keep_blank_values=True,
+ strict_parsing=False)
+ environ['paste.parsed_querystring'] = (parsed, source)
+ return parsed
+
+def parse_dict_querystring(environ):
+ """Parses a query string like parse_querystring, but returns a MultiDict
+
+ Caches this value in case parse_dict_querystring is called again
+ for the same request.
+
+ Example::
+
+ >>> environ = {'QUERY_STRING': 'day=Monday&user=fred&user=jane'}
+ >>> parsed = parse_dict_querystring(environ)
+
+ >>> parsed['day']
+ 'Monday'
+ >>> parsed['user']
+ 'fred'
+ >>> parsed.getall('user')
+ ['fred', 'jane']
+
+ """
+ source = environ.get('QUERY_STRING', '')
+ if not source:
+ return MultiDict()
+ if 'paste.parsed_dict_querystring' in environ:
+ parsed, check_source = environ['paste.parsed_dict_querystring']
+ if check_source == source:
+ return parsed
+ parsed = cgi.parse_qsl(source, keep_blank_values=True,
+ strict_parsing=False)
+ multi = MultiDict(parsed)
+ environ['paste.parsed_dict_querystring'] = (multi, source)
+ return multi
+
+def parse_formvars(environ, include_get_vars=True):
+ """Parses the request, returning a MultiDict of form variables.
+
+ If ``include_get_vars`` is true then GET (query string) variables
+ will also be folded into the MultiDict.
+
+ All values should be strings, except for file uploads which are
+ left as ``FieldStorage`` instances.
+
+ If the request was not a normal form request (e.g., a POST with an
+ XML body) then ``environ['wsgi.input']`` won't be read.
+ """
+ source = environ['wsgi.input']
+ if 'paste.parsed_formvars' in environ:
+ parsed, check_source = environ['paste.parsed_formvars']
+ if check_source == source:
+ if include_get_vars:
+ parsed.update(parse_querystring(environ))
+ return parsed
+ # @@: Shouldn't bother FieldStorage parsing during GET/HEAD and
+ # fake_out_cgi requests
+ type = environ.get('CONTENT_TYPE', '').lower()
+ if ';' in type:
+ type = type.split(';', 1)[0]
+ fake_out_cgi = type not in ('', 'application/x-www-form-urlencoded',
+ 'multipart/form-data')
+ # FieldStorage assumes a default CONTENT_LENGTH of -1, but a
+ # default of 0 is better:
+ if not environ.get('CONTENT_LENGTH'):
+ environ['CONTENT_LENGTH'] = '0'
+ # Prevent FieldStorage from parsing QUERY_STRING during GET/HEAD
+ # requests
+ old_query_string = environ.get('QUERY_STRING','')
+ environ['QUERY_STRING'] = ''
+ if fake_out_cgi:
+ input = StringIO('')
+ old_content_type = environ.get('CONTENT_TYPE')
+ old_content_length = environ.get('CONTENT_LENGTH')
+ environ['CONTENT_LENGTH'] = '0'
+ environ['CONTENT_TYPE'] = ''
+ else:
+ input = environ['wsgi.input']
+ fs = cgi.FieldStorage(fp=input,
+ environ=environ,
+ keep_blank_values=1)
+ environ['QUERY_STRING'] = old_query_string
+ if fake_out_cgi:
+ environ['CONTENT_TYPE'] = old_content_type
+ environ['CONTENT_LENGTH'] = old_content_length
+ formvars = MultiDict()
+ if isinstance(fs.value, list):
+ for name in fs.keys():
+ values = fs[name]
+ if not isinstance(values, list):
+ values = [values]
+ for value in values:
+ if not value.filename:
+ value = value.value
+ formvars.add(name, value)
+ environ['paste.parsed_formvars'] = (formvars, source)
+ if include_get_vars:
+ formvars.update(parse_querystring(environ))
+ return formvars
+
+def construct_url(environ, with_query_string=True, with_path_info=True,
+ script_name=None, path_info=None, querystring=None):
+ """Reconstructs the URL from the WSGI environment.
+
+ You may override SCRIPT_NAME, PATH_INFO, and QUERYSTRING with
+ the keyword arguments.
+
+ """
+ url = environ['wsgi.url_scheme']+'://'
+
+ if environ.get('HTTP_HOST'):
+ host = environ['HTTP_HOST']
+ port = None
+ if ':' in host:
+ host, port = host.split(':', 1)
+ if environ['wsgi.url_scheme'] == 'https':
+ if port == '443':
+ port = None
+ elif environ['wsgi.url_scheme'] == 'http':
+ if port == '80':
+ port = None
+ url += host
+ if port:
+ url += ':%s' % port
+ else:
+ url += environ['SERVER_NAME']
+ if environ['wsgi.url_scheme'] == 'https':
+ if environ['SERVER_PORT'] != '443':
+ url += ':' + environ['SERVER_PORT']
+ else:
+ if environ['SERVER_PORT'] != '80':
+ url += ':' + environ['SERVER_PORT']
+
+ if script_name is None:
+ url += urllib.quote(environ.get('SCRIPT_NAME',''))
+ else:
+ url += urllib.quote(script_name)
+ if with_path_info:
+ if path_info is None:
+ url += urllib.quote(environ.get('PATH_INFO',''))
+ else:
+ url += urllib.quote(path_info)
+ if with_query_string:
+ if querystring is None:
+ if environ.get('QUERY_STRING'):
+ url += '?' + environ['QUERY_STRING']
+ elif querystring:
+ url += '?' + querystring
+ return url
+
+def resolve_relative_url(url, environ):
+ """
+ Resolve the given relative URL as being relative to the
+ location represented by the environment. This can be used
+ for redirecting to a relative path. Note: if url is already
+ absolute, this function will (intentionally) have no effect
+ on it.
+
+ """
+ cur_url = construct_url(environ, with_query_string=False)
+ return urlparse.urljoin(cur_url, url)
+
+def path_info_split(path_info):
+ """
+ Splits off the first segment of the path. Returns (first_part,
+ rest_of_path). first_part can be None (if PATH_INFO is empty), ''
+ (if PATH_INFO is '/'), or a name without any /'s. rest_of_path
+ can be '' or a string starting with /.
+
+ """
+ if not path_info:
+ return None, ''
+ assert path_info.startswith('/'), (
+ "PATH_INFO should start with /: %r" % path_info)
+ path_info = path_info.lstrip('/')
+ if '/' in path_info:
+ first, rest = path_info.split('/', 1)
+ return first, '/' + rest
+ else:
+ return path_info, ''
+
+def path_info_pop(environ):
+ """
+ 'Pops' off the next segment of PATH_INFO, pushing it onto
+ SCRIPT_NAME, and returning that segment.
+
+ For instance::
+
+ >>> def call_it(script_name, path_info):
+ ... env = {'SCRIPT_NAME': script_name, 'PATH_INFO': path_info}
+ ... result = path_info_pop(env)
+ ... print 'SCRIPT_NAME=%r; PATH_INFO=%r; returns=%r' % (
+ ... env['SCRIPT_NAME'], env['PATH_INFO'], result)
+ >>> call_it('/foo', '/bar')
+ SCRIPT_NAME='/foo/bar'; PATH_INFO=''; returns='bar'
+ >>> call_it('/foo/bar', '')
+ SCRIPT_NAME='/foo/bar'; PATH_INFO=''; returns=None
+ >>> call_it('/foo/bar', '/')
+ SCRIPT_NAME='/foo/bar/'; PATH_INFO=''; returns=''
+ >>> call_it('', '/1/2/3')
+ SCRIPT_NAME='/1'; PATH_INFO='/2/3'; returns='1'
+ >>> call_it('', '//1/2')
+ SCRIPT_NAME='//1'; PATH_INFO='/2'; returns='1'
+
+ """
+ path = environ.get('PATH_INFO', '')
+ if not path:
+ return None
+ while path.startswith('/'):
+ environ['SCRIPT_NAME'] += '/'
+ path = path[1:]
+ if '/' not in path:
+ environ['SCRIPT_NAME'] += path
+ environ['PATH_INFO'] = ''
+ return path
+ else:
+ segment, path = path.split('/', 1)
+ environ['PATH_INFO'] = '/' + path
+ environ['SCRIPT_NAME'] += segment
+ return segment
+
+_parse_headers_special = {
+ # This is a Zope convention, but we'll allow it here:
+ 'HTTP_CGI_AUTHORIZATION': 'Authorization',
+ 'CONTENT_LENGTH': 'Content-Length',
+ 'CONTENT_TYPE': 'Content-Type',
+ }
+
+def parse_headers(environ):
+ """
+ Parse the headers in the environment (like ``HTTP_HOST``) and
+ yield a sequence of those (header_name, value) tuples.
+ """
+ # @@: Maybe should parse out comma-separated headers?
+ for cgi_var, value in environ.iteritems():
+ if cgi_var in _parse_headers_special:
+ yield _parse_headers_special[cgi_var], value
+ elif cgi_var.startswith('HTTP_'):
+ yield cgi_var[5:].title().replace('_', '-'), value
+
+class EnvironHeaders(DictMixin):
+ """An object that represents the headers as present in a
+ WSGI environment.
+
+ This object is a wrapper (with no internal state) for a WSGI
+ request object, representing the CGI-style HTTP_* keys as a
+ dictionary. Because a CGI environment can only hold one value for
+ each key, this dictionary is single-valued (unlike outgoing
+ headers).
+ """
+
+ def __init__(self, environ):
+ self.environ = environ
+
+ def _trans_name(self, name):
+ key = 'HTTP_'+name.replace('-', '_').upper()
+ if key == 'HTTP_CONTENT_LENGTH':
+ key = 'CONTENT_LENGTH'
+ elif key == 'HTTP_CONTENT_TYPE':
+ key = 'CONTENT_TYPE'
+ return key
+
+ def _trans_key(self, key):
+ if key == 'CONTENT_TYPE':
+ return 'Content-Type'
+ elif key == 'CONTENT_LENGTH':
+ return 'Content-Length'
+ elif key.startswith('HTTP_'):
+ return key[5:].replace('_', '-').title()
+ else:
+ return None
+
+ def __getitem__(self, item):
+ return self.environ[self._trans_name(item)]
+
+ def __setitem__(self, item, value):
+ # @@: Should this dictionary be writable at all?
+ self.environ[self._trans_name(item)] = value
+
+ def __delitem__(self, item):
+ del self.environ[self._trans_name(item)]
+
+ def __iter__(self):
+ for key in self.environ:
+ name = self._trans_key(key)
+ if name is not None:
+ yield name
+
+ def keys(self):
+ return list(iter(self))
+
+ def __contains__(self, item):
+ return self._trans_name(item) in self.environ
+
+def _cgi_FieldStorage__repr__patch(self):
+ """ monkey patch for FieldStorage.__repr__
+
+ Unbelievely, the default __repr__ on FieldStorage reads
+ the entire file content instead of being sane about it.
+ This is a simple replacement that doesn't do that
+ """
+ if self.file:
+ return "FieldStorage(%r, %r)" % (
+ self.name, self.filename)
+ return "FieldStorage(%r, %r, %r)" % (
+ self.name, self.filename, self.value)
+
+cgi.FieldStorage.__repr__ = _cgi_FieldStorage__repr__patch
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/response.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/response.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/response.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,240 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""Routines to generate WSGI responses"""
+
+############################################################
+## Headers
+############################################################
+import warnings
+
+class HeaderDict(dict):
+
+ """
+ This represents response headers. It handles the headers as a
+ dictionary, with case-insensitive keys.
+
+ Also there is an ``.add(key, value)`` method, which sets the key,
+ or adds the value to the current value (turning it into a list if
+ necessary).
+
+ For passing to WSGI there is a ``.headeritems()`` method which is
+ like ``.items()`` but unpacks value that are lists. It also
+ handles encoding -- all headers are encoded in ASCII (if they are
+ unicode).
+
+ @@: Should that encoding be ISO-8859-1 or UTF-8? I'm not sure
+ what the spec says.
+ """
+
+ def __getitem__(self, key):
+ return dict.__getitem__(self, self.normalize(key))
+
+ def __setitem__(self, key, value):
+ dict.__setitem__(self, self.normalize(key), value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, self.normalize(key))
+
+ def __contains__(self, key):
+ return dict.__contains__(self, self.normalize(key))
+
+ has_key = __contains__
+
+ def get(self, key, failobj=None):
+ return dict.get(self, self.normalize(key), failobj)
+
+ def setdefault(self, key, failobj=None):
+ return dict.setdefault(self, self.normalize(key), failobj)
+
+ def pop(self, key, *args):
+ return dict.pop(self, self.normalize(key), *args)
+
+ def update(self, other):
+ for key in other:
+ self[self.normalize(key)] = other[key]
+
+ def normalize(self, key):
+ return str(key).lower().strip()
+
+ def add(self, key, value):
+ key = self.normalize(key)
+ if key in self:
+ if isinstance(self[key], list):
+ self[key].append(value)
+ else:
+ self[key] = [self[key], value]
+ else:
+ self[key] = value
+
+ def headeritems(self):
+ result = []
+ for key, value in self.items():
+ if isinstance(value, list):
+ for v in value:
+ result.append((key, str(v)))
+ else:
+ result.append((key, str(value)))
+ return result
+
+ #@classmethod
+ def fromlist(cls, seq):
+ self = cls()
+ for name, value in seq:
+ self.add(name, value)
+ return self
+
+ fromlist = classmethod(fromlist)
+
+def has_header(headers, name):
+ """
+ Is header named ``name`` present in headers?
+ """
+ name = name.lower()
+ for header, value in headers:
+ if header.lower() == name:
+ return True
+ return False
+
+def header_value(headers, name):
+ """
+ Returns the header's value, or None if no such header. If a
+ header appears more than once, all the values of the headers
+ are joined with ','. Note that this is consistent /w RFC 2616
+ section 4.2 which states:
+
+ It MUST be possible to combine the multiple header fields
+ into one "field-name: field-value" pair, without changing
+ the semantics of the message, by appending each subsequent
+ field-value to the first, each separated by a comma.
+
+ However, note that the original netscape usage of 'Set-Cookie',
+ especially in MSIE which contains an 'expires' date will is not
+ compatible with this particular concatination method.
+ """
+ name = name.lower()
+ result = [value for header, value in headers
+ if header.lower() == name]
+ if result:
+ return ','.join(result)
+ else:
+ return None
+
+def remove_header(headers, name):
+ """
+ Removes the named header from the list of headers. Returns the
+ value of that header, or None if no header found. If multiple
+ headers are found, only the last one is returned.
+ """
+ name = name.lower()
+ i = 0
+ result = None
+ while i < len(headers):
+ if headers[i][0].lower() == name:
+ result = headers[i][1]
+ del headers[i]
+ continue
+ i += 1
+ return result
+
+def replace_header(headers, name, value):
+ """
+ Updates the headers replacing the first occurance of the given name
+ with the value provided; asserting that no further occurances
+ happen. Note that this is _not_ the same as remove_header and then
+ append, as two distinct operations (del followed by an append) are
+ not atomic in a threaded environment. Returns the previous header
+ value for the provided name, if any. Clearly one should not use
+ this function with ``set-cookie`` or other names that may have more
+ than one occurance in the headers.
+ """
+ name = name.lower()
+ i = 0
+ result = None
+ while i < len(headers):
+ if headers[i][0].lower() == name:
+ assert not result, "two values for the header '%s' found" % name
+ result = headers[i][1]
+ headers[i] = (name, value)
+ i += 1
+ if not result:
+ headers.append((name, value))
+ return result
+
+
+############################################################
+## Deprecated methods
+############################################################
+
+def error_body_response(error_code, message, __warn=True):
+ """
+ Returns a standard HTML response page for an HTTP error.
+ **Note:** Deprecated
+ """
+ if __warn:
+ warnings.warn(
+ 'wsgilib.error_body_response is deprecated; use the '
+ 'wsgi_application method on an HTTPException object '
+ 'instead', DeprecationWarning, 2)
+ return '''\
+<html>
+ <head>
+ <title>%(error_code)s</title>
+ </head>
+ <body>
+ <h1>%(error_code)s</h1>
+ %(message)s
+ </body>
+</html>''' % {
+ 'error_code': error_code,
+ 'message': message,
+ }
+
+
+def error_response(environ, error_code, message,
+ debug_message=None, __warn=True):
+ """
+ Returns the status, headers, and body of an error response.
+
+ Use like:
+
+ .. code-block:: python
+
+ status, headers, body = wsgilib.error_response(
+ '301 Moved Permanently', 'Moved to <a href="%s">%s</a>'
+ % (url, url))
+ start_response(status, headers)
+ return [body]
+
+ **Note:** Deprecated
+ """
+ if __warn:
+ warnings.warn(
+ 'wsgilib.error_response is deprecated; use the '
+ 'wsgi_application method on an HTTPException object '
+ 'instead', DeprecationWarning, 2)
+ if debug_message and environ.get('paste.config', {}).get('debug'):
+ message += '\n\n<!-- %s -->' % debug_message
+ body = error_body_response(error_code, message, __warn=False)
+ headers = [('content-type', 'text/html'),
+ ('content-length', str(len(body)))]
+ return error_code, headers, body
+
+def error_response_app(error_code, message, debug_message=None,
+ __warn=True):
+ """
+ An application that emits the given error response.
+
+ **Note:** Deprecated
+ """
+ if __warn:
+ warnings.warn(
+ 'wsgilib.error_response_app is deprecated; use the '
+ 'wsgi_application method on an HTTPException object '
+ 'instead', DeprecationWarning, 2)
+ def application(environ, start_response):
+ status, headers, body = error_response(
+ environ, error_code, message,
+ debug_message=debug_message, __warn=False)
+ start_response(status, headers)
+ return [body]
+ return application
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/session.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/session.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/session.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,337 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+Creates a session object in your WSGI environment.
+
+Use like:
+
+..code-block:: Python
+
+ environ['paste.session.factory']()
+
+This will return a dictionary. The contents of this dictionary will
+be saved to disk when the request is completed. The session will be
+created when you first fetch the session dictionary, and a cookie will
+be sent in that case. There's current no way to use sessions without
+cookies, and there's no way to delete a session except to clear its
+data.
+
+@@: This doesn't do any locking, and may cause problems when a single
+session is accessed concurrently. Also, it loads and saves the
+session for each request, with no caching. Also, sessions aren't
+expired.
+"""
+
+from Cookie import SimpleCookie
+import time
+import random
+import os
+import datetime
+import threading
+import tempfile
+
+try:
+ import cPickle
+except ImportError:
+ import pickle as cPickle
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+from paste import wsgilib
+from paste import request
+
+class SessionMiddleware(object):
+
+ def __init__(self, application, global_conf=None, **factory_kw):
+ self.application = application
+ self.factory_kw = factory_kw
+
+ def __call__(self, environ, start_response):
+ session_factory = SessionFactory(environ, **self.factory_kw)
+ environ['paste.session.factory'] = session_factory
+ remember_headers = []
+
+ def session_start_response(status, headers, exc_info=None):
+ if not session_factory.created:
+ remember_headers[:] = [status, headers]
+ return start_response(status, headers)
+ headers.append(session_factory.set_cookie_header())
+ return start_response(status, headers, exc_info)
+
+ app_iter = self.application(environ, session_start_response)
+ def start():
+ if session_factory.created and remember_headers:
+ # Tricky bastard used the session after start_response
+ status, headers = remember_headers
+ headers.append(session_factory.set_cookie_header())
+ exc = ValueError(
+ "You cannot get the session after content from the "
+ "app_iter has been returned")
+ start_response(status, headers, (exc.__class__, exc, None))
+ def close():
+ if session_factory.used:
+ session_factory.close()
+ return wsgilib.add_start_close(app_iter, start, close)
+
+
+class SessionFactory(object):
+
+
+ def __init__(self, environ, cookie_name='_SID_',
+ session_class=None,
+ session_expiration=60*12, # in minutes
+ **session_class_kw):
+
+ self.created = False
+ self.used = False
+ self.environ = environ
+ self.cookie_name = cookie_name
+ self.session = None
+ self.session_class = session_class or FileSession
+ self.session_class_kw = session_class_kw
+
+ self.expiration = session_expiration
+
+ def __call__(self):
+ self.used = True
+ if self.session is not None:
+ return self.session.data()
+ cookies = request.get_cookies(self.environ)
+ session = None
+ if cookies.has_key(self.cookie_name):
+ self.sid = cookies[self.cookie_name].value
+ try:
+ session = self.session_class(self.sid, create=False,
+ **self.session_class_kw)
+ except KeyError:
+ # Invalid SID
+ pass
+ if session is None:
+ self.created = True
+ self.sid = self.make_sid()
+ session = self.session_class(self.sid, create=True,
+ **self.session_class_kw)
+ session.clean_up()
+ self.session = session
+ return session.data()
+
+ def has_session(self):
+ if self.session is not None:
+ return True
+ cookies = request.get_cookies(self.environ)
+ if cookies.has_key(self.cookie_name):
+ return True
+ return False
+
+ def make_sid(self):
+ # @@: need better algorithm
+ return (''.join(['%02d' % x for x in time.localtime(time.time())[:6]])
+ + '-' + self.unique_id())
+
+ def unique_id(self, for_object=None):
+ """
+ Generates an opaque, identifier string that is practically
+ guaranteed to be unique. If an object is passed, then its
+ id() is incorporated into the generation. Relies on md5 and
+ returns a 32 character long string.
+ """
+ r = [time.time(), random.random()]
+ if hasattr(os, 'times'):
+ r.append(os.times())
+ if for_object is not None:
+ r.append(id(for_object))
+ md5_hash = md5(str(r))
+ try:
+ return md5_hash.hexdigest()
+ except AttributeError:
+ # Older versions of Python didn't have hexdigest, so we'll
+ # do it manually
+ hexdigest = []
+ for char in md5_hash.digest():
+ hexdigest.append('%02x' % ord(char))
+ return ''.join(hexdigest)
+
+ def set_cookie_header(self):
+ c = SimpleCookie()
+ c[self.cookie_name] = self.sid
+ c[self.cookie_name]['path'] = '/'
+
+ gmt_expiration_time = time.gmtime(time.time() + (self.expiration * 60))
+ c[self.cookie_name]['expires'] = time.strftime("%a, %d-%b-%Y %H:%M:%S GMT", gmt_expiration_time)
+
+ name, value = str(c).split(': ', 1)
+ return (name, value)
+
+ def close(self):
+ if self.session is not None:
+ self.session.close()
+
+
+last_cleanup = None
+cleaning_up = False
+cleanup_cycle = datetime.timedelta(seconds=15*60) #15 min
+
+class FileSession(object):
+
+ def __init__(self, sid, create=False, session_file_path=tempfile.gettempdir(),
+ chmod=None,
+ expiration=2880, # in minutes: 48 hours
+ ):
+ if chmod and isinstance(chmod, basestring):
+ chmod = int(chmod, 8)
+ self.chmod = chmod
+ if not sid:
+ # Invalid...
+ raise KeyError
+ self.session_file_path = session_file_path
+ self.sid = sid
+ if not create:
+ if not os.path.exists(self.filename()):
+ raise KeyError
+ self._data = None
+
+ self.expiration = expiration
+
+
+ def filename(self):
+ return os.path.join(self.session_file_path, self.sid)
+
+ def data(self):
+ if self._data is not None:
+ return self._data
+ if os.path.exists(self.filename()):
+ f = open(self.filename(), 'rb')
+ self._data = cPickle.load(f)
+ f.close()
+ else:
+ self._data = {}
+ return self._data
+
+ def close(self):
+ if self._data is not None:
+ filename = self.filename()
+ exists = os.path.exists(filename)
+ if not self._data:
+ if exists:
+ os.unlink(filename)
+ else:
+ f = open(filename, 'wb')
+ cPickle.dump(self._data, f)
+ f.close()
+ if not exists and self.chmod:
+ os.chmod(filename, self.chmod)
+
+ def _clean_up(self):
+ global cleaning_up
+ try:
+ exp_time = datetime.timedelta(seconds=self.expiration*60)
+ now = datetime.datetime.now()
+
+ #Open every session and check that it isn't too old
+ for root, dirs, files in os.walk(self.session_file_path):
+ for f in files:
+ self._clean_up_file(f, exp_time=exp_time, now=now)
+ finally:
+ cleaning_up = False
+
+ def _clean_up_file(self, f, exp_time, now):
+ t = f.split("-")
+ if len(t) != 2:
+ return
+ t = t[0]
+ try:
+ sess_time = datetime.datetime(
+ int(t[0:4]),
+ int(t[4:6]),
+ int(t[6:8]),
+ int(t[8:10]),
+ int(t[10:12]),
+ int(t[12:14]))
+ except ValueError:
+ # Probably not a session file at all
+ return
+
+ if sess_time + exp_time < now:
+ os.remove(os.path.join(self.session_file_path, f))
+
+ def clean_up(self):
+ global last_cleanup, cleanup_cycle, cleaning_up
+ now = datetime.datetime.now()
+
+ if cleaning_up:
+ return
+
+ if not last_cleanup or last_cleanup + cleanup_cycle < now:
+ if not cleaning_up:
+ cleaning_up = True
+ try:
+ last_cleanup = now
+ t = threading.Thread(target=self._clean_up)
+ t.start()
+ except:
+ # Normally _clean_up should set cleaning_up
+ # to false, but if something goes wrong starting
+ # it...
+ cleaning_up = False
+ raise
+
+class _NoDefault(object):
+ def __repr__(self):
+ return '<dynamic default>'
+NoDefault = _NoDefault()
+
+def make_session_middleware(
+ app, global_conf,
+ session_expiration=NoDefault,
+ expiration=NoDefault,
+ cookie_name=NoDefault,
+ session_file_path=NoDefault,
+ chmod=NoDefault):
+ """
+ Adds a middleware that handles sessions for your applications.
+ The session is a peristent dictionary. To get this dictionary
+ in your application, use ``environ['paste.session.factory']()``
+ which returns this persistent dictionary.
+
+ Configuration:
+
+ session_expiration:
+ The time each session lives, in minutes. This controls
+ the cookie expiration. Default 12 hours.
+
+ expiration:
+ The time each session lives on disk. Old sessions are
+ culled from disk based on this. Default 48 hours.
+
+ cookie_name:
+ The cookie name used to track the session. Use different
+ names to avoid session clashes.
+
+ session_file_path:
+ Sessions are put in this location, default /tmp.
+
+ chmod:
+ The octal chmod you want to apply to new sessions (e.g., 660
+ to make the sessions group readable/writable)
+
+ Each of these also takes from the global configuration. cookie_name
+ and chmod take from session_cookie_name and session_chmod
+ """
+ if session_expiration is NoDefault:
+ session_expiration = global_conf.get('session_expiration', 60*12)
+ session_expiration = int(session_expiration)
+ if expiration is NoDefault:
+ expiration = global_conf.get('expiration', 60*48)
+ expiration = int(expiration)
+ if cookie_name is NoDefault:
+ cookie_name = global_conf.get('session_cookie_name', '_SID_')
+ if session_file_path is NoDefault:
+ session_file_path = global_conf.get('session_file_path', '/tmp')
+ if chmod is NoDefault:
+ chmod = global_conf.get('session_chmod', None)
+ return SessionMiddleware(
+ app, session_expiration=session_expiration,
+ expiration=expiration, cookie_name=cookie_name,
+ session_file_path=session_file_path, chmod=chmod)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/transaction.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/transaction.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/transaction.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,120 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware related to transactions and database connections.
+
+At this time it is very basic; but will eventually sprout all that
+two-phase commit goodness that I don't need.
+
+.. note::
+
+ This is experimental, and will change in the future.
+"""
+from paste.httpexceptions import HTTPException
+from wsgilib import catch_errors
+
+class TransactionManagerMiddleware(object):
+
+ def __init__(self, application):
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ environ['paste.transaction_manager'] = manager = Manager()
+ # This makes sure nothing else traps unexpected exceptions:
+ environ['paste.throw_errors'] = True
+ return catch_errors(self.application, environ, start_response,
+ error_callback=manager.error,
+ ok_callback=manager.finish)
+
+class Manager(object):
+
+ def __init__(self):
+ self.aborted = False
+ self.transactions = []
+
+ def abort(self):
+ self.aborted = True
+
+ def error(self, exc_info):
+ self.aborted = True
+ self.finish()
+
+ def finish(self):
+ for trans in self.transactions:
+ if self.aborted:
+ trans.rollback()
+ else:
+ trans.commit()
+
+
+class ConnectionFactory(object):
+ """
+ Provides a callable interface for connecting to ADBAPI databases in
+ a WSGI style (using the environment). More advanced connection
+ factories might use the REMOTE_USER and/or other environment
+ variables to make the connection returned depend upon the request.
+ """
+ def __init__(self, module, *args, **kwargs):
+ #assert getattr(module,'threadsaftey',0) > 0
+ self.module = module
+ self.args = args
+ self.kwargs = kwargs
+
+ # deal with database string quoting issues
+ self.quote = lambda s: "'%s'" % s.replace("'","''")
+ if hasattr(self.module,'PgQuoteString'):
+ self.quote = self.module.PgQuoteString
+
+ def __call__(self, environ=None):
+ conn = self.module.connect(*self.args, **self.kwargs)
+ conn.__dict__['module'] = self.module
+ conn.__dict__['quote'] = self.quote
+ return conn
+
+def BasicTransactionHandler(application, factory):
+ """
+ Provides a simple mechanism for starting a transaction based on the
+ factory; and for either committing or rolling back the transaction
+ depending on the result. It checks for the response's current
+ status code either through the latest call to start_response; or
+ through a HTTPException's code. If it is a 100, 200, or 300; the
+ transaction is committed; otherwise it is rolled back.
+ """
+ def basic_transaction(environ, start_response):
+ conn = factory(environ)
+ environ['paste.connection'] = conn
+ should_commit = [500]
+ def finalizer(exc_info=None):
+ if exc_info:
+ if isinstance(exc_info[1], HTTPException):
+ should_commit.append(exc_info[1].code)
+ if should_commit.pop() < 400:
+ conn.commit()
+ else:
+ try:
+ conn.rollback()
+ except:
+ # TODO: check if rollback has already happened
+ return
+ conn.close()
+ def basictrans_start_response(status, headers, exc_info = None):
+ should_commit.append(int(status.split(" ")[0]))
+ return start_response(status, headers, exc_info)
+ return catch_errors(application, environ, basictrans_start_response,
+ finalizer, finalizer)
+ return basic_transaction
+
+__all__ = ['ConnectionFactory', 'BasicTransactionHandler']
+
+if '__main__' == __name__ and False:
+ from pyPgSQL import PgSQL
+ factory = ConnectionFactory(PgSQL, database="testing")
+ conn = factory()
+ curr = conn.cursor()
+ curr.execute("SELECT now(), %s" % conn.quote("B'n\\'gles"))
+ (time, bing) = curr.fetchone()
+ print bing, time
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/translogger.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/translogger.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/translogger.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,121 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Middleware for logging requests, using Apache combined log format
+"""
+
+import logging
+import time
+import urllib
+
+class TransLogger(object):
+ """
+ This logging middleware will log all requests as they go through.
+ They are, by default, sent to a logger named ``'wsgi'`` at the
+ INFO level.
+
+ If ``setup_console_handler`` is true, then messages for the named
+ logger will be sent to the console.
+ """
+
+ format = ('%(REMOTE_ADDR)s - %(REMOTE_USER)s [%(time)s] '
+ '"%(REQUEST_METHOD)s %(REQUEST_URI)s %(HTTP_VERSION)s" '
+ '%(status)s %(bytes)s "%(HTTP_REFERER)s" "%(HTTP_USER_AGENT)s"')
+
+ def __init__(self, application,
+ logger=None,
+ format=None,
+ logging_level=logging.INFO,
+ logger_name='wsgi',
+ setup_console_handler=True,
+ set_logger_level=logging.DEBUG):
+ if format is not None:
+ self.format = format
+ self.application = application
+ self.logging_level = logging_level
+ self.logger_name = logger_name
+ if logger is None:
+ self.logger = logging.getLogger(self.logger_name)
+ if setup_console_handler:
+ console = logging.StreamHandler()
+ console.setLevel(logging.DEBUG)
+ # We need to control the exact format:
+ console.setFormatter(logging.Formatter('%(message)s'))
+ self.logger.addHandler(console)
+ self.logger.propagate = False
+ if set_logger_level is not None:
+ self.logger.setLevel(set_logger_level)
+ else:
+ self.logger = logger
+
+ def __call__(self, environ, start_response):
+ start = time.localtime()
+ req_uri = urllib.quote(environ.get('SCRIPT_NAME', '')
+ + environ.get('PATH_INFO', ''))
+ if environ.get('QUERY_STRING'):
+ req_uri += '?'+environ['QUERY_STRING']
+ method = environ['REQUEST_METHOD']
+ def replacement_start_response(status, headers, exc_info=None):
+ # @@: Ideally we would count the bytes going by if no
+ # content-length header was provided; but that does add
+ # some overhead, so at least for now we'll be lazy.
+ bytes = None
+ for name, value in headers:
+ if name.lower() == 'content-length':
+ bytes = value
+ self.write_log(environ, method, req_uri, start, status, bytes)
+ return start_response(status, headers)
+ return self.application(environ, replacement_start_response)
+
+ def write_log(self, environ, method, req_uri, start, status, bytes):
+ if bytes is None:
+ bytes = '-'
+ if time.daylight:
+ offset = time.altzone / 60 / 60 * -100
+ else:
+ offset = time.timezone / 60 / 60 * -100
+ if offset >= 0:
+ offset = "+%0.4d" % (offset)
+ elif offset < 0:
+ offset = "%0.4d" % (offset)
+ remote_addr = '-'
+ if environ.get('HTTP_X_FORWARDED_FOR'):
+ remote_addr = environ['HTTP_X_FORWARDED_FOR']
+ elif environ.get('REMOTE_ADDR'):
+ remote_addr = environ['REMOTE_ADDR']
+ d = {
+ 'REMOTE_ADDR': remote_addr,
+ 'REMOTE_USER': environ.get('REMOTE_USER') or '-',
+ 'REQUEST_METHOD': method,
+ 'REQUEST_URI': req_uri,
+ 'HTTP_VERSION': environ.get('SERVER_PROTOCOL'),
+ 'time': time.strftime('%d/%b/%Y:%H:%M:%S ', start) + offset,
+ 'status': status.split(None, 1)[0],
+ 'bytes': bytes,
+ 'HTTP_REFERER': environ.get('HTTP_REFERER', '-'),
+ 'HTTP_USER_AGENT': environ.get('HTTP_USER_AGENT', '-'),
+ }
+ message = self.format % d
+ self.logger.log(self.logging_level, message)
+
+def make_filter(
+ app, global_conf,
+ logger_name='wsgi',
+ format=None,
+ logging_level=logging.INFO,
+ setup_console_handler=True,
+ set_logger_level=logging.DEBUG):
+ from paste.util.converters import asbool
+ if isinstance(logging_level, basestring):
+ logging_level = logging._levelNames[logging_level]
+ if isinstance(set_logger_level, basestring):
+ set_logger_level = logging._levelNames[set_logger_level]
+ return TransLogger(
+ app,
+ format=format or None,
+ logging_level=logging_level,
+ logger_name=logger_name,
+ setup_console_handler=asbool(setup_console_handler),
+ set_logger_level=set_logger_level)
+
+make_filter.__doc__ = TransLogger.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/url.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/url.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/url.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,475 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+This module implements a class for handling URLs.
+"""
+import urllib
+import cgi
+from paste import request
+# Imported lazily from FormEncode:
+variabledecode = None
+
+__all__ = ["URL", "Image"]
+
+def html_quote(v):
+ if v is None:
+ return ''
+ return cgi.escape(str(v), 1)
+
+def url_quote(v):
+ if v is None:
+ return ''
+ return urllib.quote(str(v))
+
+url_unquote = urllib.unquote
+
+def js_repr(v):
+ if v is None:
+ return 'null'
+ elif v is False:
+ return 'false'
+ elif v is True:
+ return 'true'
+ elif isinstance(v, list):
+ return '[%s]' % ', '.join(map(js_repr, v))
+ elif isinstance(v, dict):
+ return '{%s}' % ', '.join(
+ ['%s: %s' % (js_repr(key), js_repr(value))
+ for key, value in v])
+ elif isinstance(v, str):
+ return repr(v)
+ elif isinstance(v, unicode):
+ # @@: how do you do Unicode literals in Javascript?
+ return repr(v.encode('UTF-8'))
+ elif isinstance(v, (float, int)):
+ return repr(v)
+ elif isinstance(v, long):
+ return repr(v).lstrip('L')
+ elif hasattr(v, '__js_repr__'):
+ return v.__js_repr__()
+ else:
+ raise ValueError(
+ "I don't know how to turn %r into a Javascript representation"
+ % v)
+
+class URLResource(object):
+
+ """
+ This is an abstract superclass for different kinds of URLs
+ """
+
+ default_params = {}
+
+ def __init__(self, url, vars=None, attrs=None,
+ params=None):
+ self.url = url or '/'
+ self.vars = vars or []
+ self.attrs = attrs or {}
+ self.params = self.default_params.copy()
+ self.original_params = params or {}
+ if params:
+ self.params.update(params)
+
+ #@classmethod
+ def from_environ(cls, environ, with_query_string=True,
+ with_path_info=True, script_name=None,
+ path_info=None, querystring=None):
+ url = request.construct_url(
+ environ, with_query_string=False,
+ with_path_info=with_path_info, script_name=script_name,
+ path_info=path_info)
+ if with_query_string:
+ if querystring is None:
+ vars = request.parse_querystring(environ)
+ else:
+ vars = cgi.parse_qsl(
+ querystring,
+ keep_blank_values=True,
+ strict_parsing=False)
+ else:
+ vars = None
+ v = cls(url, vars=vars)
+ return v
+
+ from_environ = classmethod(from_environ)
+
+ def __call__(self, *args, **kw):
+ res = self._add_positional(args)
+ res = res._add_vars(kw)
+ return res
+
+ def __getitem__(self, item):
+ if '=' in item:
+ name, value = item.split('=', 1)
+ return self._add_vars({url_unquote(name): url_unquote(value)})
+ return self._add_positional((item,))
+
+ def attr(self, **kw):
+ for key in kw.keys():
+ if key.endswith('_'):
+ kw[key[:-1]] = kw[key]
+ del kw[key]
+ new_attrs = self.attrs.copy()
+ new_attrs.update(kw)
+ return self.__class__(self.url, vars=self.vars,
+ attrs=new_attrs,
+ params=self.original_params)
+
+ def param(self, **kw):
+ new_params = self.original_params.copy()
+ new_params.update(kw)
+ return self.__class__(self.url, vars=self.vars,
+ attrs=self.attrs,
+ params=new_params)
+
+ def coerce_vars(self, vars):
+ global variabledecode
+ need_variable_encode = False
+ for key, value in vars.items():
+ if isinstance(value, dict):
+ need_variable_encode = True
+ if key.endswith('_'):
+ vars[key[:-1]] = vars[key]
+ del vars[key]
+ if need_variable_encode:
+ if variabledecode is None:
+ from formencode import variabledecode
+ vars = variabledecode.variable_encode(vars)
+ return vars
+
+
+ def var(self, **kw):
+ kw = self.coerce_vars(kw)
+ new_vars = self.vars + kw.items()
+ return self.__class__(self.url, vars=new_vars,
+ attrs=self.attrs,
+ params=self.original_params)
+
+ def setvar(self, **kw):
+ """
+ Like ``.var(...)``, except overwrites keys, where .var simply
+ extends the keys. Setting a variable to None here will
+ effectively delete it.
+ """
+ kw = self.coerce_vars(kw)
+ new_vars = []
+ for name, values in self.vars:
+ if name in kw:
+ continue
+ new_vars.append((name, values))
+ new_vars.extend(kw.items())
+ return self.__class__(self.url, vars=new_vars,
+ attrs=self.attrs,
+ params=self.original_params)
+
+ def setvars(self, **kw):
+ """
+ Creates a copy of this URL, but with all the variables set/reset
+ (like .setvar(), except clears past variables at the same time)
+ """
+ return self.__class__(self.url, vars=kw.items(),
+ attrs=self.attrs,
+ params=self.original_params)
+
+ def addpath(self, *paths):
+ u = self
+ for path in paths:
+ path = str(path).lstrip('/')
+ new_url = u.url
+ if not new_url.endswith('/'):
+ new_url += '/'
+ u = u.__class__(new_url+path, vars=u.vars,
+ attrs=u.attrs,
+ params=u.original_params)
+ return u
+
+ __div__ = addpath
+
+ def become(self, OtherClass):
+ return OtherClass(self.url, vars=self.vars,
+ attrs=self.attrs,
+ params=self.original_params)
+
+ def href__get(self):
+ s = self.url
+ if self.vars:
+ s += '?'
+ vars = []
+ for name, val in self.vars:
+ if isinstance(val, (list, tuple)):
+ val = [v for v in val if v is not None]
+ elif val is None:
+ continue
+ vars.append((name, val))
+ s += urllib.urlencode(vars, True)
+ return s
+
+ href = property(href__get)
+
+ def __repr__(self):
+ base = '<%s %s' % (self.__class__.__name__,
+ self.href or "''")
+ if self.attrs:
+ base += ' attrs(%s)' % (
+ ' '.join(['%s="%s"' % (html_quote(n), html_quote(v))
+ for n, v in self.attrs.items()]))
+ if self.original_params:
+ base += ' params(%s)' % (
+ ', '.join(['%s=%r' % (n, v)
+ for n, v in self.attrs.items()]))
+ return base + '>'
+
+ def html__get(self):
+ if not self.params.get('tag'):
+ raise ValueError(
+ "You cannot get the HTML of %r until you set the "
+ "'tag' param'" % self)
+ content = self._get_content()
+ tag = '<%s' % self.params.get('tag')
+ attrs = ' '.join([
+ '%s="%s"' % (html_quote(n), html_quote(v))
+ for n, v in self._html_attrs()])
+ if attrs:
+ tag += ' ' + attrs
+ tag += self._html_extra()
+ if content is None:
+ return tag + ' />'
+ else:
+ return '%s>%s</%s>' % (tag, content, self.params.get('tag'))
+
+ html = property(html__get)
+
+ def _html_attrs(self):
+ return self.attrs.items()
+
+ def _html_extra(self):
+ return ''
+
+ def _get_content(self):
+ """
+ Return the content for a tag (for self.html); return None
+ for an empty tag (like ``<img />``)
+ """
+ raise NotImplementedError
+
+ def _add_vars(self, vars):
+ raise NotImplementedError
+
+ def _add_positional(self, args):
+ raise NotImplementedError
+
+class URL(URLResource):
+
+ r"""
+ >>> u = URL('http://localhost')
+ >>> u
+ <URL http://localhost>
+ >>> u = u['view']
+ >>> str(u)
+ 'http://localhost/view'
+ >>> u['//foo'].param(content='view').html
+ '<a href="http://localhost/view/foo">view</a>'
+ >>> u.param(confirm='Really?', content='goto').html
+ '<a href="http://localhost/view" onclick="return confirm(\'Really?\')">goto</a>'
+ >>> u(title='See "it"', content='goto').html
+ '<a href="http://localhost/view?title=See+%22it%22">goto</a>'
+ >>> u('another', var='fuggetaboutit', content='goto').html
+ '<a href="http://localhost/view/another?var=fuggetaboutit">goto</a>'
+ >>> u.attr(content='goto').html
+ Traceback (most recent call last):
+ ....
+ ValueError: You must give a content param to <URL http://localhost/view attrs(content="goto")> generate anchor tags
+ >>> str(u['foo=bar%20stuff'])
+ 'http://localhost/view?foo=bar+stuff'
+ """
+
+ default_params = {'tag': 'a'}
+
+ def __str__(self):
+ return self.href
+
+ def _get_content(self):
+ if not self.params.get('content'):
+ raise ValueError(
+ "You must give a content param to %r generate anchor tags"
+ % self)
+ return self.params['content']
+
+ def _add_vars(self, vars):
+ url = self
+ for name in ('confirm', 'content'):
+ if name in vars:
+ url = url.param(**{name: vars.pop(name)})
+ if 'target' in vars:
+ url = url.attr(target=vars.pop('target'))
+ return url.var(**vars)
+
+ def _add_positional(self, args):
+ return self.addpath(*args)
+
+ def _html_attrs(self):
+ attrs = self.attrs.items()
+ attrs.insert(0, ('href', self.href))
+ if self.params.get('confirm'):
+ attrs.append(('onclick', 'return confirm(%s)'
+ % js_repr(self.params['confirm'])))
+ return attrs
+
+ def onclick_goto__get(self):
+ return 'location.href=%s; return false' % js_repr(self.href)
+
+ onclick_goto = property(onclick_goto__get)
+
+ def button__get(self):
+ return self.become(Button)
+
+ button = property(button__get)
+
+ def js_popup__get(self):
+ return self.become(JSPopup)
+
+ js_popup = property(js_popup__get)
+
+class Image(URLResource):
+
+ r"""
+ >>> i = Image('/images')
+ >>> i = i / '/foo.png'
+ >>> i.html
+ '<img src="/images/foo.png" />'
+ >>> str(i['alt=foo'])
+ '<img src="/images/foo.png" alt="foo" />'
+ >>> i.href
+ '/images/foo.png'
+ """
+
+ default_params = {'tag': 'img'}
+
+ def __str__(self):
+ return self.html
+
+ def _get_content(self):
+ return None
+
+ def _add_vars(self, vars):
+ return self.attr(**vars)
+
+ def _add_positional(self, args):
+ return self.addpath(*args)
+
+ def _html_attrs(self):
+ attrs = self.attrs.items()
+ attrs.insert(0, ('src', self.href))
+ return attrs
+
+class Button(URLResource):
+
+ r"""
+ >>> u = URL('/')
+ >>> u = u / 'delete'
+ >>> b = u.button['confirm=Sure?'](id=5, content='del')
+ >>> str(b)
+ '<button onclick="if (confirm(\'Sure?\')) {location.href=\'/delete?id=5\'}; return false">del</button>'
+ """
+
+ default_params = {'tag': 'button'}
+
+ def __str__(self):
+ return self.html
+
+ def _get_content(self):
+ if self.params.get('content'):
+ return self.params['content']
+ if self.attrs.get('value'):
+ return self.attrs['content']
+ # @@: Error?
+ return None
+
+ def _add_vars(self, vars):
+ button = self
+ if 'confirm' in vars:
+ button = button.param(confirm=vars.pop('confirm'))
+ if 'content' in vars:
+ button = button.param(content=vars.pop('content'))
+ return button.var(**vars)
+
+ def _add_positional(self, args):
+ return self.addpath(*args)
+
+ def _html_attrs(self):
+ attrs = self.attrs.items()
+ onclick = 'location.href=%s' % js_repr(self.href)
+ if self.params.get('confirm'):
+ onclick = 'if (confirm(%s)) {%s}' % (
+ js_repr(self.params['confirm']), onclick)
+ onclick += '; return false'
+ attrs.insert(0, ('onclick', onclick))
+ return attrs
+
+class JSPopup(URLResource):
+
+ r"""
+ >>> u = URL('/')
+ >>> u = u / 'view'
+ >>> j = u.js_popup(content='view')
+ >>> j.html
+ '<a href="/view" onclick="window.open(\'/view\', \'_blank\'); return false" target="_blank">view</a>'
+ """
+
+ default_params = {'tag': 'a', 'target': '_blank'}
+
+ def _add_vars(self, vars):
+ button = self
+ for var in ('width', 'height', 'stripped', 'content'):
+ if var in vars:
+ button = button.param(**{var: vars.pop(var)})
+ return button.var(**vars)
+
+ def _window_args(self):
+ p = self.params
+ features = []
+ if p.get('stripped'):
+ p['location'] = p['status'] = p['toolbar'] = '0'
+ for param in 'channelmode directories fullscreen location menubar resizable scrollbars status titlebar'.split():
+ if param not in p:
+ continue
+ v = p[param]
+ if v not in ('yes', 'no', '1', '0'):
+ if v:
+ v = '1'
+ else:
+ v = '0'
+ features.append('%s=%s' % (param, v))
+ for param in 'height left top width':
+ if not p.get(param):
+ continue
+ features.append('%s=%s' % (param, p[param]))
+ args = [self.href, p['target']]
+ if features:
+ args.append(','.join(features))
+ return ', '.join(map(js_repr, args))
+
+ def _html_attrs(self):
+ attrs = self.attrs.items()
+ onclick = ('window.open(%s); return false'
+ % self._window_args())
+ attrs.insert(0, ('target', self.params['target']))
+ attrs.insert(0, ('onclick', onclick))
+ attrs.insert(0, ('href', self.href))
+ return attrs
+
+ def _get_content(self):
+ if not self.params.get('content'):
+ raise ValueError(
+ "You must give a content param to %r generate anchor tags"
+ % self)
+ return self.params['content']
+
+ def _add_positional(self, args):
+ return self.addpath(*args)
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlmap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlmap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlmap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,250 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Map URL prefixes to WSGI applications. See ``URLMap``
+"""
+
+from UserDict import DictMixin
+import re
+import os
+import cgi
+from paste import httpexceptions
+
+__all__ = ['URLMap', 'PathProxyURLMap']
+
+def urlmap_factory(loader, global_conf, **local_conf):
+ if 'not_found_app' in local_conf:
+ not_found_app = local_conf.pop('not_found_app')
+ else:
+ not_found_app = global_conf.get('not_found_app')
+ if not_found_app:
+ not_found_app = loader.get_app(not_found_app, global_conf=global_conf)
+ urlmap = URLMap(not_found_app=not_found_app)
+ for path, app_name in local_conf.items():
+ path = parse_path_expression(path)
+ app = loader.get_app(app_name, global_conf=global_conf)
+ urlmap[path] = app
+ return urlmap
+
+def parse_path_expression(path):
+ """
+ Parses a path expression like 'domain foobar.com port 20 /' or
+ just '/foobar' for a path alone. Returns as an address that
+ URLMap likes.
+ """
+ parts = path.split()
+ domain = port = path = None
+ while parts:
+ if parts[0] == 'domain':
+ parts.pop(0)
+ if not parts:
+ raise ValueError("'domain' must be followed with a domain name")
+ if domain:
+ raise ValueError("'domain' given twice")
+ domain = parts.pop(0)
+ elif parts[0] == 'port':
+ parts.pop(0)
+ if not parts:
+ raise ValueError("'port' must be followed with a port number")
+ if port:
+ raise ValueError("'port' given twice")
+ port = parts.pop(0)
+ else:
+ if path:
+ raise ValueError("more than one path given (have %r, got %r)"
+ % (path, parts[0]))
+ path = parts.pop(0)
+ s = ''
+ if domain:
+ s = 'http://%s' % domain
+ if port:
+ if not domain:
+ raise ValueError("If you give a port, you must also give a domain")
+ s += ':' + port
+ if path:
+ if s:
+ s += '/'
+ s += path
+ return s
+
+class URLMap(DictMixin):
+
+ """
+ URLMap instances are dictionary-like object that dispatch to one
+ of several applications based on the URL.
+
+ The dictionary keys are URLs to match (like
+ ``PATH_INFO.startswith(url)``), and the values are applications to
+ dispatch to. URLs are matched most-specific-first, i.e., longest
+ URL first. The ``SCRIPT_NAME`` and ``PATH_INFO`` environmental
+ variables are adjusted to indicate the new context.
+
+ URLs can also include domains, like ``http://blah.com/foo``, or as
+ tuples ``('blah.com', '/foo')``. This will match domain names; without
+ the ``http://domain`` or with a domain of ``None`` any domain will be
+ matched (so long as no other explicit domain matches). """
+
+ def __init__(self, not_found_app=None):
+ self.applications = []
+ if not not_found_app:
+ not_found_app = self.not_found_app
+ self.not_found_application = not_found_app
+
+ norm_url_re = re.compile('//+')
+ domain_url_re = re.compile('^(http|https)://')
+
+ def not_found_app(self, environ, start_response):
+ mapper = environ.get('paste.urlmap_object')
+ if mapper:
+ matches = [p for p, a in mapper.applications]
+ extra = 'defined apps: %s' % (
+ ',\n '.join(map(repr, matches)))
+ else:
+ extra = ''
+ extra += '\nSCRIPT_NAME: %r' % environ.get('SCRIPT_NAME')
+ extra += '\nPATH_INFO: %r' % environ.get('PATH_INFO')
+ extra += '\nHTTP_HOST: %r' % environ.get('HTTP_HOST')
+ app = httpexceptions.HTTPNotFound(
+ environ['PATH_INFO'],
+ comment=cgi.escape(extra)).wsgi_application
+ return app(environ, start_response)
+
+ def normalize_url(self, url, trim=True):
+ if isinstance(url, (list, tuple)):
+ domain = url[0]
+ url = self.normalize_url(url[1])[1]
+ return domain, url
+ assert (not url or url.startswith('/')
+ or self.domain_url_re.search(url)), (
+ "URL fragments must start with / or http:// (you gave %r)" % url)
+ match = self.domain_url_re.search(url)
+ if match:
+ url = url[match.end():]
+ if '/' in url:
+ domain, url = url.split('/', 1)
+ url = '/' + url
+ else:
+ domain, url = url, ''
+ else:
+ domain = None
+ url = self.norm_url_re.sub('/', url)
+ if trim:
+ url = url.rstrip('/')
+ return domain, url
+
+ def sort_apps(self):
+ """
+ Make sure applications are sorted with longest URLs first
+ """
+ def key(app_desc):
+ (domain, url), app = app_desc
+ if not domain:
+ # Make sure empty domains sort last:
+ return '\xff', -len(url)
+ else:
+ return domain, -len(url)
+ apps = [(key(desc), desc) for desc in self.applications]
+ apps.sort()
+ self.applications = [desc for (sortable, desc) in apps]
+
+ def __setitem__(self, url, app):
+ if app is None:
+ try:
+ del self[url]
+ except KeyError:
+ pass
+ return
+ dom_url = self.normalize_url(url)
+ if dom_url in self:
+ del self[dom_url]
+ self.applications.append((dom_url, app))
+ self.sort_apps()
+
+ def __getitem__(self, url):
+ dom_url = self.normalize_url(url)
+ for app_url, app in self.applications:
+ if app_url == dom_url:
+ return app
+ raise KeyError(
+ "No application with the url %r (domain: %r; existing: %s)"
+ % (url[1], url[0] or '*', self.applications))
+
+ def __delitem__(self, url):
+ url = self.normalize_url(url)
+ for app_url, app in self.applications:
+ if app_url == url:
+ self.applications.remove((app_url, app))
+ break
+ else:
+ raise KeyError(
+ "No application with the url %r" % (url,))
+
+ def keys(self):
+ return [app_url for app_url, app in self.applications]
+
+ def __call__(self, environ, start_response):
+ host = environ.get('HTTP_HOST', environ.get('SERVER_NAME')).lower()
+ if ':' in host:
+ host, port = host.split(':', 1)
+ else:
+ if environ['wsgi.url_scheme'] == 'http':
+ port = '80'
+ else:
+ port = '443'
+ path_info = environ.get('PATH_INFO')
+ path_info = self.normalize_url(path_info, False)[1]
+ for (domain, app_url), app in self.applications:
+ if domain and domain != host and domain != host+':'+port:
+ continue
+ if (path_info == app_url
+ or path_info.startswith(app_url + '/')):
+ environ['SCRIPT_NAME'] += app_url
+ environ['PATH_INFO'] = path_info[len(app_url):]
+ return app(environ, start_response)
+ environ['paste.urlmap_object'] = self
+ return self.not_found_application(environ, start_response)
+
+
+class PathProxyURLMap(object):
+
+ """
+ This is a wrapper for URLMap that catches any strings that
+ are passed in as applications; these strings are treated as
+ filenames (relative to `base_path`) and are passed to the
+ callable `builder`, which will return an application.
+
+ This is intended for cases when configuration files can be
+ treated as applications.
+
+ `base_paste_url` is the URL under which all applications added through
+ this wrapper must go. Use ``""`` if you want this to not
+ change incoming URLs.
+ """
+
+ def __init__(self, map, base_paste_url, base_path, builder):
+ self.map = map
+ self.base_paste_url = self.map.normalize_url(base_paste_url)
+ self.base_path = base_path
+ self.builder = builder
+
+ def __setitem__(self, url, app):
+ if isinstance(app, (str, unicode)):
+ app_fn = os.path.join(self.base_path, app)
+ app = self.builder(app_fn)
+ url = self.map.normalize_url(url)
+ # @@: This means http://foo.com/bar will potentially
+ # match foo.com, but /base_paste_url/bar, which is unintuitive
+ url = (url[0] or self.base_paste_url[0],
+ self.base_paste_url[1] + url[1])
+ self.map[url] = app
+
+ def __getattr__(self, attr):
+ return getattr(self.map, attr)
+
+ # This is really the only settable attribute
+ def not_found_application__get(self):
+ return self.map.not_found_application
+ def not_found_application__set(self, value):
+ self.map.not_found_application = value
+ not_found_application = property(not_found_application__get,
+ not_found_application__set)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlparser.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlparser.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/urlparser.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,638 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+WSGI applications that parse the URL and dispatch to on-disk resources
+"""
+
+import os
+import sys
+import imp
+import mimetypes
+try:
+ import pkg_resources
+except ImportError:
+ pkg_resources = None
+from paste import request
+from paste import fileapp
+from paste.util import import_string
+from paste import httpexceptions
+from httpheaders import ETAG
+from paste.util import converters
+
+class NoDefault(object):
+ pass
+
+__all__ = ['URLParser', 'StaticURLParser', 'PkgResourcesParser']
+
+class URLParser(object):
+
+ """
+ WSGI middleware
+
+ Application dispatching, based on URL. An instance of `URLParser` is
+ an application that loads and delegates to other applications. It
+ looks for files in its directory that match the first part of
+ PATH_INFO; these may have an extension, but are not required to have
+ one, in which case the available files are searched to find the
+ appropriate file. If it is ambiguous, a 404 is returned and an error
+ logged.
+
+ By default there is a constructor for .py files that loads the module,
+ and looks for an attribute ``application``, which is a ready
+ application object, or an attribute that matches the module name,
+ which is a factory for building applications, and is called with no
+ arguments.
+
+ URLParser will also look in __init__.py for special overrides.
+ These overrides are:
+
+ ``urlparser_hook(environ)``
+ This can modify the environment. Its return value is ignored,
+ and it cannot be used to change the response in any way. You
+ *can* use this, for example, to manipulate SCRIPT_NAME/PATH_INFO
+ (try to keep them consistent with the original URL -- but
+ consuming PATH_INFO and moving that to SCRIPT_NAME is ok).
+
+ ``urlparser_wrap(environ, start_response, app)``:
+ After URLParser finds the application, it calls this function
+ (if present). If this function doesn't call
+ ``app(environ, start_response)`` then the application won't be
+ called at all! This can be used to allocate resources (with
+ ``try:finally:``) or otherwise filter the output of the
+ application.
+
+ ``not_found_hook(environ, start_response)``:
+ If no file can be found (*in this directory*) to match the
+ request, then this WSGI application will be called. You can
+ use this to change the URL and pass the request back to
+ URLParser again, or on to some other application. This
+ doesn't catch all ``404 Not Found`` responses, just missing
+ files.
+
+ ``application(environ, start_response)``:
+ This basically overrides URLParser completely, and the given
+ application is used for all requests. ``urlparser_wrap`` and
+ ``urlparser_hook`` are still called, but the filesystem isn't
+ searched in any way.
+ """
+
+ parsers_by_directory = {}
+
+ # This is lazily initialized
+ init_module = NoDefault
+
+ global_constructors = {}
+
+ def __init__(self, global_conf,
+ directory, base_python_name,
+ index_names=NoDefault,
+ hide_extensions=NoDefault,
+ ignore_extensions=NoDefault,
+ constructors=None,
+ **constructor_conf):
+ """
+ Create a URLParser object that looks at `directory`.
+ `base_python_name` is the package that this directory
+ represents, thus any Python modules in this directory will
+ be given names under this package.
+ """
+ if global_conf:
+ import warnings
+ warnings.warn(
+ 'The global_conf argument to URLParser is deprecated; '
+ 'either pass in None or {}, or use make_url_parser',
+ DeprecationWarning)
+ else:
+ global_conf = {}
+ if os.path.sep != '/':
+ directory = directory.replace(os.path.sep, '/')
+ self.directory = directory
+ self.base_python_name = base_python_name
+ # This logic here should be deprecated since it is in
+ # make_url_parser
+ if index_names is NoDefault:
+ index_names = global_conf.get(
+ 'index_names', ('index', 'Index', 'main', 'Main'))
+ self.index_names = converters.aslist(index_names)
+ if hide_extensions is NoDefault:
+ hide_extensions = global_conf.get(
+ 'hide_extensions', ('.pyc', '.bak', '.py~', '.pyo'))
+ self.hide_extensions = converters.aslist(hide_extensions)
+ if ignore_extensions is NoDefault:
+ ignore_extensions = global_conf.get(
+ 'ignore_extensions', ())
+ self.ignore_extensions = converters.aslist(ignore_extensions)
+ self.constructors = self.global_constructors.copy()
+ if constructors:
+ self.constructors.update(constructors)
+ # @@: Should we also check the global options for constructors?
+ for name, value in constructor_conf.items():
+ if not name.startswith('constructor '):
+ raise ValueError(
+ "Only extra configuration keys allowed are "
+ "'constructor .ext = import_expr'; you gave %r "
+ "(=%r)" % (name, value))
+ ext = name[len('constructor '):].strip()
+ if isinstance(value, (str, unicode)):
+ value = import_string.eval_import(value)
+ self.constructors[ext] = value
+
+ def __call__(self, environ, start_response):
+ environ['paste.urlparser.base_python_name'] = self.base_python_name
+ if self.init_module is NoDefault:
+ self.init_module = self.find_init_module(environ)
+ path_info = environ.get('PATH_INFO', '')
+ if not path_info:
+ return self.add_slash(environ, start_response)
+ if (self.init_module
+ and getattr(self.init_module, 'urlparser_hook', None)):
+ self.init_module.urlparser_hook(environ)
+ orig_path_info = environ['PATH_INFO']
+ orig_script_name = environ['SCRIPT_NAME']
+ application, filename = self.find_application(environ)
+ if not application:
+ if (self.init_module
+ and getattr(self.init_module, 'not_found_hook', None)
+ and environ.get('paste.urlparser.not_found_parser') is not self):
+ not_found_hook = self.init_module.not_found_hook
+ environ['paste.urlparser.not_found_parser'] = self
+ environ['PATH_INFO'] = orig_path_info
+ environ['SCRIPT_NAME'] = orig_script_name
+ return not_found_hook(environ, start_response)
+ if filename is None:
+ name, rest_of_path = request.path_info_split(environ['PATH_INFO'])
+ if not name:
+ name = 'one of %s' % ', '.join(
+ self.index_names or
+ ['(no index_names defined)'])
+
+ return self.not_found(
+ environ, start_response,
+ 'Tried to load %s from directory %s'
+ % (name, self.directory))
+ else:
+ environ['wsgi.errors'].write(
+ 'Found resource %s, but could not construct application\n'
+ % filename)
+ return self.not_found(
+ environ, start_response,
+ 'Tried to load %s from directory %s'
+ % (filename, self.directory))
+ if (self.init_module
+ and getattr(self.init_module, 'urlparser_wrap', None)):
+ return self.init_module.urlparser_wrap(
+ environ, start_response, application)
+ else:
+ return application(environ, start_response)
+
+ def find_application(self, environ):
+ if (self.init_module
+ and getattr(self.init_module, 'application', None)
+ and not environ.get('paste.urlparser.init_application') == environ['SCRIPT_NAME']):
+ environ['paste.urlparser.init_application'] = environ['SCRIPT_NAME']
+ return self.init_module.application, None
+ name, rest_of_path = request.path_info_split(environ['PATH_INFO'])
+ environ['PATH_INFO'] = rest_of_path
+ if name is not None:
+ environ['SCRIPT_NAME'] = environ.get('SCRIPT_NAME', '') + '/' + name
+ if not name:
+ names = self.index_names
+ for index_name in names:
+ filename = self.find_file(environ, index_name)
+ if filename:
+ break
+ else:
+ # None of the index files found
+ filename = None
+ else:
+ filename = self.find_file(environ, name)
+ if filename is None:
+ return None, filename
+ else:
+ return self.get_application(environ, filename), filename
+
+ def not_found(self, environ, start_response, debug_message=None):
+ exc = httpexceptions.HTTPNotFound(
+ 'The resource at %s could not be found'
+ % request.construct_url(environ),
+ comment=debug_message)
+ return exc.wsgi_application(environ, start_response)
+
+ def add_slash(self, environ, start_response):
+ """
+ This happens when you try to get to a directory
+ without a trailing /
+ """
+ url = request.construct_url(environ, with_query_string=False)
+ url += '/'
+ if environ.get('QUERY_STRING'):
+ url += '?' + environ['QUERY_STRING']
+ exc = httpexceptions.HTTPMovedPermanently(
+ 'The resource has moved to %s - you should be redirected '
+ 'automatically.' % url,
+ headers=[('location', url)])
+ return exc.wsgi_application(environ, start_response)
+
+ def find_file(self, environ, base_filename):
+ possible = []
+ """Cache a few values to reduce function call overhead"""
+ for filename in os.listdir(self.directory):
+ base, ext = os.path.splitext(filename)
+ full_filename = os.path.join(self.directory, filename)
+ if (ext in self.hide_extensions
+ or not base):
+ continue
+ if filename == base_filename:
+ possible.append(full_filename)
+ continue
+ if ext in self.ignore_extensions:
+ continue
+ if base == base_filename:
+ possible.append(full_filename)
+ if not possible:
+ #environ['wsgi.errors'].write(
+ # 'No file found matching %r in %s\n'
+ # % (base_filename, self.directory))
+ return None
+ if len(possible) > 1:
+ # If there is an exact match, this isn't 'ambiguous'
+ # per se; it might mean foo.gif and foo.gif.back for
+ # instance
+ if full_filename in possible:
+ return full_filename
+ else:
+ environ['wsgi.errors'].write(
+ 'Ambiguous URL: %s; matches files %s\n'
+ % (request.construct_url(environ),
+ ', '.join(possible)))
+ return None
+ return possible[0]
+
+ def get_application(self, environ, filename):
+ if os.path.isdir(filename):
+ t = 'dir'
+ else:
+ t = os.path.splitext(filename)[1]
+ constructor = self.constructors.get(t, self.constructors.get('*'))
+ if constructor is None:
+ #environ['wsgi.errors'].write(
+ # 'No constructor found for %s\n' % t)
+ return constructor
+ app = constructor(self, environ, filename)
+ if app is None:
+ #environ['wsgi.errors'].write(
+ # 'Constructor %s return None for %s\n' %
+ # (constructor, filename))
+ pass
+ return app
+
+ def register_constructor(cls, extension, constructor):
+ """
+ Register a function as a constructor. Registered constructors
+ apply to all instances of `URLParser`.
+
+ The extension should have a leading ``.``, or the special
+ extensions ``dir`` (for directories) and ``*`` (a catch-all).
+
+ `constructor` must be a callable that takes two arguments:
+ ``environ`` and ``filename``, and returns a WSGI application.
+ """
+ d = cls.global_constructors
+ assert not d.has_key(extension), (
+ "A constructor already exists for the extension %r (%r) "
+ "when attemption to register constructor %r"
+ % (extension, d[extension], constructor))
+ d[extension] = constructor
+ register_constructor = classmethod(register_constructor)
+
+ def get_parser(self, directory, base_python_name):
+ """
+ Get a parser for the given directory, or create one if
+ necessary. This way parsers can be cached and reused.
+
+ # @@: settings are inherited from the first caller
+ """
+ try:
+ return self.parsers_by_directory[(directory, base_python_name)]
+ except KeyError:
+ parser = self.__class__(
+ {},
+ directory, base_python_name,
+ index_names=self.index_names,
+ hide_extensions=self.hide_extensions,
+ ignore_extensions=self.ignore_extensions,
+ constructors=self.constructors)
+ self.parsers_by_directory[(directory, base_python_name)] = parser
+ return parser
+
+ def find_init_module(self, environ):
+ filename = os.path.join(self.directory, '__init__.py')
+ if not os.path.exists(filename):
+ return None
+ return load_module(environ, filename)
+
+ def __repr__(self):
+ return '<%s directory=%r; module=%s at %s>' % (
+ self.__class__.__name__,
+ self.directory,
+ self.base_python_name,
+ hex(abs(id(self))))
+
+def make_directory(parser, environ, filename):
+ base_python_name = environ['paste.urlparser.base_python_name']
+ if base_python_name:
+ base_python_name += "." + os.path.basename(filename)
+ else:
+ base_python_name = os.path.basename(filename)
+ return parser.get_parser(filename, base_python_name)
+
+URLParser.register_constructor('dir', make_directory)
+
+def make_unknown(parser, environ, filename):
+ return fileapp.FileApp(filename)
+
+URLParser.register_constructor('*', make_unknown)
+
+def load_module(environ, filename):
+ base_python_name = environ['paste.urlparser.base_python_name']
+ module_name = os.path.splitext(os.path.basename(filename))[0]
+ if base_python_name:
+ module_name = base_python_name + '.' + module_name
+ return load_module_from_name(environ, filename, module_name,
+ environ['wsgi.errors'])
+
+def load_module_from_name(environ, filename, module_name, errors):
+ if sys.modules.has_key(module_name):
+ return sys.modules[module_name]
+ init_filename = os.path.join(os.path.dirname(filename), '__init__.py')
+ if not os.path.exists(init_filename):
+ try:
+ f = open(init_filename, 'w')
+ except (OSError, IOError), e:
+ errors.write(
+ 'Cannot write __init__.py file into directory %s (%s)\n'
+ % (os.path.dirname(filename), e))
+ return None
+ f.write('#\n')
+ f.close()
+ fp = None
+ if sys.modules.has_key(module_name):
+ return sys.modules[module_name]
+ if '.' in module_name:
+ parent_name = '.'.join(module_name.split('.')[:-1])
+ base_name = module_name.split('.')[-1]
+ parent = load_module_from_name(environ, os.path.dirname(filename),
+ parent_name, errors)
+ else:
+ base_name = module_name
+ fp = None
+ try:
+ fp, pathname, stuff = imp.find_module(
+ base_name, [os.path.dirname(filename)])
+ module = imp.load_module(module_name, fp, pathname, stuff)
+ finally:
+ if fp is not None:
+ fp.close()
+ return module
+
+def make_py(parser, environ, filename):
+ module = load_module(environ, filename)
+ if not module:
+ return None
+ if hasattr(module, 'application') and module.application:
+ return getattr(module.application, 'wsgi_application', module.application)
+ base_name = module.__name__.split('.')[-1]
+ if hasattr(module, base_name):
+ obj = getattr(module, base_name)
+ if hasattr(obj, 'wsgi_application'):
+ return obj.wsgi_application
+ else:
+ # @@: Old behavior; should probably be deprecated eventually:
+ return getattr(module, base_name)()
+ environ['wsgi.errors'].write(
+ "Cound not find application or %s in %s\n"
+ % (base_name, module))
+ return None
+
+URLParser.register_constructor('.py', make_py)
+
+class StaticURLParser(object):
+ """
+ Like ``URLParser`` but only serves static files.
+
+ ``cache_max_age``:
+ integer specifies Cache-Control max_age in seconds
+ """
+ # @@: Should URLParser subclass from this?
+
+ def __init__(self, directory, root_directory=None,
+ cache_max_age=None):
+ self.directory = self.normpath(directory)
+ self.root_directory = self.normpath(root_directory or directory)
+ self.cache_max_age = cache_max_age
+
+ def normpath(path):
+ return os.path.normcase(os.path.abspath(path))
+ normpath = staticmethod(normpath)
+
+ def __call__(self, environ, start_response):
+ path_info = environ.get('PATH_INFO', '')
+ if not path_info:
+ return self.add_slash(environ, start_response)
+ if path_info == '/':
+ # @@: This should obviously be configurable
+ filename = 'index.html'
+ else:
+ filename = request.path_info_pop(environ)
+ full = self.normpath(os.path.join(self.directory, filename))
+ if not full.startswith(self.root_directory):
+ # Out of bounds
+ return self.not_found(environ, start_response)
+ if not os.path.exists(full):
+ return self.not_found(environ, start_response)
+ if os.path.isdir(full):
+ # @@: Cache?
+ return self.__class__(full, root_directory=self.root_directory,
+ cache_max_age=self.cache_max_age)(environ,
+ start_response)
+ if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
+ return self.error_extra_path(environ, start_response)
+ if_none_match = environ.get('HTTP_IF_NONE_MATCH')
+ if if_none_match:
+ mytime = os.stat(full).st_mtime
+ if str(mytime) == if_none_match:
+ headers = []
+ ## FIXME: probably should be
+ ## ETAG.update(headers, '"%s"' % mytime)
+ ETAG.update(headers, mytime)
+ start_response('304 Not Modified', headers)
+ return [''] # empty body
+
+ fa = self.make_app(full)
+ if self.cache_max_age:
+ fa.cache_control(max_age=self.cache_max_age)
+ return fa(environ, start_response)
+
+ def make_app(self, filename):
+ return fileapp.FileApp(filename)
+
+ def add_slash(self, environ, start_response):
+ """
+ This happens when you try to get to a directory
+ without a trailing /
+ """
+ url = request.construct_url(environ, with_query_string=False)
+ url += '/'
+ if environ.get('QUERY_STRING'):
+ url += '?' + environ['QUERY_STRING']
+ exc = httpexceptions.HTTPMovedPermanently(
+ 'The resource has moved to %s - you should be redirected '
+ 'automatically.' % url,
+ headers=[('location', url)])
+ return exc.wsgi_application(environ, start_response)
+
+ def not_found(self, environ, start_response, debug_message=None):
+ exc = httpexceptions.HTTPNotFound(
+ 'The resource at %s could not be found'
+ % request.construct_url(environ),
+ comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in %r; debug: %s'
+ % (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
+ self.directory, debug_message or '(none)'))
+ return exc.wsgi_application(environ, start_response)
+
+ def error_extra_path(self, environ, start_response):
+ exc = httpexceptions.HTTPNotFound(
+ 'The trailing path %r is not allowed' % environ['PATH_INFO'])
+ return exc.wsgi_application(environ, start_response)
+
+ def __repr__(self):
+ return '<%s %r>' % (self.__class__.__name__, self.directory)
+
+def make_static(global_conf, document_root, cache_max_age=None):
+ """
+ Return a WSGI application that serves a directory (configured
+ with document_root)
+
+ cache_max_age - integer specifies CACHE_CONTROL max_age in seconds
+ """
+ if cache_max_age is not None:
+ cache_max_age = int(cache_max_age)
+ return StaticURLParser(
+ document_root, cache_max_age=cache_max_age)
+
+class PkgResourcesParser(StaticURLParser):
+
+ def __init__(self, egg_or_spec, resource_name, manager=None, root_resource=None):
+ if pkg_resources is None:
+ raise NotImplementedError("This class requires pkg_resources.")
+ if isinstance(egg_or_spec, (str, unicode)):
+ self.egg = pkg_resources.get_distribution(egg_or_spec)
+ else:
+ self.egg = egg_or_spec
+ self.resource_name = resource_name
+ if manager is None:
+ manager = pkg_resources.ResourceManager()
+ self.manager = manager
+ if root_resource is None:
+ root_resource = resource_name
+ self.root_resource = os.path.normpath(root_resource)
+
+ def __repr__(self):
+ return '<%s for %s:%r>' % (
+ self.__class__.__name__,
+ self.egg.project_name,
+ self.resource_name)
+
+ def __call__(self, environ, start_response):
+ path_info = environ.get('PATH_INFO', '')
+ if not path_info:
+ return self.add_slash(environ, start_response)
+ if path_info == '/':
+ # @@: This should obviously be configurable
+ filename = 'index.html'
+ else:
+ filename = request.path_info_pop(environ)
+ resource = os.path.normcase(os.path.normpath(
+ self.resource_name + '/' + filename))
+ if self.root_resource is not None and not resource.startswith(self.root_resource):
+ # Out of bounds
+ return self.not_found(environ, start_response)
+ if not self.egg.has_resource(resource):
+ return self.not_found(environ, start_response)
+ if self.egg.resource_isdir(resource):
+ # @@: Cache?
+ child_root = self.root_resource is not None and self.root_resource or \
+ self.resource_name
+ return self.__class__(self.egg, resource, self.manager,
+ root_resource=child_root)(environ, start_response)
+ if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
+ return self.error_extra_path(environ, start_response)
+
+ type, encoding = mimetypes.guess_type(resource)
+ if not type:
+ type = 'application/octet-stream'
+ # @@: I don't know what to do with the encoding.
+ try:
+ file = self.egg.get_resource_stream(self.manager, resource)
+ except (IOError, OSError), e:
+ exc = httpexceptions.HTTPForbidden(
+ 'You are not permitted to view this file (%s)' % e)
+ return exc.wsgi_application(environ, start_response)
+ start_response('200 OK',
+ [('content-type', type)])
+ return fileapp._FileIter(file)
+
+ def not_found(self, environ, start_response, debug_message=None):
+ exc = httpexceptions.HTTPNotFound(
+ 'The resource at %s could not be found'
+ % request.construct_url(environ),
+ comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in egg:%s#%r; debug: %s'
+ % (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
+ self.egg, self.resource_name, debug_message or '(none)'))
+ return exc.wsgi_application(environ, start_response)
+
+def make_pkg_resources(global_conf, egg, resource_name=''):
+ """
+ A static file parser that loads data from an egg using
+ ``pkg_resources``. Takes a configuration value ``egg``, which is
+ an egg spec, and a base ``resource_name`` (default empty string)
+ which is the path in the egg that this starts at.
+ """
+ if pkg_resources is None:
+ raise NotImplementedError("This function requires pkg_resources.")
+ return PkgResourcesParser(egg, resource_name)
+
+def make_url_parser(global_conf, directory, base_python_name,
+ index_names=None, hide_extensions=None,
+ ignore_extensions=None,
+ **constructor_conf):
+ """
+ Create a URLParser application that looks in ``directory``, which
+ should be the directory for the Python package named in
+ ``base_python_name``. ``index_names`` are used when viewing the
+ directory (like ``'index'`` for ``'index.html'``).
+ ``hide_extensions`` are extensions that are not viewable (like
+ ``'.pyc'``) and ``ignore_extensions`` are viewable but only if an
+ explicit extension is given.
+ """
+ if index_names is None:
+ index_names = global_conf.get(
+ 'index_names', ('index', 'Index', 'main', 'Main'))
+ index_names = converters.aslist(index_names)
+
+ if hide_extensions is None:
+ hide_extensions = global_conf.get(
+ 'hide_extensions', ('.pyc', 'bak', 'py~'))
+ hide_extensions = converters.aslist(hide_extensions)
+
+ if ignore_extensions is None:
+ ignore_extensions = global_conf.get(
+ 'ignore_extensions', ())
+ ignore_extensions = converters.aslist(ignore_extensions)
+ # There's no real way to set constructors currently...
+
+ return URLParser({}, directory, base_python_name,
+ index_names=index_names,
+ hide_extensions=hide_extensions,
+ ignore_extensions=ignore_extensions,
+ **constructor_conf)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/PySourceColor.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/PySourceColor.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/PySourceColor.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2103 @@
+# -*- coding: Latin-1 -*-
+"""
+PySourceColor: color Python source code
+"""
+
+"""
+ PySourceColor.py
+
+----------------------------------------------------------------------------
+
+ A python source to colorized html/css/xhtml converter.
+ Hacked by M.E.Farmer Jr. 2004, 2005
+ Python license
+
+----------------------------------------------------------------------------
+
+ - HTML markup does not create w3c valid html, but it works on every
+ browser i've tried so far.(I.E.,Mozilla/Firefox,Opera,Konqueror,wxHTML).
+ - CSS markup is w3c validated html 4.01 strict,
+ but will not render correctly on all browsers.
+ - XHTML markup is w3c validated xhtml 1.0 strict,
+ like html 4.01, will not render correctly on all browsers.
+
+----------------------------------------------------------------------------
+
+Features:
+
+ -Three types of markup:
+ html (default)
+ css/html 4.01 strict
+ xhtml 1.0 strict
+
+ -Can tokenize and colorize:
+ 12 types of strings
+ 2 comment types
+ numbers
+ operators
+ brackets
+ math operators
+ class / name
+ def / name
+ decorator / name
+ keywords
+ arguments class/def/decorator
+ linenumbers
+ names
+ text
+
+ -Eight colorschemes built-in:
+ null
+ mono
+ lite (default)
+ dark
+ dark2
+ idle
+ viewcvs
+ pythonwin
+
+ -Header and footer
+ set to '' for builtin header / footer.
+ give path to a file containing the html
+ you want added as header or footer.
+
+ -Arbitrary text and html
+ html markup converts all to raw (TEXT token)
+ #@# for raw -> send raw text.
+ #$# for span -> inline html and text.
+ #%# for div -> block level html and text.
+
+ -Linenumbers
+ Supports all styles. New token is called LINENUMBER.
+ Defaults to NAME if not defined.
+
+ Style options
+
+ -ALL markups support these text styles:
+ b = bold
+ i = italic
+ u = underline
+ -CSS and XHTML has limited support for borders:
+ HTML markup functions will ignore these.
+ Optional: Border color in RGB hex
+ Defaults to the text forecolor.
+ #rrggbb = border color
+ Border size:
+ l = thick
+ m = medium
+ t = thin
+ Border type:
+ - = dashed
+ . = dotted
+ s = solid
+ d = double
+ g = groove
+ r = ridge
+ n = inset
+ o = outset
+ You can specify multiple sides,
+ they will all use the same style.
+ Optional: Default is full border.
+ v = bottom
+ < = left
+ > = right
+ ^ = top
+ NOTE: Specify the styles you want.
+ The markups will ignore unsupported styles
+ Also note not all browsers can show these options
+
+ -All tokens default to NAME if not defined
+ so the only absolutely critical ones to define are:
+ NAME, ERRORTOKEN, PAGEBACKGROUND
+
+----------------------------------------------------------------------------
+
+Example usage::
+
+ # import
+ import PySourceColor as psc
+ psc.convert('c:/Python22/PySourceColor.py', colors=psc.idle, show=1)
+
+ # from module import *
+ from PySourceColor import *
+ convert('c:/Python22/Lib', colors=lite, markup="css",
+ header='#$#<b>This is a simpe heading</b><hr/>')
+
+ # How to use a custom colorscheme, and most of the 'features'
+ from PySourceColor import *
+ new = {
+ ERRORTOKEN: ('bui','#FF8080',''),
+ DECORATOR_NAME: ('s','#AACBBC',''),
+ DECORATOR: ('n','#333333',''),
+ NAME: ('t.<v','#1133AA','#DDFF22'),
+ NUMBER: ('','#236676','#FF5555'),
+ OPERATOR: ('b','#454567','#BBBB11'),
+ MATH_OPERATOR: ('','#935623','#423afb'),
+ BRACKETS: ('b','#ac34bf','#6457a5'),
+ COMMENT: ('t-#0022FF','#545366','#AABBFF'),
+ DOUBLECOMMENT: ('<l#553455','#553455','#FF00FF'),
+ CLASS_NAME: ('m^v-','#000000','#FFFFFF'),
+ DEF_NAME: ('l=<v','#897845','#000022'),
+ KEYWORD: ('.b','#345345','#FFFF22'),
+ SINGLEQUOTE: ('mn','#223344','#AADDCC'),
+ SINGLEQUOTE_R: ('','#344522',''),
+ SINGLEQUOTE_U: ('','#234234',''),
+ DOUBLEQUOTE: ('m#0022FF','#334421',''),
+ DOUBLEQUOTE_R: ('','#345345',''),
+ DOUBLEQUOTE_U: ('','#678673',''),
+ TRIPLESINGLEQUOTE: ('tv','#FFFFFF','#000000'),
+ TRIPLESINGLEQUOTE_R: ('tbu','#443256','#DDFFDA'),
+ TRIPLESINGLEQUOTE_U: ('','#423454','#DDFFDA'),
+ TRIPLEDOUBLEQUOTE: ('li#236fd3b<>','#000000','#FFFFFF'),
+ TRIPLEDOUBLEQUOTE_R: ('tub','#000000','#FFFFFF'),
+ TRIPLEDOUBLEQUOTE_U: ('-', '#CCAABB','#FFFAFF'),
+ LINENUMBER: ('ib-','#ff66aa','#7733FF'),]
+ TEXT: ('','#546634',''),
+ PAGEBACKGROUND: '#FFFAAA',
+ }
+ if __name__ == '__main__':
+ import sys
+ convert(sys.argv[1], './xhtml.html', colors=new, markup='xhtml', show=1,
+ linenumbers=1)
+ convert(sys.argv[1], './html.html', colors=new, markup='html', show=1,
+ linenumbers=1)
+
+"""
+
+__all__ = ['ERRORTOKEN','DECORATOR_NAME', 'DECORATOR', 'ARGS', 'EXTRASPACE',
+ 'NAME', 'NUMBER', 'OPERATOR', 'COMMENT', 'MATH_OPERATOR',
+ 'DOUBLECOMMENT', 'CLASS_NAME', 'DEF_NAME', 'KEYWORD', 'BRACKETS',
+ 'SINGLEQUOTE','SINGLEQUOTE_R','SINGLEQUOTE_U','DOUBLEQUOTE',
+ 'DOUBLEQUOTE_R', 'DOUBLEQUOTE_U', 'TRIPLESINGLEQUOTE', 'TEXT',
+ 'TRIPLESINGLEQUOTE_R', 'TRIPLESINGLEQUOTE_U', 'TRIPLEDOUBLEQUOTE',
+ 'TRIPLEDOUBLEQUOTE_R', 'TRIPLEDOUBLEQUOTE_U', 'PAGEBACKGROUND',
+ 'LINENUMBER', 'CODESTART', 'CODEEND', 'PY', 'TOKEN_NAMES', 'CSSHOOK',
+ 'null', 'mono', 'lite', 'dark','dark2', 'pythonwin','idle',
+ 'viewcvs', 'Usage', 'cli', 'str2stdout', 'path2stdout', 'Parser',
+ 'str2file', 'str2html', 'str2css', 'str2markup', 'path2file',
+ 'path2html', 'convert', 'walkdir', 'defaultColors', 'showpage',
+ 'pageconvert','tagreplace', 'MARKUPDICT']
+__title__ = 'PySourceColor'
+__version__ = "2.1a"
+__date__ = '25 April 2005'
+__author__ = "M.E.Farmer Jr."
+__credits__ = '''This was originally based on a python recipe
+submitted by Jürgen Hermann to ASPN. Now based on the voices in my head.
+M.E.Farmer 2004, 2005
+Python license
+'''
+import os
+import sys
+import time
+import glob
+import getopt
+import keyword
+import token
+import tokenize
+import traceback
+try :
+ import cStringIO as StringIO
+except:
+ import StringIO
+# Do not edit
+NAME = token.NAME
+NUMBER = token.NUMBER
+COMMENT = tokenize.COMMENT
+OPERATOR = token.OP
+ERRORTOKEN = token.ERRORTOKEN
+ARGS = token.NT_OFFSET + 1
+DOUBLECOMMENT = token.NT_OFFSET + 2
+CLASS_NAME = token.NT_OFFSET + 3
+DEF_NAME = token.NT_OFFSET + 4
+KEYWORD = token.NT_OFFSET + 5
+SINGLEQUOTE = token.NT_OFFSET + 6
+SINGLEQUOTE_R = token.NT_OFFSET + 7
+SINGLEQUOTE_U = token.NT_OFFSET + 8
+DOUBLEQUOTE = token.NT_OFFSET + 9
+DOUBLEQUOTE_R = token.NT_OFFSET + 10
+DOUBLEQUOTE_U = token.NT_OFFSET + 11
+TRIPLESINGLEQUOTE = token.NT_OFFSET + 12
+TRIPLESINGLEQUOTE_R = token.NT_OFFSET + 13
+TRIPLESINGLEQUOTE_U = token.NT_OFFSET + 14
+TRIPLEDOUBLEQUOTE = token.NT_OFFSET + 15
+TRIPLEDOUBLEQUOTE_R = token.NT_OFFSET + 16
+TRIPLEDOUBLEQUOTE_U = token.NT_OFFSET + 17
+PAGEBACKGROUND = token.NT_OFFSET + 18
+DECORATOR = token.NT_OFFSET + 19
+DECORATOR_NAME = token.NT_OFFSET + 20
+BRACKETS = token.NT_OFFSET + 21
+MATH_OPERATOR = token.NT_OFFSET + 22
+LINENUMBER = token.NT_OFFSET + 23
+TEXT = token.NT_OFFSET + 24
+PY = token.NT_OFFSET + 25
+CODESTART = token.NT_OFFSET + 26
+CODEEND = token.NT_OFFSET + 27
+CSSHOOK = token.NT_OFFSET + 28
+EXTRASPACE = token.NT_OFFSET + 29
+
+# markup classname lookup
+MARKUPDICT = {
+ ERRORTOKEN: 'py_err',
+ DECORATOR_NAME: 'py_decn',
+ DECORATOR: 'py_dec',
+ ARGS: 'py_args',
+ NAME: 'py_name',
+ NUMBER: 'py_num',
+ OPERATOR: 'py_op',
+ COMMENT: 'py_com',
+ DOUBLECOMMENT: 'py_dcom',
+ CLASS_NAME: 'py_clsn',
+ DEF_NAME: 'py_defn',
+ KEYWORD: 'py_key',
+ SINGLEQUOTE: 'py_sq',
+ SINGLEQUOTE_R: 'py_sqr',
+ SINGLEQUOTE_U: 'py_squ',
+ DOUBLEQUOTE: 'py_dq',
+ DOUBLEQUOTE_R: 'py_dqr',
+ DOUBLEQUOTE_U: 'py_dqu',
+ TRIPLESINGLEQUOTE: 'py_tsq',
+ TRIPLESINGLEQUOTE_R: 'py_tsqr',
+ TRIPLESINGLEQUOTE_U: 'py_tsqu',
+ TRIPLEDOUBLEQUOTE: 'py_tdq',
+ TRIPLEDOUBLEQUOTE_R: 'py_tdqr',
+ TRIPLEDOUBLEQUOTE_U: 'py_tdqu',
+ BRACKETS: 'py_bra',
+ MATH_OPERATOR: 'py_mop',
+ LINENUMBER: 'py_lnum',
+ TEXT: 'py_text',
+ }
+# might help users that want to create custom schemes
+TOKEN_NAMES= {
+ ERRORTOKEN:'ERRORTOKEN',
+ DECORATOR_NAME:'DECORATOR_NAME',
+ DECORATOR:'DECORATOR',
+ ARGS:'ARGS',
+ NAME:'NAME',
+ NUMBER:'NUMBER',
+ OPERATOR:'OPERATOR',
+ COMMENT:'COMMENT',
+ DOUBLECOMMENT:'DOUBLECOMMENT',
+ CLASS_NAME:'CLASS_NAME',
+ DEF_NAME:'DEF_NAME',
+ KEYWORD:'KEYWORD',
+ SINGLEQUOTE:'SINGLEQUOTE',
+ SINGLEQUOTE_R:'SINGLEQUOTE_R',
+ SINGLEQUOTE_U:'SINGLEQUOTE_U',
+ DOUBLEQUOTE:'DOUBLEQUOTE',
+ DOUBLEQUOTE_R:'DOUBLEQUOTE_R',
+ DOUBLEQUOTE_U:'DOUBLEQUOTE_U',
+ TRIPLESINGLEQUOTE:'TRIPLESINGLEQUOTE',
+ TRIPLESINGLEQUOTE_R:'TRIPLESINGLEQUOTE_R',
+ TRIPLESINGLEQUOTE_U:'TRIPLESINGLEQUOTE_U',
+ TRIPLEDOUBLEQUOTE:'TRIPLEDOUBLEQUOTE',
+ TRIPLEDOUBLEQUOTE_R:'TRIPLEDOUBLEQUOTE_R',
+ TRIPLEDOUBLEQUOTE_U:'TRIPLEDOUBLEQUOTE_U',
+ BRACKETS:'BRACKETS',
+ MATH_OPERATOR:'MATH_OPERATOR',
+ LINENUMBER:'LINENUMBER',
+ TEXT:'TEXT',
+ PAGEBACKGROUND:'PAGEBACKGROUND',
+ }
+
+######################################################################
+# Edit colors and styles to taste
+# Create your own scheme, just copy one below , rename and edit.
+# Custom styles must at least define NAME, ERRORTOKEN, PAGEBACKGROUND,
+# all missing elements will default to NAME.
+# See module docstring for details on style attributes.
+######################################################################
+# Copy null and use it as a starter colorscheme.
+null = {# tokentype: ('tags border_color', 'textforecolor', 'textbackcolor')
+ ERRORTOKEN: ('','#000000',''),# Error token
+ DECORATOR_NAME: ('','#000000',''),# Decorator name
+ DECORATOR: ('','#000000',''),# @ symbol
+ ARGS: ('','#000000',''),# class,def,deco arguments
+ NAME: ('','#000000',''),# All other python text
+ NUMBER: ('','#000000',''),# 0->10
+ OPERATOR: ('','#000000',''),# ':','<=',';',',','.','==', etc
+ MATH_OPERATOR: ('','#000000',''),# '+','-','=','','**',etc
+ BRACKETS: ('','#000000',''),# '[',']','(',')','{','}'
+ COMMENT: ('','#000000',''),# Single comment
+ DOUBLECOMMENT: ('','#000000',''),## Double comment
+ CLASS_NAME: ('','#000000',''),# Class name
+ DEF_NAME: ('','#000000',''),# Def name
+ KEYWORD: ('','#000000',''),# Python keywords
+ SINGLEQUOTE: ('','#000000',''),# 'SINGLEQUOTE'
+ SINGLEQUOTE_R: ('','#000000',''),# r'SINGLEQUOTE'
+ SINGLEQUOTE_U: ('','#000000',''),# u'SINGLEQUOTE'
+ DOUBLEQUOTE: ('','#000000',''),# "DOUBLEQUOTE"
+ DOUBLEQUOTE_R: ('','#000000',''),# r"DOUBLEQUOTE"
+ DOUBLEQUOTE_U: ('','#000000',''),# u"DOUBLEQUOTE"
+ TRIPLESINGLEQUOTE: ('','#000000',''),# '''TRIPLESINGLEQUOTE'''
+ TRIPLESINGLEQUOTE_R: ('','#000000',''),# r'''TRIPLESINGLEQUOTE'''
+ TRIPLESINGLEQUOTE_U: ('','#000000',''),# u'''TRIPLESINGLEQUOTE'''
+ TRIPLEDOUBLEQUOTE: ('','#000000',''),# """TRIPLEDOUBLEQUOTE"""
+ TRIPLEDOUBLEQUOTE_R: ('','#000000',''),# r"""TRIPLEDOUBLEQUOTE"""
+ TRIPLEDOUBLEQUOTE_U: ('','#000000',''),# u"""TRIPLEDOUBLEQUOTE"""
+ TEXT: ('','#000000',''),# non python text
+ LINENUMBER: ('>ti#555555','#000000',''),# Linenumbers
+ PAGEBACKGROUND: '#FFFFFF'# set the page background
+ }
+
+mono = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('bu','#000000',''),
+ DECORATOR: ('b','#000000',''),
+ ARGS: ('b','#555555',''),
+ NAME: ('','#000000',''),
+ NUMBER: ('b','#000000',''),
+ OPERATOR: ('b','#000000',''),
+ MATH_OPERATOR: ('b','#000000',''),
+ BRACKETS: ('b','#000000',''),
+ COMMENT: ('i','#999999',''),
+ DOUBLECOMMENT: ('b','#999999',''),
+ CLASS_NAME: ('bu','#000000',''),
+ DEF_NAME: ('b','#000000',''),
+ KEYWORD: ('b','#000000',''),
+ SINGLEQUOTE: ('','#000000',''),
+ SINGLEQUOTE_R: ('','#000000',''),
+ SINGLEQUOTE_U: ('','#000000',''),
+ DOUBLEQUOTE: ('','#000000',''),
+ DOUBLEQUOTE_R: ('','#000000',''),
+ DOUBLEQUOTE_U: ('','#000000',''),
+ TRIPLESINGLEQUOTE: ('','#000000',''),
+ TRIPLESINGLEQUOTE_R: ('','#000000',''),
+ TRIPLESINGLEQUOTE_U: ('','#000000',''),
+ TRIPLEDOUBLEQUOTE: ('i','#000000',''),
+ TRIPLEDOUBLEQUOTE_R: ('i','#000000',''),
+ TRIPLEDOUBLEQUOTE_U: ('i','#000000',''),
+ TEXT: ('','#000000',''),
+ LINENUMBER: ('>ti#555555','#000000',''),
+ PAGEBACKGROUND: '#FFFFFF'
+ }
+
+dark = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('b','#FFBBAA',''),
+ DECORATOR: ('b','#CC5511',''),
+ ARGS: ('b','#DDDDFF',''),
+ NAME: ('','#DDDDDD',''),
+ NUMBER: ('','#FF0000',''),
+ OPERATOR: ('b','#FAF785',''),
+ MATH_OPERATOR: ('b','#FAF785',''),
+ BRACKETS: ('b','#FAF785',''),
+ COMMENT: ('','#45FCA0',''),
+ DOUBLECOMMENT: ('i','#A7C7A9',''),
+ CLASS_NAME: ('b','#B666FD',''),
+ DEF_NAME: ('b','#EBAE5C',''),
+ KEYWORD: ('b','#8680FF',''),
+ SINGLEQUOTE: ('','#F8BAFE',''),
+ SINGLEQUOTE_R: ('','#F8BAFE',''),
+ SINGLEQUOTE_U: ('','#F8BAFE',''),
+ DOUBLEQUOTE: ('','#FF80C0',''),
+ DOUBLEQUOTE_R: ('','#FF80C0',''),
+ DOUBLEQUOTE_U: ('','#FF80C0',''),
+ TRIPLESINGLEQUOTE: ('','#FF9595',''),
+ TRIPLESINGLEQUOTE_R: ('','#FF9595',''),
+ TRIPLESINGLEQUOTE_U: ('','#FF9595',''),
+ TRIPLEDOUBLEQUOTE: ('','#B3FFFF',''),
+ TRIPLEDOUBLEQUOTE_R: ('','#B3FFFF',''),
+ TRIPLEDOUBLEQUOTE_U: ('','#B3FFFF',''),
+ TEXT: ('','#FFFFFF',''),
+ LINENUMBER: ('>mi#555555','#bbccbb','#333333'),
+ PAGEBACKGROUND: '#000000'
+ }
+
+dark2 = {
+ ERRORTOKEN: ('','#FF0000',''),
+ DECORATOR_NAME: ('b','#FFBBAA',''),
+ DECORATOR: ('b','#CC5511',''),
+ ARGS: ('b','#DDDDDD',''),
+ NAME: ('','#C0C0C0',''),
+ NUMBER: ('b','#00FF00',''),
+ OPERATOR: ('b','#FF090F',''),
+ MATH_OPERATOR: ('b','#EE7020',''),
+ BRACKETS: ('b','#FFB90F',''),
+ COMMENT: ('i','#D0D000','#522000'),#'#88AA88','#11111F'),
+ DOUBLECOMMENT: ('i','#D0D000','#522000'),#'#77BB77','#11111F'),
+ CLASS_NAME: ('b','#DD4080',''),
+ DEF_NAME: ('b','#FF8040',''),
+ KEYWORD: ('b','#4726d1',''),
+ SINGLEQUOTE: ('','#8080C0',''),
+ SINGLEQUOTE_R: ('','#8080C0',''),
+ SINGLEQUOTE_U: ('','#8080C0',''),
+ DOUBLEQUOTE: ('','#ADB9F1',''),
+ DOUBLEQUOTE_R: ('','#ADB9F1',''),
+ DOUBLEQUOTE_U: ('','#ADB9F1',''),
+ TRIPLESINGLEQUOTE: ('','#00C1C1',''),#A050C0
+ TRIPLESINGLEQUOTE_R: ('','#00C1C1',''),#A050C0
+ TRIPLESINGLEQUOTE_U: ('','#00C1C1',''),#A050C0
+ TRIPLEDOUBLEQUOTE: ('','#33E3E3',''),#B090E0
+ TRIPLEDOUBLEQUOTE_R: ('','#33E3E3',''),#B090E0
+ TRIPLEDOUBLEQUOTE_U: ('','#33E3E3',''),#B090E0
+ TEXT: ('','#C0C0C0',''),
+ LINENUMBER: ('>mi#555555','#bbccbb','#333333'),
+ PAGEBACKGROUND: '#000000'
+ }
+
+lite = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('b','#BB4422',''),
+ DECORATOR: ('b','#3333AF',''),
+ ARGS: ('b','#000000',''),
+ NAME: ('','#333333',''),
+ NUMBER: ('b','#DD2200',''),
+ OPERATOR: ('b','#000000',''),
+ MATH_OPERATOR: ('b','#000000',''),
+ BRACKETS: ('b','#000000',''),
+ COMMENT: ('','#007F00',''),
+ DOUBLECOMMENT: ('','#608060',''),
+ CLASS_NAME: ('b','#0000DF',''),
+ DEF_NAME: ('b','#9C7A00',''),#f09030
+ KEYWORD: ('b','#0000AF',''),
+ SINGLEQUOTE: ('','#600080',''),
+ SINGLEQUOTE_R: ('','#600080',''),
+ SINGLEQUOTE_U: ('','#600080',''),
+ DOUBLEQUOTE: ('','#A0008A',''),
+ DOUBLEQUOTE_R: ('','#A0008A',''),
+ DOUBLEQUOTE_U: ('','#A0008A',''),
+ TRIPLESINGLEQUOTE: ('','#337799',''),
+ TRIPLESINGLEQUOTE_R: ('','#337799',''),
+ TRIPLESINGLEQUOTE_U: ('','#337799',''),
+ TRIPLEDOUBLEQUOTE: ('','#1166AA',''),
+ TRIPLEDOUBLEQUOTE_R: ('','#1166AA',''),
+ TRIPLEDOUBLEQUOTE_U: ('','#1166AA',''),
+ TEXT: ('','#000000',''),
+ LINENUMBER: ('>ti#555555','#000000',''),
+ PAGEBACKGROUND: '#FFFFFF'
+ }
+
+idle = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('','#900090',''),
+ DECORATOR: ('','#FF7700',''),
+ NAME: ('','#000000',''),
+ NUMBER: ('','#000000',''),
+ OPERATOR: ('','#000000',''),
+ MATH_OPERATOR: ('','#000000',''),
+ BRACKETS: ('','#000000',''),
+ COMMENT: ('','#DD0000',''),
+ DOUBLECOMMENT: ('','#DD0000',''),
+ CLASS_NAME: ('','#0000FF',''),
+ DEF_NAME: ('','#0000FF',''),
+ KEYWORD: ('','#FF7700',''),
+ SINGLEQUOTE: ('','#00AA00',''),
+ SINGLEQUOTE_R: ('','#00AA00',''),
+ SINGLEQUOTE_U: ('','#00AA00',''),
+ DOUBLEQUOTE: ('','#00AA00',''),
+ DOUBLEQUOTE_R: ('','#00AA00',''),
+ DOUBLEQUOTE_U: ('','#00AA00',''),
+ TRIPLESINGLEQUOTE: ('','#00AA00',''),
+ TRIPLESINGLEQUOTE_R: ('','#00AA00',''),
+ TRIPLESINGLEQUOTE_U: ('','#00AA00',''),
+ TRIPLEDOUBLEQUOTE: ('','#00AA00',''),
+ TRIPLEDOUBLEQUOTE_R: ('','#00AA00',''),
+ TRIPLEDOUBLEQUOTE_U: ('','#00AA00',''),
+ TEXT: ('','#000000',''),
+ LINENUMBER: ('>ti#555555','#000000',''),
+ PAGEBACKGROUND: '#FFFFFF'
+ }
+
+pythonwin = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('b','#DD0080',''),
+ DECORATOR: ('b','#000080',''),
+ ARGS: ('','#000000',''),
+ NAME: ('','#303030',''),
+ NUMBER: ('','#008080',''),
+ OPERATOR: ('','#000000',''),
+ MATH_OPERATOR: ('','#000000',''),
+ BRACKETS: ('','#000000',''),
+ COMMENT: ('','#007F00',''),
+ DOUBLECOMMENT: ('','#7F7F7F',''),
+ CLASS_NAME: ('b','#0000FF',''),
+ DEF_NAME: ('b','#007F7F',''),
+ KEYWORD: ('b','#000080',''),
+ SINGLEQUOTE: ('','#808000',''),
+ SINGLEQUOTE_R: ('','#808000',''),
+ SINGLEQUOTE_U: ('','#808000',''),
+ DOUBLEQUOTE: ('','#808000',''),
+ DOUBLEQUOTE_R: ('','#808000',''),
+ DOUBLEQUOTE_U: ('','#808000',''),
+ TRIPLESINGLEQUOTE: ('','#808000',''),
+ TRIPLESINGLEQUOTE_R: ('','#808000',''),
+ TRIPLESINGLEQUOTE_U: ('','#808000',''),
+ TRIPLEDOUBLEQUOTE: ('','#808000',''),
+ TRIPLEDOUBLEQUOTE_R: ('','#808000',''),
+ TRIPLEDOUBLEQUOTE_U: ('','#808000',''),
+ TEXT: ('','#303030',''),
+ LINENUMBER: ('>ti#555555','#000000',''),
+ PAGEBACKGROUND: '#FFFFFF'
+ }
+
+viewcvs = {
+ ERRORTOKEN: ('s#FF0000','#FF8080',''),
+ DECORATOR_NAME: ('','#000000',''),
+ DECORATOR: ('','#000000',''),
+ ARGS: ('','#000000',''),
+ NAME: ('','#000000',''),
+ NUMBER: ('','#000000',''),
+ OPERATOR: ('','#000000',''),
+ MATH_OPERATOR: ('','#000000',''),
+ BRACKETS: ('','#000000',''),
+ COMMENT: ('i','#b22222',''),
+ DOUBLECOMMENT: ('i','#b22222',''),
+ CLASS_NAME: ('','#000000',''),
+ DEF_NAME: ('b','#0000ff',''),
+ KEYWORD: ('b','#a020f0',''),
+ SINGLEQUOTE: ('b','#bc8f8f',''),
+ SINGLEQUOTE_R: ('b','#bc8f8f',''),
+ SINGLEQUOTE_U: ('b','#bc8f8f',''),
+ DOUBLEQUOTE: ('b','#bc8f8f',''),
+ DOUBLEQUOTE_R: ('b','#bc8f8f',''),
+ DOUBLEQUOTE_U: ('b','#bc8f8f',''),
+ TRIPLESINGLEQUOTE: ('b','#bc8f8f',''),
+ TRIPLESINGLEQUOTE_R: ('b','#bc8f8f',''),
+ TRIPLESINGLEQUOTE_U: ('b','#bc8f8f',''),
+ TRIPLEDOUBLEQUOTE: ('b','#bc8f8f',''),
+ TRIPLEDOUBLEQUOTE_R: ('b','#bc8f8f',''),
+ TRIPLEDOUBLEQUOTE_U: ('b','#bc8f8f',''),
+ TEXT: ('','#000000',''),
+ LINENUMBER: ('>ti#555555','#000000',''),
+ PAGEBACKGROUND: '#FFFFFF'
+ }
+
+defaultColors = lite
+
+def Usage():
+ doc = """
+ -----------------------------------------------------------------------------
+ PySourceColor.py ver: %s
+ -----------------------------------------------------------------------------
+ Module summary:
+ This module is designed to colorize python source code.
+ Input--->python source
+ Output-->colorized (html, html4.01/css, xhtml1.0)
+ Standalone:
+ This module will work from the command line with options.
+ This module will work with redirected stdio.
+ Imported:
+ This module can be imported and used directly in your code.
+ -----------------------------------------------------------------------------
+ Command line options:
+ -h, --help
+ Optional-> Display this help message.
+ -t, --test
+ Optional-> Will ignore all others flags but --profile
+ test all schemes and markup combinations
+ -p, --profile
+ Optional-> Works only with --test or -t
+ runs profile.py and makes the test work in quiet mode.
+ -i, --in, --input
+ Optional-> If you give input on stdin.
+ Use any of these for the current dir (.,cwd)
+ Input can be file or dir.
+ Input from stdin use one of the following (-,stdin)
+ If stdin is used as input stdout is output unless specified.
+ -o, --out, --output
+ Optional-> output dir for the colorized source.
+ default: output dir is the input dir.
+ To output html to stdout use one of the following (-,stdout)
+ Stdout can be used without stdin if you give a file as input.
+ -c, --color
+ Optional-> null, mono, dark, dark2, lite, idle, pythonwin, viewcvs
+ default: dark
+ -s, --show
+ Optional-> Show page after creation.
+ default: no show
+ -m, --markup
+ Optional-> html, css, xhtml
+ css, xhtml also support external stylesheets (-e,--external)
+ default: HTML
+ -e, --external
+ Optional-> use with css, xhtml
+ Writes an style sheet instead of embedding it in the page
+ saves it as pystyle.css in the same directory.
+ html markup will silently ignore this flag.
+ -H, --header
+ Opional-> add a page header to the top of the output
+ -H
+ Builtin header (name,date,hrule)
+ --header
+ You must specify a filename.
+ The header file must be valid html
+ and must handle its own font colors.
+ ex. --header c:/tmp/header.txt
+ -F, --footer
+ Opional-> add a page footer to the bottom of the output
+ -F
+ Builtin footer (hrule,name,date)
+ --footer
+ You must specify a filename.
+ The footer file must be valid html
+ and must handle its own font colors.
+ ex. --footer c:/tmp/footer.txt
+ -l, --linenumbers
+ Optional-> default is no linenumbers
+ Adds line numbers to the start of each line in the code.
+ --convertpage
+ Given a webpage that has code embedded in tags it will
+ convert embedded code to colorized html.
+ (see pageconvert for details)
+ -----------------------------------------------------------------------------
+ Option usage:
+ # Test and show pages
+ python PySourceColor.py -t -s
+ # Test and only show profile results
+ python PySourceColor.py -t -p
+ # Colorize all .py,.pyw files in cwdir you can also use: (.,cwd)
+ python PySourceColor.py -i .
+ # Using long options w/ =
+ python PySourceColor.py --in=c:/myDir/my.py --color=lite --show
+ # Using short options w/out =
+ python PySourceColor.py -i c:/myDir/ -c idle -m css -e
+ # Using any mix
+ python PySourceColor.py --in . -o=c:/myDir --show
+ # Place a custom header on your files
+ python PySourceColor.py -i . -o c:/tmp -m xhtml --header c:/header.txt
+ -----------------------------------------------------------------------------
+ Stdio usage:
+ # Stdio using no options
+ python PySourceColor.py < c:/MyFile.py > c:/tmp/MyFile.html
+ # Using stdin alone automatically uses stdout for output: (stdin,-)
+ python PySourceColor.py -i- < c:/MyFile.py > c:/tmp/myfile.html
+ # Stdout can also be written to directly from a file instead of stdin
+ python PySourceColor.py -i c:/MyFile.py -m css -o- > c:/tmp/myfile.html
+ # Stdin can be used as input , but output can still be specified
+ python PySourceColor.py -i- -o c:/pydoc.py.html -s < c:/Python22/my.py
+ _____________________________________________________________________________
+ """
+ print doc % (__version__)
+ sys.exit(1)
+
+###################################################### Command line interface
+
+def cli():
+ """Handle command line args and redirections"""
+ try:
+ # try to get command line args
+ opts, args = getopt.getopt(sys.argv[1:],
+ "hseqtplHFi:o:c:m:h:f:",["help", "show", "quiet",
+ "test", "external", "linenumbers", "convertpage", "profile",
+ "input=", "output=", "color=", "markup=","header=", "footer="])
+ except getopt.GetoptError:
+ # on error print help information and exit:
+ Usage()
+ # init some names
+ input = None
+ output = None
+ colorscheme = None
+ markup = 'html'
+ header = None
+ footer = None
+ linenumbers = 0
+ show = 0
+ quiet = 0
+ test = 0
+ profile = 0
+ convertpage = 0
+ form = None
+ # if we have args then process them
+ for o, a in opts:
+ if o in ["-h", "--help"]:
+ Usage()
+ sys.exit()
+ if o in ["-o", "--output", "--out"]:
+ output = a
+ if o in ["-i", "--input", "--in"]:
+ input = a
+ if input in [".", "cwd"]:
+ input = os.getcwd()
+ if o in ["-s", "--show"]:
+ show = 1
+ if o in ["-q", "--quiet"]:
+ quiet = 1
+ if o in ["-t", "--test"]:
+ test = 1
+ if o in ["--convertpage"]:
+ convertpage = 1
+ if o in ["-p", "--profile"]:
+ profile = 1
+ if o in ["-e", "--external"]:
+ form = 'external'
+ if o in ["-m", "--markup"]:
+ markup = str(a)
+ if o in ["-l", "--linenumbers"]:
+ linenumbers = 1
+ if o in ["--header"]:
+ header = str(a)
+ elif o == "-H":
+ header = ''
+ if o in ["--footer"]:
+ footer = str(a)
+ elif o == "-F":
+ footer = ''
+ if o in ["-c", "--color"]:
+ try:
+ colorscheme = globals().get(a.lower())
+ except:
+ traceback.print_exc()
+ Usage()
+ if test:
+ if profile:
+ import profile
+ profile.run('_test(show=%s, quiet=%s)'%(show,quiet))
+ else:
+ # Parse this script in every possible colorscheme and markup
+ _test(show,quiet)
+ elif input in [None, "-", "stdin"] or output in ["-", "stdout"]:
+ # determine if we are going to use stdio
+ if input not in [None, "-", "stdin"]:
+ if os.path.isfile(input) :
+ path2stdout(input, colors=colorscheme, markup=markup,
+ linenumbers=linenumbers, header=header,
+ footer=footer, form=form)
+ else:
+ raise PathError, 'File does not exists!'
+ else:
+ try:
+ if sys.stdin.isatty():
+ raise InputError, 'Please check input!'
+ else:
+ if output in [None,"-","stdout"]:
+ str2stdout(sys.stdin.read(), colors=colorscheme,
+ markup=markup, header=header,
+ footer=footer, linenumbers=linenumbers,
+ form=form)
+ else:
+ str2file(sys.stdin.read(), outfile=output, show=show,
+ markup=markup, header=header, footer=footer,
+ linenumbers=linenumbers, form=form)
+ except:
+ traceback.print_exc()
+ Usage()
+ else:
+ if os.path.exists(input):
+ if convertpage:
+ # if there was at least an input given we can proceed
+ pageconvert(input, out=output, colors=colorscheme,
+ show=show, markup=markup,linenumbers=linenumbers)
+ else:
+ # if there was at least an input given we can proceed
+ convert(source=input, outdir=output, colors=colorscheme,
+ show=show, markup=markup, quiet=quiet, header=header,
+ footer=footer, linenumbers=linenumbers, form=form)
+ else:
+ raise PathError, 'File does not exists!'
+ Usage()
+
+######################################################### Simple markup tests
+
+def _test(show=0, quiet=0):
+ """Test the parser and most of the functions.
+
+ There are 19 test total(eight colorschemes in three diffrent markups,
+ and a str2file test. Most functions are tested by this.
+ """
+ fi = sys.argv[0]
+ if not fi.endswith('.exe'):# Do not test if frozen as an archive
+ # this is a collection of test, most things are covered.
+ path2file(fi, '/tmp/null.html', null, show=show, quiet=quiet)
+ path2file(fi, '/tmp/null_css.html', null, show=show,
+ markup='css', quiet=quiet)
+ path2file(fi, '/tmp/mono.html', mono, show=show, quiet=quiet)
+ path2file(fi, '/tmp/mono_css.html', mono, show=show,
+ markup='css', quiet=quiet)
+ path2file(fi, '/tmp/lite.html', lite, show=show, quiet=quiet)
+ path2file(fi, '/tmp/lite_css.html', lite, show=show,
+ markup='css', quiet=quiet, header='', footer='',
+ linenumbers=1)
+ path2file(fi, '/tmp/lite_xhtml.html', lite, show=show,
+ markup='xhtml', quiet=quiet)
+ path2file(fi, '/tmp/dark.html', dark, show=show, quiet=quiet)
+ path2file(fi, '/tmp/dark_css.html', dark, show=show,
+ markup='css', quiet=quiet, linenumbers=1)
+ path2file(fi, '/tmp/dark2.html', dark2, show=show, quiet=quiet)
+ path2file(fi, '/tmp/dark2_css.html', dark2, show=show,
+ markup='css', quiet=quiet)
+ path2file(fi, '/tmp/dark2_xhtml.html', dark2, show=show,
+ markup='xhtml', quiet=quiet, header='', footer='',
+ linenumbers=1, form='external')
+ path2file(fi, '/tmp/idle.html', idle, show=show, quiet=quiet)
+ path2file(fi, '/tmp/idle_css.html', idle, show=show,
+ markup='css', quiet=quiet)
+ path2file(fi, '/tmp/viewcvs.html', viewcvs, show=show,
+ quiet=quiet, linenumbers=1)
+ path2file(fi, '/tmp/viewcvs_css.html', viewcvs, show=show,
+ markup='css', linenumbers=1, quiet=quiet)
+ path2file(fi, '/tmp/pythonwin.html', pythonwin, show=show,
+ quiet=quiet)
+ path2file(fi, '/tmp/pythonwin_css.html', pythonwin, show=show,
+ markup='css', quiet=quiet)
+ teststr=r'''"""This is a test of decorators and other things"""
+# This should be line 421...
+ at whatever(arg,arg2)
+ at A @B(arghh) @C
+def LlamaSaysNi(arg='Ni!',arg2="RALPH"):
+ """This docstring is deeply disturbed by all the llama references"""
+ print '%s The Wonder Llama says %s'% (arg2,arg)
+# So I was like duh!, and he was like ya know?!,
+# and so we were both like huh...wtf!? RTFM!! LOL!!;)
+ at staticmethod## Double comments are KewL.
+def LlamasRLumpy():
+ """This docstring is too sexy to be here.
+ """
+ u"""
+=============================
+A Møøse once bit my sister...
+=============================
+ """
+ ## Relax, this won't hurt a bit, just a simple, painless procedure,
+ ## hold still while I get the anesthetizing hammer.
+ m = {'three':'1','won':'2','too':'3'}
+ o = r'fishy\fishy\fishy/fish\oh/where/is\my/little\..'
+ python = uR"""
+ No realli! She was Karving her initials øn the møøse with the sharpened end
+ of an interspace tøøthbrush given her by Svenge - her brother-in-law -an Oslo
+ dentist and star of many Norwegian møvies: "The Høt Hands of an Oslo
+ Dentist", "Fillings of Passion", "The Huge Mølars of Horst Nordfink"..."""
+ RU"""142 MEXICAN WHOOPING LLAMAS"""#<-Can you fit 142 llamas in a red box?
+ n = u' HERMSGERVØRDENBRØTBØRDA ' + """ YUTTE """
+ t = """SAMALLNIATNUOMNAIRODAUCE"""+"DENIARTYLLAICEPS04"
+ ## We apologise for the fault in the
+ ## comments. Those responsible have been
+ ## sacked.
+ y = '14 NORTH CHILEAN GUANACOS \
+(CLOSELY RELATED TO THE LLAMA)'
+ rules = [0,1,2,3,4,5]
+ print y'''
+ htmlPath = os.path.abspath('/tmp/strtest_lines.html')
+ str2file(teststr, htmlPath, colors=dark, markup='xhtml',
+ linenumbers=420, show=show)
+ _printinfo(" wrote %s" % htmlPath, quiet)
+ htmlPath = os.path.abspath('/tmp/strtest_nolines.html')
+ str2file(teststr, htmlPath, colors=dark, markup='xhtml',
+ show=show)
+ _printinfo(" wrote %s" % htmlPath, quiet)
+ else:
+ Usage()
+ return
+
+# emacs wants this: '
+
+####################################################### User funtctions
+
+def str2stdout(sourcestring, colors=None, title='', markup='html',
+ header=None, footer=None,
+ linenumbers=0, form=None):
+ """Converts a code(string) to colorized HTML. Writes to stdout.
+
+ form='code',or'snip' (for "<pre>yourcode</pre>" only)
+ colors=null,mono,lite,dark,dark2,idle,or pythonwin
+ """
+ Parser(sourcestring, colors=colors, title=title, markup=markup,
+ header=header, footer=footer,
+ linenumbers=linenumbers).format(form)
+
+def path2stdout(sourcepath, title='', colors=None, markup='html',
+ header=None, footer=None,
+ linenumbers=0, form=None):
+ """Converts code(file) to colorized HTML. Writes to stdout.
+
+ form='code',or'snip' (for "<pre>yourcode</pre>" only)
+ colors=null,mono,lite,dark,dark2,idle,or pythonwin
+ """
+ sourcestring = open(sourcepath).read()
+ Parser(sourcestring, colors=colors, title=sourcepath,
+ markup=markup, header=header, footer=footer,
+ linenumbers=linenumbers).format(form)
+
+def str2html(sourcestring, colors=None, title='',
+ markup='html', header=None, footer=None,
+ linenumbers=0, form=None):
+ """Converts a code(string) to colorized HTML. Returns an HTML string.
+
+ form='code',or'snip' (for "<pre>yourcode</pre>" only)
+ colors=null,mono,lite,dark,dark2,idle,or pythonwin
+ """
+ stringIO = StringIO.StringIO()
+ Parser(sourcestring, colors=colors, title=title, out=stringIO,
+ markup=markup, header=header, footer=footer,
+ linenumbers=linenumbers).format(form)
+ stringIO.seek(0)
+ return stringIO.read()
+
+def str2css(sourcestring, colors=None, title='',
+ markup='css', header=None, footer=None,
+ linenumbers=0, form=None):
+ """Converts a code string to colorized CSS/HTML. Returns CSS/HTML string
+
+ If form != None then this will return (stylesheet_str, code_str)
+ colors=null,mono,lite,dark,dark2,idle,or pythonwin
+ """
+ if markup.lower() not in ['css' ,'xhtml']:
+ markup = 'css'
+ stringIO = StringIO.StringIO()
+ parse = Parser(sourcestring, colors=colors, title=title,
+ out=stringIO, markup=markup,
+ header=header, footer=footer,
+ linenumbers=linenumbers)
+ parse.format(form)
+ stringIO.seek(0)
+ if form != None:
+ return parse._sendCSSStyle(external=1), stringIO.read()
+ else:
+ return None, stringIO.read()
+
+def str2markup(sourcestring, colors=None, title = '',
+ markup='xhtml', header=None, footer=None,
+ linenumbers=0, form=None):
+ """ Convert code strings into ([stylesheet or None], colorized string) """
+ if markup.lower() == 'html':
+ return None, str2html(sourcestring, colors=colors, title=title,
+ header=header, footer=footer, markup=markup,
+ linenumbers=linenumbers, form=form)
+ else:
+ return str2css(sourcestring, colors=colors, title=title,
+ header=header, footer=footer, markup=markup,
+ linenumbers=linenumbers, form=form)
+
+def str2file(sourcestring, outfile, colors=None, title='',
+ markup='html', header=None, footer=None,
+ linenumbers=0, show=0, dosheet=1, form=None):
+ """Converts a code string to a file.
+
+ makes no attempt at correcting bad pathnames
+ """
+ css , html = str2markup(sourcestring, colors=colors, title='',
+ markup=markup, header=header, footer=footer,
+ linenumbers=linenumbers, form=form)
+ # write html
+ f = open(outfile,'wt')
+ f.writelines(html)
+ f.close()
+ #write css
+ if css != None and dosheet:
+ dir = os.path.dirname(outfile)
+ outcss = os.path.join(dir,'pystyle.css')
+ f = open(outcss,'wt')
+ f.writelines(css)
+ f.close()
+ if show:
+ showpage(outfile)
+
+def path2html(sourcepath, colors=None, markup='html',
+ header=None, footer=None,
+ linenumbers=0, form=None):
+ """Converts code(file) to colorized HTML. Returns an HTML string.
+
+ form='code',or'snip' (for "<pre>yourcode</pre>" only)
+ colors=null,mono,lite,dark,dark2,idle,or pythonwin
+ """
+ stringIO = StringIO.StringIO()
+ sourcestring = open(sourcepath).read()
+ Parser(sourcestring, colors, title=sourcepath, out=stringIO,
+ markup=markup, header=header, footer=footer,
+ linenumbers=linenumbers).format(form)
+ stringIO.seek(0)
+ return stringIO.read()
+
+def convert(source, outdir=None, colors=None,
+ show=0, markup='html', quiet=0,
+ header=None, footer=None, linenumbers=0, form=None):
+ """Takes a file or dir as input and places the html in the outdir.
+
+ If outdir is none it defaults to the input dir
+ """
+ count=0
+ # If it is a filename then path2file
+ if not os.path.isdir(source):
+ if os.path.isfile(source):
+ count+=1
+ path2file(source, outdir, colors, show, markup,
+ quiet, form, header, footer, linenumbers, count)
+ else:
+ raise PathError, 'File does not exist!'
+ # If we pass in a dir we need to walkdir for files.
+ # Then we need to colorize them with path2file
+ else:
+ fileList = walkdir(source)
+ if fileList != None:
+ # make sure outdir is a dir
+ if outdir != None:
+ if os.path.splitext(outdir)[1] != '':
+ outdir = os.path.split(outdir)[0]
+ for item in fileList:
+ count+=1
+ path2file(item, outdir, colors, show, markup,
+ quiet, form, header, footer, linenumbers, count)
+ _printinfo('Completed colorizing %s files.'%str(count), quiet)
+ else:
+ _printinfo("No files to convert in dir.", quiet)
+
+def path2file(sourcePath, out=None, colors=None, show=0,
+ markup='html', quiet=0, form=None,
+ header=None, footer=None, linenumbers=0, count=1):
+ """ Converts python source to html file"""
+ # If no outdir is given we use the sourcePath
+ if out == None:#this is a guess
+ htmlPath = sourcePath + '.html'
+ else:
+ # If we do give an out_dir, and it does
+ # not exist , it will be created.
+ if os.path.splitext(out)[1] == '':
+ if not os.path.isdir(out):
+ os.makedirs(out)
+ sourceName = os.path.basename(sourcePath)
+ htmlPath = os.path.join(out,sourceName)+'.html'
+ # If we do give an out_name, and its dir does
+ # not exist , it will be created.
+ else:
+ outdir = os.path.split(out)[0]
+ if not os.path.isdir(outdir):
+ os.makedirs(outdir)
+ htmlPath = out
+ htmlPath = os.path.abspath(htmlPath)
+ # Open the text and do the parsing.
+ source = open(sourcePath).read()
+ parse = Parser(source, colors, sourcePath, open(htmlPath, 'wt'),
+ markup, header, footer, linenumbers)
+ parse.format(form)
+ _printinfo(" wrote %s" % htmlPath, quiet)
+ # html markup will ignore the external flag, but
+ # we need to stop the blank file from being written.
+ if form == 'external' and count == 1 and markup != 'html':
+ cssSheet = parse._sendCSSStyle(external=1)
+ cssPath = os.path.join(os.path.dirname(htmlPath),'pystyle.css')
+ css = open(cssPath, 'wt')
+ css.write(cssSheet)
+ css.close()
+ _printinfo(" wrote %s" % cssPath, quiet)
+ if show:
+ # load HTML page into the default web browser.
+ showpage(htmlPath)
+ return htmlPath
+
+def tagreplace(sourcestr, colors=lite, markup='xhtml',
+ linenumbers=0, dosheet=1, tagstart='<PY>'.lower(),
+ tagend='</PY>'.lower(), stylesheet='pystyle.css'):
+ """This is a helper function for pageconvert. Returns css, page.
+ """
+ if markup.lower() != 'html':
+ link = '<link rel="stylesheet" href="%s" type="text/css"/></head>'
+ css = link%stylesheet
+ if sourcestr.find(css) == -1:
+ sourcestr = sourcestr.replace('</head>', css, 1)
+ starttags = sourcestr.count(tagstart)
+ endtags = sourcestr.count(tagend)
+ if starttags:
+ if starttags == endtags:
+ for _ in range(starttags):
+ datastart = sourcestr.find(tagstart)
+ dataend = sourcestr.find(tagend)
+ data = sourcestr[datastart+len(tagstart):dataend]
+ data = unescape(data)
+ css , data = str2markup(data, colors=colors,
+ linenumbers=linenumbers, markup=markup, form='embed')
+ start = sourcestr[:datastart]
+ end = sourcestr[dataend+len(tagend):]
+ sourcestr = ''.join([start,data,end])
+ else:
+ raise InputError,'Tag mismatch!\nCheck %s,%s tags'%tagstart,tagend
+ if not dosheet:
+ css = None
+ return css, sourcestr
+
+def pageconvert(path, out=None, colors=lite, markup='xhtml', linenumbers=0,
+ dosheet=1, tagstart='<PY>'.lower(), tagend='</PY>'.lower(),
+ stylesheet='pystyle', show=1, returnstr=0):
+ """This function can colorize Python source
+
+ that is written in a webpage enclosed in tags.
+ """
+ if out == None:
+ out = os.path.dirname(path)
+ infile = open(path, 'r').read()
+ css,page = tagreplace(sourcestr=infile,colors=colors,
+ markup=markup, linenumbers=linenumbers, dosheet=dosheet,
+ tagstart=tagstart, tagend=tagend, stylesheet=stylesheet)
+ if not returnstr:
+ newpath = os.path.abspath(os.path.join(
+ out,'tmp', os.path.basename(path)))
+ if not os.path.exists(newpath):
+ try:
+ os.makedirs(os.path.dirname(newpath))
+ except:
+ pass#traceback.print_exc()
+ #Usage()
+ y = open(newpath, 'w')
+ y.write(page)
+ y.close()
+ if css:
+ csspath = os.path.abspath(os.path.join(
+ out,'tmp','%s.css'%stylesheet))
+ x = open(csspath,'w')
+ x.write(css)
+ x.close()
+ if show:
+ try:
+ os.startfile(newpath)
+ except:
+ traceback.print_exc()
+ return newpath
+ else:
+ return css, page
+
+##################################################################### helpers
+
+def walkdir(dir):
+ """Return a list of .py and .pyw files from a given directory.
+
+ This function can be written as a generator Python 2.3, or a genexp
+ in Python 2.4. But 2.2 and 2.1 would be left out....
+ """
+ # Get a list of files that match *.py*
+ GLOB_PATTERN = os.path.join(dir, "*.[p][y]*")
+ pathlist = glob.glob(GLOB_PATTERN)
+ # Now filter out all but py and pyw
+ filterlist = [x for x in pathlist
+ if x.endswith('.py')
+ or x.endswith('.pyw')]
+ if filterlist != []:
+ # if we have a list send it
+ return filterlist
+ else:
+ return None
+
+def showpage(path):
+ """Helper function to open webpages"""
+ try:
+ import webbrowser
+ webbrowser.open_new(os.path.abspath(path))
+ except:
+ traceback.print_exc()
+
+def _printinfo(message, quiet):
+ """Helper to print messages"""
+ if not quiet:
+ print message
+
+def escape(text):
+ """escape text for html. similar to cgi.escape"""
+ text = text.replace("&", "&")
+ text = text.replace("<", "<")
+ text = text.replace(">", ">")
+ return text
+
+def unescape(text):
+ """unsecape escaped text"""
+ text = text.replace(""", '"')
+ text = text.replace(">", ">")
+ text = text.replace("<", "<")
+ text = text.replace("&", "&")
+ return text
+
+########################################################### Custom Exceptions
+
+class PySourceColorError(Exception):
+ # Base for custom errors
+ def __init__(self, msg=''):
+ self._msg = msg
+ Exception.__init__(self, msg)
+ def __repr__(self):
+ return self._msg
+ __str__ = __repr__
+
+class PathError(PySourceColorError):
+ def __init__(self, msg):
+ PySourceColorError.__init__(self,
+ 'Path error! : %s'% msg)
+
+class InputError(PySourceColorError):
+ def __init__(self, msg):
+ PySourceColorError.__init__(self,
+ 'Input error! : %s'% msg)
+
+########################################################## Python code parser
+
+class Parser(object):
+
+ """MoinMoin python parser heavily chopped :)"""
+
+ def __init__(self, raw, colors=None, title='', out=sys.stdout,
+ markup='html', header=None, footer=None, linenumbers=0):
+ """Store the source text & set some flags"""
+ if colors == None:
+ colors = defaultColors
+ self.raw = raw.expandtabs().rstrip()
+ self.title = os.path.basename(title)
+ self.out = out
+ self.line = ''
+ self.lasttext = ''
+ self.argFlag = 0
+ self.classFlag = 0
+ self.defFlag = 0
+ self.decoratorFlag = 0
+ self.external = 0
+ self.markup = markup.upper()
+ self.colors = colors
+ self.header = header
+ self.footer = footer
+ self.doArgs = 1 # overrides the new tokens
+ self.doNames = 1 # overrides the new tokens
+ self.doMathOps = 1 # overrides the new tokens
+ self.doBrackets = 1 # overrides the new tokens
+ self.doURL = 1 # override url conversion
+ self.LINENUMHOLDER = "___line___".upper()
+ self.LINESTART = "___start___".upper()
+ self.skip = 0
+ # add space left side of code for padding.Override in color dict.
+ self.extraspace = self.colors.get(EXTRASPACE, '')
+ # Linenumbers less then zero also have numberlinks
+ self.dolinenums = self.linenum = abs(linenumbers)
+ if linenumbers < 0:
+ self.numberlinks = 1
+ else:
+ self.numberlinks = 0
+
+ def format(self, form=None):
+ """Parse and send the colorized source"""
+ if form in ('snip','code'):
+ self.addEnds = 0
+ elif form == 'embed':
+ self.addEnds = 0
+ self.external = 1
+ else:
+ if form == 'external':
+ self.external = 1
+ self.addEnds = 1
+
+ # Store line offsets in self.lines
+ self.lines = [0, 0]
+ pos = 0
+
+ # Add linenumbers
+ if self.dolinenums:
+ start=self.LINENUMHOLDER+' '+self.extraspace
+ else:
+ start=''+self.extraspace
+ newlines = []
+ lines = self.raw.splitlines(0)
+ for l in lines:
+ # span and div escape for customizing and embedding raw text
+ if (l.startswith('#$#')
+ or l.startswith('#%#')
+ or l.startswith('#@#')):
+ newlines.append(l)
+ else:
+ # kludge for line spans in css,xhtml
+ if self.markup in ['XHTML','CSS']:
+ newlines.append(self.LINESTART+' '+start+l)
+ else:
+ newlines.append(start+l)
+ self.raw = "\n".join(newlines)+'\n'# plus an extra newline at the end
+
+ # Gather lines
+ while 1:
+ pos = self.raw.find('\n', pos) + 1
+ if not pos: break
+ self.lines.append(pos)
+ self.lines.append(len(self.raw))
+
+ # Wrap text in a filelike object
+ self.pos = 0
+ text = StringIO.StringIO(self.raw)
+
+ # Markup start
+ if self.addEnds:
+ self._doPageStart()
+ else:
+ self._doSnippetStart()
+
+ ## Tokenize calls the __call__
+ ## function for each token till done.
+ # Parse the source and write out the results.
+ try:
+ tokenize.tokenize(text.readline, self)
+ except tokenize.TokenError, ex:
+ msg = ex[0]
+ line = ex[1][0]
+ self.out.write("<h3>ERROR: %s</h3>%s\n"%
+ (msg, self.raw[self.lines[line]:]))
+ #traceback.print_exc()
+
+ # Markup end
+ if self.addEnds:
+ self._doPageEnd()
+ else:
+ self._doSnippetEnd()
+
+ def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
+ """Token handler. Order is important do not rearrange."""
+ self.line = line
+ # Calculate new positions
+ oldpos = self.pos
+ newpos = self.lines[srow] + scol
+ self.pos = newpos + len(toktext)
+ # Handle newlines
+ if toktype in (token.NEWLINE, tokenize.NL):
+ self.decoratorFlag = self.argFlag = 0
+ # kludge for line spans in css,xhtml
+ if self.markup in ['XHTML','CSS']:
+ self.out.write('</span>')
+ self.out.write('\n')
+ return
+
+ # Send the original whitespace, and tokenize backslashes if present.
+ # Tokenizer.py just sends continued line backslashes with whitespace.
+ # This is a hack to tokenize continued line slashes as operators.
+ # Should continued line backslashes be treated as operators
+ # or some other token?
+
+ if newpos > oldpos:
+ if self.raw[oldpos:newpos].isspace():
+ # consume a single space after linestarts and linenumbers
+ # had to have them so tokenizer could seperate them.
+ # multiline strings are handled by do_Text functions
+ if self.lasttext != self.LINESTART \
+ and self.lasttext != self.LINENUMHOLDER:
+ self.out.write(self.raw[oldpos:newpos])
+ else:
+ self.out.write(self.raw[oldpos+1:newpos])
+ else:
+ slash = self.raw[oldpos:newpos].find('\\')+oldpos
+ self.out.write(self.raw[oldpos:slash])
+ getattr(self, '_send%sText'%(self.markup))(OPERATOR, '\\')
+ self.linenum+=1
+ # kludge for line spans in css,xhtml
+ if self.markup in ['XHTML','CSS']:
+ self.out.write('</span>')
+ self.out.write(self.raw[slash+1:newpos])
+
+ # Skip indenting tokens
+ if toktype in (token.INDENT, token.DEDENT):
+ self.pos = newpos
+ return
+
+ # Look for operators
+ if token.LPAR <= toktype and toktype <= token.OP:
+ # Trap decorators py2.4 >
+ if toktext == '@':
+ toktype = DECORATOR
+ # Set a flag if this was the decorator start so
+ # the decorator name and arguments can be identified
+ self.decoratorFlag = self.argFlag = 1
+ else:
+ if self.doArgs:
+ # Find the start for arguments
+ if toktext == '(' and self.argFlag:
+ self.argFlag = 2
+ # Find the end for arguments
+ elif toktext == ':':
+ self.argFlag = 0
+ ## Seperate the diffrent operator types
+ # Brackets
+ if self.doBrackets and toktext in ['[',']','(',')','{','}']:
+ toktype = BRACKETS
+ # Math operators
+ elif self.doMathOps and toktext in ['*=','**=','-=','+=','|=',
+ '%=','>>=','<<=','=','^=',
+ '/=', '+','-','**','*','/','%']:
+ toktype = MATH_OPERATOR
+ # Operator
+ else:
+ toktype = OPERATOR
+ # example how flags should work.
+ # def fun(arg=argvalue,arg2=argvalue2):
+ # 0 1 2 A 1 N 2 A 1 N 0
+ if toktext == "=" and self.argFlag == 2:
+ self.argFlag = 1
+ elif toktext == "," and self.argFlag == 1:
+ self.argFlag = 2
+ # Look for keywords
+ elif toktype == NAME and keyword.iskeyword(toktext):
+ toktype = KEYWORD
+ # Set a flag if this was the class / def start so
+ # the class / def name and arguments can be identified
+ if toktext in ['class', 'def']:
+ if toktext =='class' and \
+ not line[:line.find('class')].endswith('.'):
+ self.classFlag = self.argFlag = 1
+ elif toktext == 'def' and \
+ not line[:line.find('def')].endswith('.'):
+ self.defFlag = self.argFlag = 1
+ else:
+ # must have used a keyword as a name i.e. self.class
+ toktype = ERRORTOKEN
+
+ # Look for class, def, decorator name
+ elif (self.classFlag or self.defFlag or self.decoratorFlag) \
+ and self.doNames:
+ if self.classFlag:
+ self.classFlag = 0
+ toktype = CLASS_NAME
+ elif self.defFlag:
+ self.defFlag = 0
+ toktype = DEF_NAME
+ elif self.decoratorFlag:
+ self.decoratorFlag = 0
+ toktype = DECORATOR_NAME
+
+ # Look for strings
+ # Order of evaluation is important do not change.
+ elif toktype == token.STRING:
+ text = toktext.lower()
+ # TRIPLE DOUBLE QUOTE's
+ if (text[:3] == '"""'):
+ toktype = TRIPLEDOUBLEQUOTE
+ elif (text[:4] == 'r"""'):
+ toktype = TRIPLEDOUBLEQUOTE_R
+ elif (text[:4] == 'u"""' or
+ text[:5] == 'ur"""'):
+ toktype = TRIPLEDOUBLEQUOTE_U
+ # DOUBLE QUOTE's
+ elif (text[:1] == '"'):
+ toktype = DOUBLEQUOTE
+ elif (text[:2] == 'r"'):
+ toktype = DOUBLEQUOTE_R
+ elif (text[:2] == 'u"' or
+ text[:3] == 'ur"'):
+ toktype = DOUBLEQUOTE_U
+ # TRIPLE SINGLE QUOTE's
+ elif (text[:3] == "'''"):
+ toktype = TRIPLESINGLEQUOTE
+ elif (text[:4] == "r'''"):
+ toktype = TRIPLESINGLEQUOTE_R
+ elif (text[:4] == "u'''" or
+ text[:5] == "ur'''"):
+ toktype = TRIPLESINGLEQUOTE_U
+ # SINGLE QUOTE's
+ elif (text[:1] == "'"):
+ toktype = SINGLEQUOTE
+ elif (text[:2] == "r'"):
+ toktype = SINGLEQUOTE_R
+ elif (text[:2] == "u'" or
+ text[:3] == "ur'"):
+ toktype = SINGLEQUOTE_U
+
+ # test for invalid string declaration
+ if self.lasttext.lower() == 'ru':
+ toktype = ERRORTOKEN
+
+ # Look for comments
+ elif toktype == COMMENT:
+ if toktext[:2] == "##":
+ toktype = DOUBLECOMMENT
+ elif toktext[:3] == '#$#':
+ toktype = TEXT
+ self.textFlag = 'SPAN'
+ toktext = toktext[3:]
+ elif toktext[:3] == '#%#':
+ toktype = TEXT
+ self.textFlag = 'DIV'
+ toktext = toktext[3:]
+ elif toktext[:3] == '#@#':
+ toktype = TEXT
+ self.textFlag = 'RAW'
+ toktext = toktext[3:]
+ if self.doURL:
+ # this is a 'fake helper function'
+ # url(URI,Alias_name) or url(URI)
+ url_pos = toktext.find('url(')
+ if url_pos != -1:
+ before = toktext[:url_pos]
+ url = toktext[url_pos+4:]
+ splitpoint = url.find(',')
+ endpoint = url.find(')')
+ after = url[endpoint+1:]
+ url = url[:endpoint]
+ if splitpoint != -1:
+ urlparts = url.split(',',1)
+ toktext = '%s<a href="%s">%s</a>%s'%(
+ before,urlparts[0],urlparts[1].lstrip(),after)
+ else:
+ toktext = '%s<a href="%s">%s</a>%s'%(before,url,url,after)
+
+ # Seperate errors from decorators
+ elif toktype == ERRORTOKEN:
+ # Bug fix for < py2.4
+ # space between decorators
+ if self.argFlag and toktext.isspace():
+ #toktype = NAME
+ self.out.write(toktext)
+ return
+ # Bug fix for py2.2 linenumbers with decorators
+ elif toktext.isspace():
+ # What if we have a decorator after a >>> or ...
+ #p = line.find('@')
+ #if p >= 0 and not line[:p].isspace():
+ #self.out.write(toktext)
+ #return
+ if self.skip:
+ self.skip=0
+ return
+ else:
+ self.out.write(toktext)
+ return
+ # trap decorators < py2.4
+ elif toktext == '@':
+ toktype = DECORATOR
+ # Set a flag if this was the decorator start so
+ # the decorator name and arguments can be identified
+ self.decoratorFlag = self.argFlag = 1
+
+ # Seperate args from names
+ elif (self.argFlag == 2 and
+ toktype == NAME and
+ toktext != 'None' and
+ self.doArgs):
+ toktype = ARGS
+
+ # Look for line numbers
+ # The conversion code for them is in the send_text functions.
+ if toktext in [self.LINENUMHOLDER,self.LINESTART]:
+ toktype = LINENUMBER
+ # if we don't have linenumbers set flag
+ # to skip the trailing space from linestart
+ if toktext == self.LINESTART and not self.dolinenums \
+ or toktext == self.LINENUMHOLDER:
+ self.skip=1
+
+
+ # Skip blank token that made it thru
+ ## bugfix for the last empty tag.
+ if toktext == '':
+ return
+
+ # Last token text history
+ self.lasttext = toktext
+
+ # escape all but the urls in the comments
+ if toktype in (DOUBLECOMMENT, COMMENT):
+ if toktext.find('<a href=') == -1:
+ toktext = escape(toktext)
+ else:
+ pass
+ elif toktype == TEXT:
+ pass
+ else:
+ toktext = escape(toktext)
+
+ # Send text for any markup
+ getattr(self, '_send%sText'%(self.markup))(toktype, toktext)
+ return
+
+ ################################################################# Helpers
+
+ def _doSnippetStart(self):
+ if self.markup == 'HTML':
+ # Start of html snippet
+ self.out.write('<pre>\n')
+ else:
+ # Start of css/xhtml snippet
+ self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
+
+ def _doSnippetEnd(self):
+ # End of html snippet
+ self.out.write(self.colors.get(CODEEND,'</pre>\n'))
+
+ ######################################################## markup selectors
+
+ def _getFile(self, filepath):
+ try:
+ _file = open(filepath,'r')
+ content = _file.read()
+ _file.close()
+ except:
+ traceback.print_exc()
+ content = ''
+ return content
+
+ def _doPageStart(self):
+ getattr(self, '_do%sStart'%(self.markup))()
+
+ def _doPageHeader(self):
+ if self.header != None:
+ if self.header.find('#$#') != -1 or \
+ self.header.find('#$#') != -1 or \
+ self.header.find('#%#') != -1:
+ self.out.write(self.header[3:])
+ else:
+ if self.header != '':
+ self.header = self._getFile(self.header)
+ getattr(self, '_do%sHeader'%(self.markup))()
+
+ def _doPageFooter(self):
+ if self.footer != None:
+ if self.footer.find('#$#') != -1 or \
+ self.footer.find('#@#') != -1 or \
+ self.footer.find('#%#') != -1:
+ self.out.write(self.footer[3:])
+ else:
+ if self.footer != '':
+ self.footer = self._getFile(self.footer)
+ getattr(self, '_do%sFooter'%(self.markup))()
+
+ def _doPageEnd(self):
+ getattr(self, '_do%sEnd'%(self.markup))()
+
+ ################################################### color/style retrieval
+ ## Some of these are not used anymore but are kept for documentation
+
+ def _getLineNumber(self):
+ num = self.linenum
+ self.linenum+=1
+ return str(num).rjust(5)+" "
+
+ def _getTags(self, key):
+ # style tags
+ return self.colors.get(key, self.colors[NAME])[0]
+
+ def _getForeColor(self, key):
+ # get text foreground color, if not set to black
+ color = self.colors.get(key, self.colors[NAME])[1]
+ if color[:1] != '#':
+ color = '#000000'
+ return color
+
+ def _getBackColor(self, key):
+ # get text background color
+ return self.colors.get(key, self.colors[NAME])[2]
+
+ def _getPageColor(self):
+ # get page background color
+ return self.colors.get(PAGEBACKGROUND, '#FFFFFF')
+
+ def _getStyle(self, key):
+ # get the token style from the color dictionary
+ return self.colors.get(key, self.colors[NAME])
+
+ def _getMarkupClass(self, key):
+ # get the markup class name from the markup dictionary
+ return MARKUPDICT.get(key, MARKUPDICT[NAME])
+
+ def _getDocumentCreatedBy(self):
+ return '<!--This document created by %s ver.%s on: %s-->\n'%(
+ __title__,__version__,time.ctime())
+
+ ################################################### HTML markup functions
+
+ def _doHTMLStart(self):
+ # Start of html page
+ self.out.write('<!DOCTYPE html PUBLIC \
+"-//W3C//DTD HTML 4.01//EN">\n')
+ self.out.write('<html><head><title>%s</title>\n'%(self.title))
+ self.out.write(self._getDocumentCreatedBy())
+ self.out.write('<meta http-equiv="Content-Type" \
+content="text/html;charset=iso-8859-1">\n')
+ # Get background
+ self.out.write('</head><body bgcolor="%s">\n'%self._getPageColor())
+ self._doPageHeader()
+ self.out.write('<pre>')
+
+ def _getHTMLStyles(self, toktype, toktext):
+ # Get styles
+ tags, color = self.colors.get(toktype, self.colors[NAME])[:2]#
+ tagstart=[]
+ tagend=[]
+ # check for styles and set them if needed.
+ if 'b' in tags:#Bold
+ tagstart.append('<b>')
+ tagend.append('</b>')
+ if 'i' in tags:#Italics
+ tagstart.append('<i>')
+ tagend.append('</i>')
+ if 'u' in tags:#Underline
+ tagstart.append('<u>')
+ tagend.append('</u>')
+ # HTML tags should be paired like so : <b><i><u>Doh!</u></i></b>
+ tagend.reverse()
+ starttags="".join(tagstart)
+ endtags="".join(tagend)
+ return starttags,endtags,color
+
+ def _sendHTMLText(self, toktype, toktext):
+ numberlinks = self.numberlinks
+
+ # If it is an error, set a red box around the bad tokens
+ # older browsers should ignore it
+ if toktype == ERRORTOKEN:
+ style = ' style="border: solid 1.5pt #FF0000;"'
+ else:
+ style = ''
+ # Get styles
+ starttag, endtag, color = self._getHTMLStyles(toktype, toktext)
+ # This is a hack to 'fix' multi-line strings.
+ # Multi-line strings are treated as only one token
+ # even though they can be several physical lines.
+ # That makes it hard to spot the start of a line,
+ # because at this level all we know about are tokens.
+
+ if toktext.count(self.LINENUMHOLDER):
+ # rip apart the string and separate it by line.
+ # count lines and change all linenum token to line numbers.
+ # embedded all the new font tags inside the current one.
+ # Do this by ending the tag first then writing our new tags,
+ # then starting another font tag exactly like the first one.
+ if toktype == LINENUMBER:
+ splittext = toktext.split(self.LINENUMHOLDER)
+ else:
+ splittext = toktext.split(self.LINENUMHOLDER+' ')
+ store = []
+ store.append(splittext.pop(0))
+ lstarttag, lendtag, lcolor = self._getHTMLStyles(LINENUMBER, toktext)
+ count = len(splittext)
+ for item in splittext:
+ num = self._getLineNumber()
+ if numberlinks:
+ numstrip = num.strip()
+ content = '<a name="%s" href="#%s">%s</a>' \
+ %(numstrip,numstrip,num)
+ else:
+ content = num
+ if count <= 1:
+ endtag,starttag = '',''
+ linenumber = ''.join([endtag,'<font color=', lcolor, '>',
+ lstarttag, content, lendtag, '</font>' ,starttag])
+ store.append(linenumber+item)
+ toktext = ''.join(store)
+ # send text
+ ## Output optimization
+ # skip font tag if black text, but styles will still be sent. (b,u,i)
+ if color !='#000000':
+ startfont = '<font color="%s"%s>'%(color, style)
+ endfont = '</font>'
+ else:
+ startfont, endfont = ('','')
+ if toktype != LINENUMBER:
+ self.out.write(''.join([startfont,starttag,
+ toktext,endtag,endfont]))
+ else:
+ self.out.write(toktext)
+ return
+
+ def _doHTMLHeader(self):
+ # Optional
+ if self.header != '':
+ self.out.write('%s\n'%self.header)
+ else:
+ color = self._getForeColor(NAME)
+ self.out.write('<b><font color="%s"># %s \
+ <br># %s</font></b><hr>\n'%
+ (color, self.title, time.ctime()))
+
+ def _doHTMLFooter(self):
+ # Optional
+ if self.footer != '':
+ self.out.write('%s\n'%self.footer)
+ else:
+ color = self._getForeColor(NAME)
+ self.out.write('<b><font color="%s"> \
+ <hr># %s<br># %s</font></b>\n'%
+ (color, self.title, time.ctime()))
+
+ def _doHTMLEnd(self):
+ # End of html page
+ self.out.write('</pre>\n')
+ # Write a little info at the bottom
+ self._doPageFooter()
+ self.out.write('</body></html>\n')
+
+ #################################################### CSS markup functions
+
+ def _getCSSStyle(self, key):
+ # Get the tags and colors from the dictionary
+ tags, forecolor, backcolor = self._getStyle(key)
+ style=[]
+ border = None
+ bordercolor = None
+ tags = tags.lower()
+ if tags:
+ # get the border color if specified
+ # the border color will be appended to
+ # the list after we define a border
+ if '#' in tags:# border color
+ start = tags.find('#')
+ end = start + 7
+ bordercolor = tags[start:end]
+ tags.replace(bordercolor,'',1)
+ # text styles
+ if 'b' in tags:# Bold
+ style.append('font-weight:bold;')
+ else:
+ style.append('font-weight:normal;')
+ if 'i' in tags:# Italic
+ style.append('font-style:italic;')
+ if 'u' in tags:# Underline
+ style.append('text-decoration:underline;')
+ # border size
+ if 'l' in tags:# thick border
+ size='thick'
+ elif 'm' in tags:# medium border
+ size='medium'
+ elif 't' in tags:# thin border
+ size='thin'
+ else:# default
+ size='medium'
+ # border styles
+ if 'n' in tags:# inset border
+ border='inset'
+ elif 'o' in tags:# outset border
+ border='outset'
+ elif 'r' in tags:# ridge border
+ border='ridge'
+ elif 'g' in tags:# groove border
+ border='groove'
+ elif '=' in tags:# double border
+ border='double'
+ elif '.' in tags:# dotted border
+ border='dotted'
+ elif '-' in tags:# dashed border
+ border='dashed'
+ elif 's' in tags:# solid border
+ border='solid'
+ # border type check
+ seperate_sides=0
+ for side in ['<','>','^','v']:
+ if side in tags:
+ seperate_sides+=1
+ # border box or seperate sides
+ if seperate_sides==0 and border:
+ style.append('border: %s %s;'%(border,size))
+ else:
+ if border == None:
+ border = 'solid'
+ if 'v' in tags:# bottom border
+ style.append('border-bottom:%s %s;'%(border,size))
+ if '<' in tags:# left border
+ style.append('border-left:%s %s;'%(border,size))
+ if '>' in tags:# right border
+ style.append('border-right:%s %s;'%(border,size))
+ if '^' in tags:# top border
+ style.append('border-top:%s %s;'%(border,size))
+ else:
+ style.append('font-weight:normal;')# css inherited style fix
+ # we have to define our borders before we set colors
+ if bordercolor:
+ style.append('border-color:%s;'%bordercolor)
+ # text forecolor
+ style.append('color:%s;'% forecolor)
+ # text backcolor
+ if backcolor:
+ style.append('background-color:%s;'%backcolor)
+ return (self._getMarkupClass(key),' '.join(style))
+
+ def _sendCSSStyle(self, external=0):
+ """ create external and internal style sheets"""
+ styles = []
+ external += self.external
+ if not external:
+ styles.append('<style type="text/css">\n<!--\n')
+ # Get page background color and write styles ignore any we don't know
+ styles.append('body { background:%s; }\n'%self._getPageColor())
+ # write out the various css styles
+ for key in MARKUPDICT:
+ styles.append('.%s { %s }\n'%self._getCSSStyle(key))
+ # If you want to style the pre tag you must modify the color dict.
+ # Example:
+ # lite[PY] = .py {border: solid thin #000000;background:#555555}\n'''
+ styles.append(self.colors.get(PY, '.py { }\n'))
+ # Extra css can be added here
+ # add CSSHOOK to the color dict if you need it.
+ # Example:
+ #lite[CSSHOOK] = """.mytag { border: solid thin #000000; } \n
+ # .myothertag { font-weight:bold; )\n"""
+ styles.append(self.colors.get(CSSHOOK,''))
+ if not self.external:
+ styles.append('--></style>\n')
+ return ''.join(styles)
+
+ def _doCSSStart(self):
+ # Start of css/html 4.01 page
+ self.out.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">\n')
+ self.out.write('<html><head><title>%s</title>\n'%(self.title))
+ self.out.write(self._getDocumentCreatedBy())
+ self.out.write('<meta http-equiv="Content-Type" \
+content="text/html;charset=iso-8859-1">\n')
+ self._doCSSStyleSheet()
+ self.out.write('</head>\n<body>\n')
+ # Write a little info at the top.
+ self._doPageHeader()
+ self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
+ return
+
+ def _doCSSStyleSheet(self):
+ if not self.external:
+ # write an embedded style sheet
+ self.out.write(self._sendCSSStyle())
+ else:
+ # write a link to an external style sheet
+ self.out.write('<link rel="stylesheet" \
+href="pystyle.css" type="text/css">')
+ return
+
+ def _sendCSSText(self, toktype, toktext):
+ # This is a hack to 'fix' multi-line strings.
+ # Multi-line strings are treated as only one token
+ # even though they can be several physical lines.
+ # That makes it hard to spot the start of a line,
+ # because at this level all we know about are tokens.
+ markupclass = MARKUPDICT.get(toktype, MARKUPDICT[NAME])
+ # if it is a LINENUMBER type then we can skip the rest
+ if toktext == self.LINESTART and toktype == LINENUMBER:
+ self.out.write('<span class="py_line">')
+ return
+ if toktext.count(self.LINENUMHOLDER):
+ # rip apart the string and separate it by line
+ # count lines and change all linenum token to line numbers
+ # also convert linestart and lineend tokens
+ # <linestart> <lnumstart> lnum <lnumend> text <lineend>
+ #################################################
+ newmarkup = MARKUPDICT.get(LINENUMBER, MARKUPDICT[NAME])
+ lstartspan = '<span class="%s">'%(newmarkup)
+ if toktype == LINENUMBER:
+ splittext = toktext.split(self.LINENUMHOLDER)
+ else:
+ splittext = toktext.split(self.LINENUMHOLDER+' ')
+ store = []
+ # we have already seen the first linenumber token
+ # so we can skip the first one
+ store.append(splittext.pop(0))
+ for item in splittext:
+ num = self._getLineNumber()
+ if self.numberlinks:
+ numstrip = num.strip()
+ content= '<a name="%s" href="#%s">%s</a>' \
+ %(numstrip,numstrip,num)
+ else:
+ content = num
+ linenumber= ''.join([lstartspan,content,'</span>'])
+ store.append(linenumber+item)
+ toktext = ''.join(store)
+ if toktext.count(self.LINESTART):
+ # wraps the textline in a line span
+ # this adds a lot of kludges, is it really worth it?
+ store = []
+ parts = toktext.split(self.LINESTART+' ')
+ # handle the first part differently
+ # the whole token gets wraqpped in a span later on
+ first = parts.pop(0)
+ # place spans before the newline
+ pos = first.rfind('\n')
+ if pos != -1:
+ first=first[:pos]+'</span></span>'+first[pos:]
+ store.append(first)
+ #process the rest of the string
+ for item in parts:
+ #handle line numbers if present
+ if self.dolinenums:
+ item = item.replace('</span>',
+ '</span><span class="%s">'%(markupclass))
+ else:
+ item = '<span class="%s">%s'%(markupclass,item)
+ # add endings for line and string tokens
+ pos = item.rfind('\n')
+ if pos != -1:
+ item=item[:pos]+'</span></span>\n'
+ store.append(item)
+ # add start tags for lines
+ toktext = '<span class="py_line">'.join(store)
+ # Send text
+ if toktype != LINENUMBER:
+ if toktype == TEXT and self.textFlag == 'DIV':
+ startspan = '<div class="%s">'%(markupclass)
+ endspan = '</div>'
+ elif toktype == TEXT and self.textFlag == 'RAW':
+ startspan,endspan = ('','')
+ else:
+ startspan = '<span class="%s">'%(markupclass)
+ endspan = '</span>'
+ self.out.write(''.join([startspan, toktext, endspan]))
+ else:
+ self.out.write(toktext)
+ return
+
+ def _doCSSHeader(self):
+ if self.header != '':
+ self.out.write('%s\n'%self.header)
+ else:
+ name = MARKUPDICT.get(NAME)
+ self.out.write('<div class="%s"># %s <br> \
+# %s</div><hr>\n'%(name, self.title, time.ctime()))
+
+ def _doCSSFooter(self):
+ # Optional
+ if self.footer != '':
+ self.out.write('%s\n'%self.footer)
+ else:
+ self.out.write('<hr><div class="%s"># %s <br> \
+# %s</div>\n'%(MARKUPDICT.get(NAME),self.title, time.ctime()))
+
+ def _doCSSEnd(self):
+ # End of css/html page
+ self.out.write(self.colors.get(CODEEND,'</pre>\n'))
+ # Write a little info at the bottom
+ self._doPageFooter()
+ self.out.write('</body></html>\n')
+ return
+
+ ################################################## XHTML markup functions
+
+ def _doXHTMLStart(self):
+ # XHTML is really just XML + HTML 4.01.
+ # We only need to change the page headers,
+ # and a few tags to get valid XHTML.
+ # Start of xhtml page
+ self.out.write('<?xml version="1.0"?>\n \
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n \
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n \
+<html xmlns="http://www.w3.org/1999/xhtml">\n')
+ self.out.write('<head><title>%s</title>\n'%(self.title))
+ self.out.write(self._getDocumentCreatedBy())
+ self.out.write('<meta http-equiv="Content-Type" \
+content="text/html;charset=iso-8859-1"/>\n')
+ self._doXHTMLStyleSheet()
+ self.out.write('</head>\n<body>\n')
+ # Write a little info at the top.
+ self._doPageHeader()
+ self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
+ return
+
+ def _doXHTMLStyleSheet(self):
+ if not self.external:
+ # write an embedded style sheet
+ self.out.write(self._sendCSSStyle())
+ else:
+ # write a link to an external style sheet
+ self.out.write('<link rel="stylesheet" \
+href="pystyle.css" type="text/css"/>\n')
+ return
+
+ def _sendXHTMLText(self, toktype, toktext):
+ self._sendCSSText(toktype, toktext)
+
+ def _doXHTMLHeader(self):
+ # Optional
+ if self.header:
+ self.out.write('%s\n'%self.header)
+ else:
+ name = MARKUPDICT.get(NAME)
+ self.out.write('<div class="%s"># %s <br/> \
+# %s</div><hr/>\n '%(
+ name, self.title, time.ctime()))
+
+ def _doXHTMLFooter(self):
+ # Optional
+ if self.footer:
+ self.out.write('%s\n'%self.footer)
+ else:
+ self.out.write('<hr/><div class="%s"># %s <br/> \
+# %s</div>\n'%(MARKUPDICT.get(NAME), self.title, time.ctime()))
+
+ def _doXHTMLEnd(self):
+ self._doCSSEnd()
+
+#############################################################################
+
+if __name__ == '__main__':
+ cli()
+
+#############################################################################
+# PySourceColor.py
+# 2004, 2005 M.E.Farmer Jr.
+# Python license
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/UserDict24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/UserDict24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/UserDict24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,167 @@
+"""A more or less complete user-defined wrapper around dictionary objects."""
+
+class UserDict:
+ def __init__(self, dict=None, **kwargs):
+ self.data = {}
+ if dict is not None:
+ if not hasattr(dict,'keys'):
+ dict = type({})(dict) # make mapping from a sequence
+ self.update(dict)
+ if len(kwargs):
+ self.update(kwargs)
+ def __repr__(self): return repr(self.data)
+ def __cmp__(self, dict):
+ if isinstance(dict, UserDict):
+ return cmp(self.data, dict.data)
+ else:
+ return cmp(self.data, dict)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, key): return self.data[key]
+ def __setitem__(self, key, item): self.data[key] = item
+ def __delitem__(self, key): del self.data[key]
+ def clear(self): self.data.clear()
+ def copy(self):
+ if self.__class__ is UserDict:
+ return UserDict(self.data)
+ import copy
+ data = self.data
+ try:
+ self.data = {}
+ c = copy.copy(self)
+ finally:
+ self.data = data
+ c.update(self)
+ return c
+ def keys(self): return self.data.keys()
+ def items(self): return self.data.items()
+ def iteritems(self): return self.data.iteritems()
+ def iterkeys(self): return self.data.iterkeys()
+ def itervalues(self): return self.data.itervalues()
+ def values(self): return self.data.values()
+ def has_key(self, key): return self.data.has_key(key)
+ def update(self, dict):
+ if isinstance(dict, UserDict):
+ self.data.update(dict.data)
+ elif isinstance(dict, type(self.data)):
+ self.data.update(dict)
+ else:
+ for k, v in dict.items():
+ self[k] = v
+ def get(self, key, failobj=None):
+ if not self.has_key(key):
+ return failobj
+ return self[key]
+ def setdefault(self, key, failobj=None):
+ if not self.has_key(key):
+ self[key] = failobj
+ return self[key]
+ def pop(self, key, *args):
+ return self.data.pop(key, *args)
+ def popitem(self):
+ return self.data.popitem()
+ def __contains__(self, key):
+ return key in self.data
+ def fromkeys(cls, iterable, value=None):
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+ fromkeys = classmethod(fromkeys)
+
+class IterableUserDict(UserDict):
+ def __iter__(self):
+ return iter(self.data)
+
+class DictMixin:
+ # Mixin defining all dictionary methods for classes that already have
+ # a minimum dictionary interface including getitem, setitem, delitem,
+ # and keys. Without knowledge of the subclass constructor, the mixin
+ # does not define __init__() or copy(). In addition to the four base
+ # methods, progressively more efficiency comes with defining
+ # __contains__(), __iter__(), and iteritems().
+
+ # second level definitions support higher levels
+ def __iter__(self):
+ for k in self.keys():
+ yield k
+ def has_key(self, key):
+ try:
+ value = self[key]
+ except KeyError:
+ return False
+ return True
+ def __contains__(self, key):
+ return self.has_key(key)
+
+ # third level takes advantage of second level definitions
+ def iteritems(self):
+ for k in self:
+ yield (k, self[k])
+ def iterkeys(self):
+ return self.__iter__()
+
+ # fourth level uses definitions from lower levels
+ def itervalues(self):
+ for _, v in self.iteritems():
+ yield v
+ def values(self):
+ return [v for _, v in self.iteritems()]
+ def items(self):
+ return list(self.iteritems())
+ def clear(self):
+ for key in self.keys():
+ del self[key]
+ def setdefault(self, key, default):
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return default
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError, "pop expected at most 2 arguments, got "\
+ + repr(1 + len(args))
+ try:
+ value = self[key]
+ except KeyError:
+ if args:
+ return args[0]
+ raise
+ del self[key]
+ return value
+ def popitem(self):
+ try:
+ k, v = self.iteritems().next()
+ except StopIteration:
+ raise KeyError, 'container is empty'
+ del self[k]
+ return (k, v)
+ def update(self, other):
+ # Make progressively weaker assumptions about "other"
+ if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
+ for k, v in other.iteritems():
+ self[k] = v
+ elif hasattr(other, '__iter__'): # iter saves memory
+ for k in other:
+ self[k] = other[k]
+ else:
+ for k in other.keys():
+ self[k] = other[k]
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+ def __repr__(self):
+ return repr(dict(self.iteritems()))
+ def __cmp__(self, other):
+ if other is None:
+ return 1
+ if isinstance(other, DictMixin):
+ other = dict(other.iteritems())
+ return cmp(dict(self.iteritems()), other)
+ def __len__(self):
+ return len(self.keys())
+
+ def __nonzero__(self):
+ return bool(self.iteritems())
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+"""
+Package for miscellaneous routines that do not depend on other parts
+of Paste
+"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinit.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinit.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinit.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,42 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+class ClassInitMeta(type):
+
+ def __new__(meta, class_name, bases, new_attrs):
+ cls = type.__new__(meta, class_name, bases, new_attrs)
+ if (new_attrs.has_key('__classinit__')
+ and not isinstance(cls.__classinit__, staticmethod)):
+ setattr(cls, '__classinit__',
+ staticmethod(cls.__classinit__.im_func))
+ if hasattr(cls, '__classinit__'):
+ cls.__classinit__(cls, new_attrs)
+ return cls
+
+def build_properties(cls, new_attrs):
+ """
+ Given a class and a new set of attributes (as passed in by
+ __classinit__), create or modify properties based on functions
+ with special names ending in __get, __set, and __del.
+ """
+ for name, value in new_attrs.items():
+ if (name.endswith('__get') or name.endswith('__set')
+ or name.endswith('__del')):
+ base = name[:-5]
+ if hasattr(cls, base):
+ old_prop = getattr(cls, base)
+ if not isinstance(old_prop, property):
+ raise ValueError(
+ "Attribute %s is a %s, not a property; function %s is named like a property"
+ % (base, type(old_prop), name))
+ attrs = {'fget': old_prop.fget,
+ 'fset': old_prop.fset,
+ 'fdel': old_prop.fdel,
+ 'doc': old_prop.__doc__}
+ else:
+ attrs = {}
+ attrs['f' + name[-3:]] = value
+ if name.endswith('__get') and value.__doc__:
+ attrs['doc'] = value.__doc__
+ new_prop = property(**attrs)
+ setattr(cls, base, new_prop)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinstance.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinstance.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/classinstance.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,38 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+class classinstancemethod(object):
+ """
+ Acts like a class method when called from a class, like an
+ instance method when called by an instance. The method should
+ take two arguments, 'self' and 'cls'; one of these will be None
+ depending on how the method was called.
+ """
+
+ def __init__(self, func):
+ self.func = func
+ self.__doc__ = func.__doc__
+
+ def __get__(self, obj, type=None):
+ return _methodwrapper(self.func, obj=obj, type=type)
+
+class _methodwrapper(object):
+
+ def __init__(self, func, obj, type):
+ self.func = func
+ self.obj = obj
+ self.type = type
+
+ def __call__(self, *args, **kw):
+ assert not kw.has_key('self') and not kw.has_key('cls'), (
+ "You cannot use 'self' or 'cls' arguments to a "
+ "classinstancemethod")
+ return self.func(*((self.obj, self.type) + args), **kw)
+
+ def __repr__(self):
+ if self.obj is None:
+ return ('<bound class method %s.%s>'
+ % (self.type.__name__, self.func.func_name))
+ else:
+ return ('<bound method %s.%s of %r>'
+ % (self.type.__name__, self.func.func_name, self.obj))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/converters.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/converters.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/converters.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,26 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+def asbool(obj):
+ if isinstance(obj, (str, unicode)):
+ obj = obj.strip().lower()
+ if obj in ['true', 'yes', 'on', 'y', 't', '1']:
+ return True
+ elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
+ return False
+ else:
+ raise ValueError(
+ "String is not true/false: %r" % obj)
+ return bool(obj)
+
+def aslist(obj, sep=None, strip=True):
+ if isinstance(obj, (str, unicode)):
+ lst = obj.split(sep)
+ if strip:
+ lst = [v.strip() for v in lst]
+ return lst
+ elif isinstance(obj, (list, tuple)):
+ return obj
+ elif obj is None:
+ return []
+ else:
+ return [obj]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/dateinterval.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/dateinterval.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/dateinterval.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,103 @@
+"""
+DateInterval.py
+
+Convert interval strings (in the form of 1w2d, etc) to
+seconds, and back again. Is not exactly about months or
+years (leap years in particular).
+
+Accepts (y)ear, (b)month, (w)eek, (d)ay, (h)our, (m)inute, (s)econd.
+
+Exports only timeEncode and timeDecode functions.
+"""
+
+import re
+
+__all__ = ['interval_decode', 'interval_encode']
+
+second = 1
+minute = second*60
+hour = minute*60
+day = hour*24
+week = day*7
+month = day*30
+year = day*365
+timeValues = {
+ 'y': year,
+ 'b': month,
+ 'w': week,
+ 'd': day,
+ 'h': hour,
+ 'm': minute,
+ 's': second,
+ }
+timeOrdered = timeValues.items()
+timeOrdered.sort(lambda a, b: -cmp(a[1], b[1]))
+
+def interval_encode(seconds, include_sign=False):
+ """Encodes a number of seconds (representing a time interval)
+ into a form like 1h2d3s.
+
+ >>> interval_encode(10)
+ '10s'
+ >>> interval_encode(493939)
+ '5d17h12m19s'
+ """
+ s = ''
+ orig = seconds
+ seconds = abs(seconds)
+ for char, amount in timeOrdered:
+ if seconds >= amount:
+ i, seconds = divmod(seconds, amount)
+ s += '%i%s' % (i, char)
+ if orig < 0:
+ s = '-' + s
+ elif not orig:
+ return '0'
+ elif include_sign:
+ s = '+' + s
+ return s
+
+_timeRE = re.compile(r'[0-9]+[a-zA-Z]')
+def interval_decode(s):
+ """Decodes a number in the format 1h4d3m (1 hour, 3 days, 3 minutes)
+ into a number of seconds
+
+ >>> interval_decode('40s')
+ 40
+ >>> interval_decode('10000s')
+ 10000
+ >>> interval_decode('3d1w45s')
+ 864045
+ """
+ time = 0
+ sign = 1
+ s = s.strip()
+ if s.startswith('-'):
+ s = s[1:]
+ sign = -1
+ elif s.startswith('+'):
+ s = s[1:]
+ for match in allMatches(s, _timeRE):
+ char = match.group(0)[-1].lower()
+ if not timeValues.has_key(char):
+ # @@: should signal error
+ continue
+ time += int(match.group(0)[:-1]) * timeValues[char]
+ return time
+
+# @@-sgd 2002-12-23 - this function does not belong in this module, find a better place.
+def allMatches(source, regex):
+ """Return a list of matches for regex in source
+ """
+ pos = 0
+ end = len(source)
+ rv = []
+ match = regex.search(source, pos)
+ while match:
+ rv.append(match)
+ match = regex.search(source, match.end() )
+ return rv
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/datetimeutil.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/datetimeutil.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/datetimeutil.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,361 @@
+# (c) 2005 Clark C. Evans and contributors
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# Some of this code was funded by: http://prometheusresearch.com
+"""
+Date, Time, and Timespan Parsing Utilities
+
+This module contains parsing support to create "human friendly"
+``datetime`` object parsing. The explicit goal of these routines is
+to provide a multi-format date/time support not unlike that found in
+Microsoft Excel. In most approaches, the input is very "strict" to
+prevent errors -- however, this approach is much more liberal since we
+are assuming the user-interface is parroting back the normalized value
+and thus the user has immediate feedback if the data is not typed in
+correctly.
+
+ ``parse_date`` and ``normalize_date``
+
+ These functions take a value like '9 jan 2007' and returns either an
+ ``date`` object, or an ISO 8601 formatted date value such
+ as '2007-01-09'. There is an option to provide an Oracle database
+ style output as well, ``09 JAN 2007``, but this is not the default.
+
+ This module always treats '/' delimiters as using US date order
+ (since the author's clients are US based), hence '1/9/2007' is
+ January 9th. Since this module treats the '-' as following
+ European order this supports both modes of data-entry; together
+ with immediate parroting back the result to the screen, the author
+ has found this approach to work well in pratice.
+
+ ``parse_time`` and ``normalize_time``
+
+ These functions take a value like '1 pm' and returns either an
+ ``time`` object, or an ISO 8601 formatted 24h clock time
+ such as '13:00'. There is an option to provide for US style time
+ values, '1:00 PM', however this is not the default.
+
+ ``parse_datetime`` and ``normalize_datetime``
+
+ These functions take a value like '9 jan 2007 at 1 pm' and returns
+ either an ``datetime`` object, or an ISO 8601 formatted
+ return (without the T) such as '2007-01-09 13:00'. There is an
+ option to provide for Oracle / US style, '09 JAN 2007 @ 1:00 PM',
+ however this is not the default.
+
+ ``parse_delta`` and ``normalize_delta``
+
+ These functions take a value like '1h 15m' and returns either an
+ ``timedelta`` object, or an 2-decimal fixed-point
+ numerical value in hours, such as '1.25'. The rationale is to
+ support meeting or time-billing lengths, not to be an accurate
+ representation in mili-seconds. As such not all valid
+ ``timedelta`` values will have a normalized representation.
+
+"""
+from datetime import timedelta, time, date
+from time import localtime
+import string
+
+__all__ = ['parse_timedelta', 'normalize_timedelta',
+ 'parse_time', 'normalize_time',
+ 'parse_date', 'normalize_date']
+
+def _number(val):
+ try:
+ return string.atoi(val)
+ except:
+ return None
+
+#
+# timedelta
+#
+def parse_timedelta(val):
+ """
+ returns a ``timedelta`` object, or None
+ """
+ if not val:
+ return None
+ val = string.lower(val)
+ if "." in val:
+ val = float(val)
+ return timedelta(hours=int(val), minutes=60*(val % 1.0))
+ fHour = ("h" in val or ":" in val)
+ fMin = ("m" in val or ":" in val)
+ fFraction = "." in val
+ for noise in "minu:teshour()":
+ val = string.replace(val, noise, ' ')
+ val = string.strip(val)
+ val = string.split(val)
+ hr = 0.0
+ mi = 0
+ val.reverse()
+ if fHour:
+ hr = int(val.pop())
+ if fMin:
+ mi = int(val.pop())
+ if len(val) > 0 and not hr:
+ hr = int(val.pop())
+ return timedelta(hours=hr, minutes=mi)
+
+def normalize_timedelta(val):
+ """
+ produces a normalized string value of the timedelta
+
+ This module returns a normalized time span value consisting of the
+ number of hours in fractional form. For example '1h 15min' is
+ formatted as 01.25.
+ """
+ if type(val) == str:
+ val = parse_timedelta(val)
+ if not val:
+ return ''
+ hr = val.seconds/3600
+ mn = (val.seconds % 3600)/60
+ return "%d.%02d" % (hr, mn * 100/60)
+
+#
+# time
+#
+def parse_time(val):
+ if not val:
+ return None
+ hr = mi = 0
+ val = string.lower(val)
+ amflag = (-1 != string.find(val, 'a')) # set if AM is found
+ pmflag = (-1 != string.find(val, 'p')) # set if PM is found
+ for noise in ":amp.":
+ val = string.replace(val, noise, ' ')
+ val = string.split(val)
+ if len(val) > 1:
+ hr = int(val[0])
+ mi = int(val[1])
+ else:
+ val = val[0]
+ if len(val) < 1:
+ pass
+ elif 'now' == val:
+ tm = localtime()
+ hr = tm[3]
+ mi = tm[4]
+ elif 'noon' == val:
+ hr = 12
+ elif len(val) < 3:
+ hr = int(val)
+ if not amflag and not pmflag and hr < 7:
+ hr += 12
+ elif len(val) < 5:
+ hr = int(val[:-2])
+ mi = int(val[-2:])
+ else:
+ hr = int(val[:1])
+ if amflag and hr >= 12:
+ hr = hr - 12
+ if pmflag and hr < 12:
+ hr = hr + 12
+ return time(hr, mi)
+
+def normalize_time(value, ampm):
+ if not value:
+ return ''
+ if type(value) == str:
+ value = parse_time(value)
+ if not ampm:
+ return "%02d:%02d" % (value.hour, value.minute)
+ hr = value.hour
+ am = "AM"
+ if hr < 1 or hr > 23:
+ hr = 12
+ elif hr >= 12:
+ am = "PM"
+ if hr > 12:
+ hr = hr - 12
+ return "%02d:%02d %s" % (hr, value.minute, am)
+
+#
+# Date Processing
+#
+
+_one_day = timedelta(days=1)
+
+_str2num = {'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
+ 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12 }
+
+def _month(val):
+ for (key, mon) in _str2num.items():
+ if key in val:
+ return mon
+ raise TypeError("unknown month '%s'" % val)
+
+_days_in_month = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30,
+ 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31,
+ }
+_num2str = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun',
+ 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec',
+ }
+_wkdy = ("mon", "tue", "wed", "thu", "fri", "sat", "sun")
+
+def parse_date(val):
+ if not(val):
+ return None
+ val = string.lower(val)
+ now = None
+
+ # optimized check for YYYY-MM-DD
+ strict = val.split("-")
+ if len(strict) == 3:
+ (y, m, d) = strict
+ if "+" in d:
+ d = d.split("+")[0]
+ if " " in d:
+ d = d.split(" ")[0]
+ try:
+ now = date(int(y), int(m), int(d))
+ val = "xxx" + val[10:]
+ except ValueError:
+ pass
+
+ # allow for 'now', 'mon', 'tue', etc.
+ if not now:
+ chk = val[:3]
+ if chk in ('now','tod'):
+ now = date.today()
+ elif chk in _wkdy:
+ now = date.today()
+ idx = list(_wkdy).index(chk) + 1
+ while now.isoweekday() != idx:
+ now += _one_day
+
+ # allow dates to be modified via + or - /w number of days, so
+ # that now+3 is three days from now
+ if now:
+ tail = val[3:].strip()
+ tail = tail.replace("+"," +").replace("-"," -")
+ for item in tail.split():
+ try:
+ days = int(item)
+ except ValueError:
+ pass
+ else:
+ now += timedelta(days=days)
+ return now
+
+ # ok, standard parsing
+ yr = mo = dy = None
+ for noise in ('/', '-', ',', '*'):
+ val = string.replace(val, noise, ' ')
+ for noise in _wkdy:
+ val = string.replace(val, noise, ' ')
+ out = []
+ last = False
+ ldig = False
+ for ch in val:
+ if ch.isdigit():
+ if last and not ldig:
+ out.append(' ')
+ last = ldig = True
+ else:
+ if ldig:
+ out.append(' ')
+ ldig = False
+ last = True
+ out.append(ch)
+ val = string.split("".join(out))
+ if 3 == len(val):
+ a = _number(val[0])
+ b = _number(val[1])
+ c = _number(val[2])
+ if len(val[0]) == 4:
+ yr = a
+ if b: # 1999 6 23
+ mo = b
+ dy = c
+ else: # 1999 Jun 23
+ mo = _month(val[1])
+ dy = c
+ elif a > 0:
+ yr = c
+ if len(val[2]) < 4:
+ raise TypeError("four digit year required")
+ if b: # 6 23 1999
+ dy = b
+ mo = a
+ else: # 23 Jun 1999
+ dy = a
+ mo = _month(val[1])
+ else: # Jun 23, 2000
+ dy = b
+ yr = c
+ if len(val[2]) < 4:
+ raise TypeError("four digit year required")
+ mo = _month(val[0])
+ elif 2 == len(val):
+ a = _number(val[0])
+ b = _number(val[1])
+ if a > 999:
+ yr = a
+ dy = 1
+ if b > 0: # 1999 6
+ mo = b
+ else: # 1999 Jun
+ mo = _month(val[1])
+ elif a > 0:
+ if b > 999: # 6 1999
+ mo = a
+ yr = b
+ dy = 1
+ elif b > 0: # 6 23
+ mo = a
+ dy = b
+ else: # 23 Jun
+ dy = a
+ mo = _month(val[1])
+ else:
+ if b > 999: # Jun 2001
+ yr = b
+ dy = 1
+ else: # Jun 23
+ dy = b
+ mo = _month(val[0])
+ elif 1 == len(val):
+ val = val[0]
+ if not val.isdigit():
+ mo = _month(val)
+ if mo is not None:
+ dy = 1
+ else:
+ v = _number(val)
+ val = str(v)
+ if 8 == len(val): # 20010623
+ yr = _number(val[:4])
+ mo = _number(val[4:6])
+ dy = _number(val[6:])
+ elif len(val) in (3,4):
+ if v > 1300: # 2004
+ yr = v
+ mo = 1
+ dy = 1
+ else: # 1202
+ mo = _number(val[:-2])
+ dy = _number(val[-2:])
+ elif v < 32:
+ dy = v
+ else:
+ raise TypeError("four digit year required")
+ tm = localtime()
+ if mo is None:
+ mo = tm[1]
+ if dy is None:
+ dy = tm[2]
+ if yr is None:
+ yr = tm[0]
+ return date(yr, mo, dy)
+
+def normalize_date(val, iso8601=True):
+ if not val:
+ return ''
+ if type(val) == str:
+ val = parse_date(val)
+ if iso8601:
+ return "%4d-%02d-%02d" % (val.year, val.month, val.day)
+ return "%02d %s %4d" % (val.day, _num2str[val.month], val.year)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/doctest24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/doctest24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/doctest24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2665 @@
+# Module doctest.
+# Released to the public domain 16-Jan-2001, by Tim Peters (tim at python.org).
+# Major enhancements and refactoring by:
+# Jim Fulton
+# Edward Loper
+
+# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
+
+r"""Module doctest -- a framework for running examples in docstrings.
+
+In simplest use, end each module M to be tested with:
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
+
+Then running the module as a script will cause the examples in the
+docstrings to get executed and verified:
+
+python M.py
+
+This won't display anything unless an example fails, in which case the
+failing example(s) and the cause(s) of the failure(s) are printed to stdout
+(why not stderr? because stderr is a lame hack <0.2 wink>), and the final
+line of output is "Test failed.".
+
+Run it with the -v switch instead:
+
+python M.py -v
+
+and a detailed report of all examples tried is printed to stdout, along
+with assorted summaries at the end.
+
+You can force verbose mode by passing "verbose=True" to testmod, or prohibit
+it by passing "verbose=False". In either of those cases, sys.argv is not
+examined by testmod.
+
+There are a variety of other ways to run doctests, including integration
+with the unittest framework, and support for running non-Python text
+files containing doctests. There are also many ways to override parts
+of doctest's default behaviors. See the Library Reference Manual for
+details.
+"""
+
+__docformat__ = 'reStructuredText en'
+
+__all__ = [
+ # 0, Option Flags
+ 'register_optionflag',
+ 'DONT_ACCEPT_TRUE_FOR_1',
+ 'DONT_ACCEPT_BLANKLINE',
+ 'NORMALIZE_WHITESPACE',
+ 'ELLIPSIS',
+ 'IGNORE_EXCEPTION_DETAIL',
+ 'COMPARISON_FLAGS',
+ 'REPORT_UDIFF',
+ 'REPORT_CDIFF',
+ 'REPORT_NDIFF',
+ 'REPORT_ONLY_FIRST_FAILURE',
+ 'REPORTING_FLAGS',
+ # 1. Utility Functions
+ 'is_private',
+ # 2. Example & DocTest
+ 'Example',
+ 'DocTest',
+ # 3. Doctest Parser
+ 'DocTestParser',
+ # 4. Doctest Finder
+ 'DocTestFinder',
+ # 5. Doctest Runner
+ 'DocTestRunner',
+ 'OutputChecker',
+ 'DocTestFailure',
+ 'UnexpectedException',
+ 'DebugRunner',
+ # 6. Test Functions
+ 'testmod',
+ 'testfile',
+ 'run_docstring_examples',
+ # 7. Tester
+ 'Tester',
+ # 8. Unittest Support
+ 'DocTestSuite',
+ 'DocFileSuite',
+ 'set_unittest_reportflags',
+ # 9. Debugging Support
+ 'script_from_examples',
+ 'testsource',
+ 'debug_src',
+ 'debug',
+]
+
+import __future__
+
+import sys, traceback, inspect, linecache, os, re, types
+import unittest, difflib, pdb, tempfile
+import warnings
+from StringIO import StringIO
+
+# Don't whine about the deprecated is_private function in this
+# module's tests.
+warnings.filterwarnings("ignore", "is_private", DeprecationWarning,
+ __name__, 0)
+
+# There are 4 basic classes:
+# - Example: a <source, want> pair, plus an intra-docstring line number.
+# - DocTest: a collection of examples, parsed from a docstring, plus
+# info about where the docstring came from (name, filename, lineno).
+# - DocTestFinder: extracts DocTests from a given object's docstring and
+# its contained objects' docstrings.
+# - DocTestRunner: runs DocTest cases, and accumulates statistics.
+#
+# So the basic picture is:
+#
+# list of:
+# +------+ +---------+ +-------+
+# |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results|
+# +------+ +---------+ +-------+
+# | Example |
+# | ... |
+# | Example |
+# +---------+
+
+# Option constants.
+
+OPTIONFLAGS_BY_NAME = {}
+def register_optionflag(name):
+ flag = 1 << len(OPTIONFLAGS_BY_NAME)
+ OPTIONFLAGS_BY_NAME[name] = flag
+ return flag
+
+DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1')
+DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE')
+NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
+ELLIPSIS = register_optionflag('ELLIPSIS')
+IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL')
+
+COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 |
+ DONT_ACCEPT_BLANKLINE |
+ NORMALIZE_WHITESPACE |
+ ELLIPSIS |
+ IGNORE_EXCEPTION_DETAIL)
+
+REPORT_UDIFF = register_optionflag('REPORT_UDIFF')
+REPORT_CDIFF = register_optionflag('REPORT_CDIFF')
+REPORT_NDIFF = register_optionflag('REPORT_NDIFF')
+REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE')
+
+REPORTING_FLAGS = (REPORT_UDIFF |
+ REPORT_CDIFF |
+ REPORT_NDIFF |
+ REPORT_ONLY_FIRST_FAILURE)
+
+# Special string markers for use in `want` strings:
+BLANKLINE_MARKER = '<BLANKLINE>'
+ELLIPSIS_MARKER = '...'
+
+######################################################################
+## Table of Contents
+######################################################################
+# 1. Utility Functions
+# 2. Example & DocTest -- store test cases
+# 3. DocTest Parser -- extracts examples from strings
+# 4. DocTest Finder -- extracts test cases from objects
+# 5. DocTest Runner -- runs test cases
+# 6. Test Functions -- convenient wrappers for testing
+# 7. Tester Class -- for backwards compatibility
+# 8. Unittest Support
+# 9. Debugging Support
+# 10. Example Usage
+
+######################################################################
+## 1. Utility Functions
+######################################################################
+
+def is_private(prefix, base):
+ """prefix, base -> true iff name prefix + "." + base is "private".
+
+ Prefix may be an empty string, and base does not contain a period.
+ Prefix is ignored (although functions you write conforming to this
+ protocol may make use of it).
+ Return true iff base begins with an (at least one) underscore, but
+ does not both begin and end with (at least) two underscores.
+
+ >>> is_private("a.b", "my_func")
+ False
+ >>> is_private("____", "_my_func")
+ True
+ >>> is_private("someclass", "__init__")
+ False
+ >>> is_private("sometypo", "__init_")
+ True
+ >>> is_private("x.y.z", "_")
+ True
+ >>> is_private("_x.y.z", "__")
+ False
+ >>> is_private("", "") # senseless but consistent
+ False
+ """
+ warnings.warn("is_private is deprecated; it wasn't useful; "
+ "examine DocTestFinder.find() lists instead",
+ DeprecationWarning, stacklevel=2)
+ return base[:1] == "_" and not base[:2] == "__" == base[-2:]
+
+def _extract_future_flags(globs):
+ """
+ Return the compiler-flags associated with the future features that
+ have been imported into the given namespace (globs).
+ """
+ flags = 0
+ for fname in __future__.all_feature_names:
+ feature = globs.get(fname, None)
+ if feature is getattr(__future__, fname):
+ flags |= feature.compiler_flag
+ return flags
+
+def _normalize_module(module, depth=2):
+ """
+ Return the module specified by `module`. In particular:
+ - If `module` is a module, then return module.
+ - If `module` is a string, then import and return the
+ module with that name.
+ - If `module` is None, then return the calling module.
+ The calling module is assumed to be the module of
+ the stack frame at the given depth in the call stack.
+ """
+ if inspect.ismodule(module):
+ return module
+ elif isinstance(module, (str, unicode)):
+ return __import__(module, globals(), locals(), ["*"])
+ elif module is None:
+ return sys.modules[sys._getframe(depth).f_globals['__name__']]
+ else:
+ raise TypeError("Expected a module, string, or None")
+
+def _indent(s, indent=4):
+ """
+ Add the given number of space characters to the beginning every
+ non-blank line in `s`, and return the result.
+ """
+ # This regexp matches the start of non-blank lines:
+ return re.sub('(?m)^(?!$)', indent*' ', s)
+
+def _exception_traceback(exc_info):
+ """
+ Return a string containing a traceback message for the given
+ exc_info tuple (as returned by sys.exc_info()).
+ """
+ # Get a traceback message.
+ excout = StringIO()
+ exc_type, exc_val, exc_tb = exc_info
+ traceback.print_exception(exc_type, exc_val, exc_tb, file=excout)
+ return excout.getvalue()
+
+# Override some StringIO methods.
+class _SpoofOut(StringIO):
+ def getvalue(self):
+ result = StringIO.getvalue(self)
+ # If anything at all was written, make sure there's a trailing
+ # newline. There's no way for the expected output to indicate
+ # that a trailing newline is missing.
+ if result and not result.endswith("\n"):
+ result += "\n"
+ # Prevent softspace from screwing up the next test case, in
+ # case they used print with a trailing comma in an example.
+ if hasattr(self, "softspace"):
+ del self.softspace
+ return result
+
+ def truncate(self, size=None):
+ StringIO.truncate(self, size)
+ if hasattr(self, "softspace"):
+ del self.softspace
+
+# Worst-case linear-time ellipsis matching.
+def _ellipsis_match(want, got):
+ """
+ Essentially the only subtle case:
+ >>> _ellipsis_match('aa...aa', 'aaa')
+ False
+ """
+ if ELLIPSIS_MARKER not in want:
+ return want == got
+
+ # Find "the real" strings.
+ ws = want.split(ELLIPSIS_MARKER)
+ assert len(ws) >= 2
+
+ # Deal with exact matches possibly needed at one or both ends.
+ startpos, endpos = 0, len(got)
+ w = ws[0]
+ if w: # starts with exact match
+ if got.startswith(w):
+ startpos = len(w)
+ del ws[0]
+ else:
+ return False
+ w = ws[-1]
+ if w: # ends with exact match
+ if got.endswith(w):
+ endpos -= len(w)
+ del ws[-1]
+ else:
+ return False
+
+ if startpos > endpos:
+ # Exact end matches required more characters than we have, as in
+ # _ellipsis_match('aa...aa', 'aaa')
+ return False
+
+ # For the rest, we only need to find the leftmost non-overlapping
+ # match for each piece. If there's no overall match that way alone,
+ # there's no overall match period.
+ for w in ws:
+ # w may be '' at times, if there are consecutive ellipses, or
+ # due to an ellipsis at the start or end of `want`. That's OK.
+ # Search for an empty string succeeds, and doesn't change startpos.
+ startpos = got.find(w, startpos, endpos)
+ if startpos < 0:
+ return False
+ startpos += len(w)
+
+ return True
+
+def _comment_line(line):
+ "Return a commented form of the given line"
+ line = line.rstrip()
+ if line:
+ return '# '+line
+ else:
+ return '#'
+
+class _OutputRedirectingPdb(pdb.Pdb):
+ """
+ A specialized version of the python debugger that redirects stdout
+ to a given stream when interacting with the user. Stdout is *not*
+ redirected when traced code is executed.
+ """
+ def __init__(self, out):
+ self.__out = out
+ pdb.Pdb.__init__(self)
+
+ def trace_dispatch(self, *args):
+ # Redirect stdout to the given stream.
+ save_stdout = sys.stdout
+ sys.stdout = self.__out
+ # Call Pdb's trace dispatch method.
+ try:
+ return pdb.Pdb.trace_dispatch(self, *args)
+ finally:
+ sys.stdout = save_stdout
+
+# [XX] Normalize with respect to os.path.pardir?
+def _module_relative_path(module, path):
+ if not inspect.ismodule(module):
+ raise TypeError, 'Expected a module: %r' % module
+ if path.startswith('/'):
+ raise ValueError, 'Module-relative files may not have absolute paths'
+
+ # Find the base directory for the path.
+ if hasattr(module, '__file__'):
+ # A normal module/package
+ basedir = os.path.split(module.__file__)[0]
+ elif module.__name__ == '__main__':
+ # An interactive session.
+ if len(sys.argv)>0 and sys.argv[0] != '':
+ basedir = os.path.split(sys.argv[0])[0]
+ else:
+ basedir = os.curdir
+ else:
+ # A module w/o __file__ (this includes builtins)
+ raise ValueError("Can't resolve paths relative to the module " +
+ module + " (it has no __file__)")
+
+ # Combine the base directory and the path.
+ return os.path.join(basedir, *(path.split('/')))
+
+######################################################################
+## 2. Example & DocTest
+######################################################################
+## - An "example" is a <source, want> pair, where "source" is a
+## fragment of source code, and "want" is the expected output for
+## "source." The Example class also includes information about
+## where the example was extracted from.
+##
+## - A "doctest" is a collection of examples, typically extracted from
+## a string (such as an object's docstring). The DocTest class also
+## includes information about where the string was extracted from.
+
+class Example:
+ """
+ A single doctest example, consisting of source code and expected
+ output. `Example` defines the following attributes:
+
+ - source: A single Python statement, always ending with a newline.
+ The constructor adds a newline if needed.
+
+ - want: The expected output from running the source code (either
+ from stdout, or a traceback in case of exception). `want` ends
+ with a newline unless it's empty, in which case it's an empty
+ string. The constructor adds a newline if needed.
+
+ - exc_msg: The exception message generated by the example, if
+ the example is expected to generate an exception; or `None` if
+ it is not expected to generate an exception. This exception
+ message is compared against the return value of
+ `traceback.format_exception_only()`. `exc_msg` ends with a
+ newline unless it's `None`. The constructor adds a newline
+ if needed.
+
+ - lineno: The line number within the DocTest string containing
+ this Example where the Example begins. This line number is
+ zero-based, with respect to the beginning of the DocTest.
+
+ - indent: The example's indentation in the DocTest string.
+ I.e., the number of space characters that preceed the
+ example's first prompt.
+
+ - options: A dictionary mapping from option flags to True or
+ False, which is used to override default options for this
+ example. Any option flags not contained in this dictionary
+ are left at their default value (as specified by the
+ DocTestRunner's optionflags). By default, no options are set.
+ """
+ def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
+ options=None):
+ # Normalize inputs.
+ if not source.endswith('\n'):
+ source += '\n'
+ if want and not want.endswith('\n'):
+ want += '\n'
+ if exc_msg is not None and not exc_msg.endswith('\n'):
+ exc_msg += '\n'
+ # Store properties.
+ self.source = source
+ self.want = want
+ self.lineno = lineno
+ self.indent = indent
+ if options is None: options = {}
+ self.options = options
+ self.exc_msg = exc_msg
+
+class DocTest:
+ """
+ A collection of doctest examples that should be run in a single
+ namespace. Each `DocTest` defines the following attributes:
+
+ - examples: the list of examples.
+
+ - globs: The namespace (aka globals) that the examples should
+ be run in.
+
+ - name: A name identifying the DocTest (typically, the name of
+ the object whose docstring this DocTest was extracted from).
+
+ - filename: The name of the file that this DocTest was extracted
+ from, or `None` if the filename is unknown.
+
+ - lineno: The line number within filename where this DocTest
+ begins, or `None` if the line number is unavailable. This
+ line number is zero-based, with respect to the beginning of
+ the file.
+
+ - docstring: The string that the examples were extracted from,
+ or `None` if the string is unavailable.
+ """
+ def __init__(self, examples, globs, name, filename, lineno, docstring):
+ """
+ Create a new DocTest containing the given examples. The
+ DocTest's globals are initialized with a copy of `globs`.
+ """
+ assert not isinstance(examples, basestring), \
+ "DocTest no longer accepts str; use DocTestParser instead"
+ self.examples = examples
+ self.docstring = docstring
+ self.globs = globs.copy()
+ self.name = name
+ self.filename = filename
+ self.lineno = lineno
+
+ def __repr__(self):
+ if len(self.examples) == 0:
+ examples = 'no examples'
+ elif len(self.examples) == 1:
+ examples = '1 example'
+ else:
+ examples = '%d examples' % len(self.examples)
+ return ('<DocTest %s from %s:%s (%s)>' %
+ (self.name, self.filename, self.lineno, examples))
+
+
+ # This lets us sort tests by name:
+ def __cmp__(self, other):
+ if not isinstance(other, DocTest):
+ return -1
+ return cmp((self.name, self.filename, self.lineno, id(self)),
+ (other.name, other.filename, other.lineno, id(other)))
+
+######################################################################
+## 3. DocTestParser
+######################################################################
+
+class DocTestParser:
+ """
+ A class used to parse strings containing doctest examples.
+ """
+ # This regular expression is used to find doctest examples in a
+ # string. It defines three groups: `source` is the source code
+ # (including leading indentation and prompts); `indent` is the
+ # indentation of the first (PS1) line of the source code; and
+ # `want` is the expected output (including leading indentation).
+ _EXAMPLE_RE = re.compile(r'''
+ # Source consists of a PS1 line followed by zero or more PS2 lines.
+ (?P<source>
+ (?:^(?P<indent> [ ]*) >>> .*) # PS1 line
+ (?:\n [ ]* \.\.\. .*)*) # PS2 lines
+ \n?
+ # Want consists of any non-blank lines that do not start with PS1.
+ (?P<want> (?:(?![ ]*$) # Not a blank line
+ (?![ ]*>>>) # Not a line starting with PS1
+ .*$\n? # But any other line
+ )*)
+ ''', re.MULTILINE | re.VERBOSE)
+
+ # A regular expression for handling `want` strings that contain
+ # expected exceptions. It divides `want` into three pieces:
+ # - the traceback header line (`hdr`)
+ # - the traceback stack (`stack`)
+ # - the exception message (`msg`), as generated by
+ # traceback.format_exception_only()
+ # `msg` may have multiple lines. We assume/require that the
+ # exception message is the first non-indented line starting with a word
+ # character following the traceback header line.
+ _EXCEPTION_RE = re.compile(r"""
+ # Grab the traceback header. Different versions of Python have
+ # said different things on the first traceback line.
+ ^(?P<hdr> Traceback\ \(
+ (?: most\ recent\ call\ last
+ | innermost\ last
+ ) \) :
+ )
+ \s* $ # toss trailing whitespace on the header.
+ (?P<stack> .*?) # don't blink: absorb stuff until...
+ ^ (?P<msg> \w+ .*) # a line *starts* with alphanum.
+ """, re.VERBOSE | re.MULTILINE | re.DOTALL)
+
+ # A callable returning a true value iff its argument is a blank line
+ # or contains a single comment.
+ _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match
+
+ def parse(self, string, name='<string>'):
+ """
+ Divide the given string into examples and intervening text,
+ and return them as a list of alternating Examples and strings.
+ Line numbers for the Examples are 0-based. The optional
+ argument `name` is a name identifying this string, and is only
+ used for error messages.
+ """
+ string = string.expandtabs()
+ # If all lines begin with the same indentation, then strip it.
+ min_indent = self._min_indent(string)
+ if min_indent > 0:
+ string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+
+ output = []
+ charno, lineno = 0, 0
+ # Find all doctest examples in the string:
+ for m in self._EXAMPLE_RE.finditer(string):
+ # Add the pre-example text to `output`.
+ output.append(string[charno:m.start()])
+ # Update lineno (lines before this example)
+ lineno += string.count('\n', charno, m.start())
+ # Extract info from the regexp match.
+ (source, options, want, exc_msg) = \
+ self._parse_example(m, name, lineno)
+ # Create an Example, and add it to the list.
+ if not self._IS_BLANK_OR_COMMENT(source):
+ output.append( Example(source, want, exc_msg,
+ lineno=lineno,
+ indent=min_indent+len(m.group('indent')),
+ options=options) )
+ # Update lineno (lines inside this example)
+ lineno += string.count('\n', m.start(), m.end())
+ # Update charno.
+ charno = m.end()
+ # Add any remaining post-example text to `output`.
+ output.append(string[charno:])
+ return output
+
+ def get_doctest(self, string, globs, name, filename, lineno):
+ """
+ Extract all doctest examples from the given string, and
+ collect them into a `DocTest` object.
+
+ `globs`, `name`, `filename`, and `lineno` are attributes for
+ the new `DocTest` object. See the documentation for `DocTest`
+ for more information.
+ """
+ return DocTest(self.get_examples(string, name), globs,
+ name, filename, lineno, string)
+
+ def get_examples(self, string, name='<string>'):
+ """
+ Extract all doctest examples from the given string, and return
+ them as a list of `Example` objects. Line numbers are
+ 0-based, because it's most common in doctests that nothing
+ interesting appears on the same line as opening triple-quote,
+ and so the first interesting line is called \"line 1\" then.
+
+ The optional argument `name` is a name identifying this
+ string, and is only used for error messages.
+ """
+ return [x for x in self.parse(string, name)
+ if isinstance(x, Example)]
+
+ def _parse_example(self, m, name, lineno):
+ """
+ Given a regular expression match from `_EXAMPLE_RE` (`m`),
+ return a pair `(source, want)`, where `source` is the matched
+ example's source code (with prompts and indentation stripped);
+ and `want` is the example's expected output (with indentation
+ stripped).
+
+ `name` is the string's name, and `lineno` is the line number
+ where the example starts; both are used for error messages.
+ """
+ # Get the example's indentation level.
+ indent = len(m.group('indent'))
+
+ # Divide source into lines; check that they're properly
+ # indented; and then strip their indentation & prompts.
+ source_lines = m.group('source').split('\n')
+ self._check_prompt_blank(source_lines, indent, name, lineno)
+ self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno)
+ source = '\n'.join([sl[indent+4:] for sl in source_lines])
+
+ # Divide want into lines; check that it's properly indented; and
+ # then strip the indentation. Spaces before the last newline should
+ # be preserved, so plain rstrip() isn't good enough.
+ want = m.group('want')
+ want_lines = want.split('\n')
+ if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+ del want_lines[-1] # forget final newline & spaces after it
+ self._check_prefix(want_lines, ' '*indent, name,
+ lineno + len(source_lines))
+ want = '\n'.join([wl[indent:] for wl in want_lines])
+
+ # If `want` contains a traceback message, then extract it.
+ m = self._EXCEPTION_RE.match(want)
+ if m:
+ exc_msg = m.group('msg')
+ else:
+ exc_msg = None
+
+ # Extract options from the source.
+ options = self._find_options(source, name, lineno)
+
+ return source, options, want, exc_msg
+
+ # This regular expression looks for option directives in the
+ # source code of an example. Option directives are comments
+ # starting with "doctest:". Warning: this may give false
+ # positives for string-literals that contain the string
+ # "#doctest:". Eliminating these false positives would require
+ # actually parsing the string; but we limit them by ignoring any
+ # line containing "#doctest:" that is *followed* by a quote mark.
+ _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$',
+ re.MULTILINE)
+
+ def _find_options(self, source, name, lineno):
+ """
+ Return a dictionary containing option overrides extracted from
+ option directives in the given source string.
+
+ `name` is the string's name, and `lineno` is the line number
+ where the example starts; both are used for error messages.
+ """
+ options = {}
+ # (note: with the current regexp, this will match at most once:)
+ for m in self._OPTION_DIRECTIVE_RE.finditer(source):
+ option_strings = m.group(1).replace(',', ' ').split()
+ for option in option_strings:
+ if (option[0] not in '+-' or
+ option[1:] not in OPTIONFLAGS_BY_NAME):
+ raise ValueError('line %r of the doctest for %s '
+ 'has an invalid option: %r' %
+ (lineno+1, name, option))
+ flag = OPTIONFLAGS_BY_NAME[option[1:]]
+ options[flag] = (option[0] == '+')
+ if options and self._IS_BLANK_OR_COMMENT(source):
+ raise ValueError('line %r of the doctest for %s has an option '
+ 'directive on a line with no example: %r' %
+ (lineno, name, source))
+ return options
+
+ # This regular expression finds the indentation of every non-blank
+ # line in a string.
+ _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE)
+
+ def _min_indent(self, s):
+ "Return the minimum indentation of any non-blank line in `s`"
+ indents = [len(indent) for indent in self._INDENT_RE.findall(s)]
+ if len(indents) > 0:
+ return min(indents)
+ else:
+ return 0
+
+ def _check_prompt_blank(self, lines, indent, name, lineno):
+ """
+ Given the lines of a source string (including prompts and
+ leading indentation), check to make sure that every prompt is
+ followed by a space character. If any line is not followed by
+ a space character, then raise ValueError.
+ """
+ for i, line in enumerate(lines):
+ if len(line) >= indent+4 and line[indent+3] != ' ':
+ raise ValueError('line %r of the docstring for %s '
+ 'lacks blank after %s: %r' %
+ (lineno+i+1, name,
+ line[indent:indent+3], line))
+
+ def _check_prefix(self, lines, prefix, name, lineno):
+ """
+ Check that every line in the given list starts with the given
+ prefix; if any line does not, then raise a ValueError.
+ """
+ for i, line in enumerate(lines):
+ if line and not line.startswith(prefix):
+ raise ValueError('line %r of the docstring for %s has '
+ 'inconsistent leading whitespace: %r' %
+ (lineno+i+1, name, line))
+
+
+######################################################################
+## 4. DocTest Finder
+######################################################################
+
+class DocTestFinder:
+ """
+ A class used to extract the DocTests that are relevant to a given
+ object, from its docstring and the docstrings of its contained
+ objects. Doctests can currently be extracted from the following
+ object types: modules, functions, classes, methods, staticmethods,
+ classmethods, and properties.
+ """
+
+ def __init__(self, verbose=False, parser=DocTestParser(),
+ recurse=True, _namefilter=None, exclude_empty=True):
+ """
+ Create a new doctest finder.
+
+ The optional argument `parser` specifies a class or
+ function that should be used to create new DocTest objects (or
+ objects that implement the same interface as DocTest). The
+ signature for this factory function should match the signature
+ of the DocTest constructor.
+
+ If the optional argument `recurse` is false, then `find` will
+ only examine the given object, and not any contained objects.
+
+ If the optional argument `exclude_empty` is false, then `find`
+ will include tests for objects with empty docstrings.
+ """
+ self._parser = parser
+ self._verbose = verbose
+ self._recurse = recurse
+ self._exclude_empty = exclude_empty
+ # _namefilter is undocumented, and exists only for temporary backward-
+ # compatibility support of testmod's deprecated isprivate mess.
+ self._namefilter = _namefilter
+
+ def find(self, obj, name=None, module=None, globs=None,
+ extraglobs=None):
+ """
+ Return a list of the DocTests that are defined by the given
+ object's docstring, or by any of its contained objects'
+ docstrings.
+
+ The optional parameter `module` is the module that contains
+ the given object. If the module is not specified or is None, then
+ the test finder will attempt to automatically determine the
+ correct module. The object's module is used:
+
+ - As a default namespace, if `globs` is not specified.
+ - To prevent the DocTestFinder from extracting DocTests
+ from objects that are imported from other modules.
+ - To find the name of the file containing the object.
+ - To help find the line number of the object within its
+ file.
+
+ Contained objects whose module does not match `module` are ignored.
+
+ If `module` is False, no attempt to find the module will be made.
+ This is obscure, of use mostly in tests: if `module` is False, or
+ is None but cannot be found automatically, then all objects are
+ considered to belong to the (non-existent) module, so all contained
+ objects will (recursively) be searched for doctests.
+
+ The globals for each DocTest is formed by combining `globs`
+ and `extraglobs` (bindings in `extraglobs` override bindings
+ in `globs`). A new copy of the globals dictionary is created
+ for each DocTest. If `globs` is not specified, then it
+ defaults to the module's `__dict__`, if specified, or {}
+ otherwise. If `extraglobs` is not specified, then it defaults
+ to {}.
+
+ """
+ # If name was not specified, then extract it from the object.
+ if name is None:
+ name = getattr(obj, '__name__', None)
+ if name is None:
+ raise ValueError("DocTestFinder.find: name must be given "
+ "when obj.__name__ doesn't exist: %r" %
+ (type(obj),))
+
+ # Find the module that contains the given object (if obj is
+ # a module, then module=obj.). Note: this may fail, in which
+ # case module will be None.
+ if module is False:
+ module = None
+ elif module is None:
+ module = inspect.getmodule(obj)
+
+ # Read the module's source code. This is used by
+ # DocTestFinder._find_lineno to find the line number for a
+ # given object's docstring.
+ try:
+ file = inspect.getsourcefile(obj) or inspect.getfile(obj)
+ source_lines = linecache.getlines(file)
+ if not source_lines:
+ source_lines = None
+ except TypeError:
+ source_lines = None
+
+ # Initialize globals, and merge in extraglobs.
+ if globs is None:
+ if module is None:
+ globs = {}
+ else:
+ globs = module.__dict__.copy()
+ else:
+ globs = globs.copy()
+ if extraglobs is not None:
+ globs.update(extraglobs)
+
+ # Recursively expore `obj`, extracting DocTests.
+ tests = []
+ self._find(tests, obj, name, module, source_lines, globs, {})
+ return tests
+
+ def _filter(self, obj, prefix, base):
+ """
+ Return true if the given object should not be examined.
+ """
+ return (self._namefilter is not None and
+ self._namefilter(prefix, base))
+
+ def _from_module(self, module, object):
+ """
+ Return true if the given object is defined in the given
+ module.
+ """
+ if module is None:
+ return True
+ elif inspect.isfunction(object):
+ return module.__dict__ is object.func_globals
+ elif inspect.isclass(object):
+ return module.__name__ == object.__module__
+ elif inspect.getmodule(object) is not None:
+ return module is inspect.getmodule(object)
+ elif hasattr(object, '__module__'):
+ return module.__name__ == object.__module__
+ elif isinstance(object, property):
+ return True # [XX] no way not be sure.
+ else:
+ raise ValueError("object must be a class or function")
+
+ def _find(self, tests, obj, name, module, source_lines, globs, seen):
+ """
+ Find tests for the given object and any contained objects, and
+ add them to `tests`.
+ """
+ if self._verbose:
+ print 'Finding tests in %s' % name
+
+ # If we've already processed this object, then ignore it.
+ if id(obj) in seen:
+ return
+ seen[id(obj)] = 1
+
+ # Find a test for this object, and add it to the list of tests.
+ test = self._get_test(obj, name, module, globs, source_lines)
+ if test is not None:
+ tests.append(test)
+
+ # Look for tests in a module's contained objects.
+ if inspect.ismodule(obj) and self._recurse:
+ for valname, val in obj.__dict__.items():
+ # Check if this contained object should be ignored.
+ if self._filter(val, name, valname):
+ continue
+ valname = '%s.%s' % (name, valname)
+ # Recurse to functions & classes.
+ if ((inspect.isfunction(val) or inspect.isclass(val)) and
+ self._from_module(module, val)):
+ self._find(tests, val, valname, module, source_lines,
+ globs, seen)
+
+ # Look for tests in a module's __test__ dictionary.
+ if inspect.ismodule(obj) and self._recurse:
+ for valname, val in getattr(obj, '__test__', {}).items():
+ if not isinstance(valname, basestring):
+ raise ValueError("DocTestFinder.find: __test__ keys "
+ "must be strings: %r" %
+ (type(valname),))
+ if not (inspect.isfunction(val) or inspect.isclass(val) or
+ inspect.ismethod(val) or inspect.ismodule(val) or
+ isinstance(val, basestring)):
+ raise ValueError("DocTestFinder.find: __test__ values "
+ "must be strings, functions, methods, "
+ "classes, or modules: %r" %
+ (type(val),))
+ valname = '%s.__test__.%s' % (name, valname)
+ self._find(tests, val, valname, module, source_lines,
+ globs, seen)
+
+ # Look for tests in a class's contained objects.
+ if inspect.isclass(obj) and self._recurse:
+ for valname, val in obj.__dict__.items():
+ # Check if this contained object should be ignored.
+ if self._filter(val, name, valname):
+ continue
+ # Special handling for staticmethod/classmethod.
+ if isinstance(val, staticmethod):
+ val = getattr(obj, valname)
+ if isinstance(val, classmethod):
+ val = getattr(obj, valname).im_func
+
+ # Recurse to methods, properties, and nested classes.
+ if ((inspect.isfunction(val) or inspect.isclass(val) or
+ isinstance(val, property)) and
+ self._from_module(module, val)):
+ valname = '%s.%s' % (name, valname)
+ self._find(tests, val, valname, module, source_lines,
+ globs, seen)
+
+ def _get_test(self, obj, name, module, globs, source_lines):
+ """
+ Return a DocTest for the given object, if it defines a docstring;
+ otherwise, return None.
+ """
+ # Extract the object's docstring. If it doesn't have one,
+ # then return None (no test for this object).
+ if isinstance(obj, basestring):
+ docstring = obj
+ else:
+ try:
+ if obj.__doc__ is None:
+ docstring = ''
+ else:
+ docstring = obj.__doc__
+ if not isinstance(docstring, basestring):
+ docstring = str(docstring)
+ except (TypeError, AttributeError):
+ docstring = ''
+
+ # Find the docstring's location in the file.
+ lineno = self._find_lineno(obj, source_lines)
+
+ # Don't bother if the docstring is empty.
+ if self._exclude_empty and not docstring:
+ return None
+
+ # Return a DocTest for this object.
+ if module is None:
+ filename = None
+ else:
+ filename = getattr(module, '__file__', module.__name__)
+ if filename[-4:] in (".pyc", ".pyo"):
+ filename = filename[:-1]
+ return self._parser.get_doctest(docstring, globs, name,
+ filename, lineno)
+
+ def _find_lineno(self, obj, source_lines):
+ """
+ Return a line number of the given object's docstring. Note:
+ this method assumes that the object has a docstring.
+ """
+ lineno = None
+
+ # Find the line number for modules.
+ if inspect.ismodule(obj):
+ lineno = 0
+
+ # Find the line number for classes.
+ # Note: this could be fooled if a class is defined multiple
+ # times in a single file.
+ if inspect.isclass(obj):
+ if source_lines is None:
+ return None
+ pat = re.compile(r'^\s*class\s*%s\b' %
+ getattr(obj, '__name__', '-'))
+ for i, line in enumerate(source_lines):
+ if pat.match(line):
+ lineno = i
+ break
+
+ # Find the line number for functions & methods.
+ if inspect.ismethod(obj): obj = obj.im_func
+ if inspect.isfunction(obj): obj = obj.func_code
+ if inspect.istraceback(obj): obj = obj.tb_frame
+ if inspect.isframe(obj): obj = obj.f_code
+ if inspect.iscode(obj):
+ lineno = getattr(obj, 'co_firstlineno', None)-1
+
+ # Find the line number where the docstring starts. Assume
+ # that it's the first line that begins with a quote mark.
+ # Note: this could be fooled by a multiline function
+ # signature, where a continuation line begins with a quote
+ # mark.
+ if lineno is not None:
+ if source_lines is None:
+ return lineno+1
+ pat = re.compile('(^|.*:)\s*\w*("|\')')
+ for lineno in range(lineno, len(source_lines)):
+ if pat.match(source_lines[lineno]):
+ return lineno
+
+ # We couldn't find the line number.
+ return None
+
+######################################################################
+## 5. DocTest Runner
+######################################################################
+
+class DocTestRunner:
+ """
+ A class used to run DocTest test cases, and accumulate statistics.
+ The `run` method is used to process a single DocTest case. It
+ returns a tuple `(f, t)`, where `t` is the number of test cases
+ tried, and `f` is the number of test cases that failed.
+
+ >>> tests = DocTestFinder().find(_TestClass)
+ >>> runner = DocTestRunner(verbose=False)
+ >>> for test in tests:
+ ... print runner.run(test)
+ (0, 2)
+ (0, 1)
+ (0, 2)
+ (0, 2)
+
+ The `summarize` method prints a summary of all the test cases that
+ have been run by the runner, and returns an aggregated `(f, t)`
+ tuple:
+
+ >>> runner.summarize(verbose=1)
+ 4 items passed all tests:
+ 2 tests in _TestClass
+ 2 tests in _TestClass.__init__
+ 2 tests in _TestClass.get
+ 1 tests in _TestClass.square
+ 7 tests in 4 items.
+ 7 passed and 0 failed.
+ Test passed.
+ (0, 7)
+
+ The aggregated number of tried examples and failed examples is
+ also available via the `tries` and `failures` attributes:
+
+ >>> runner.tries
+ 7
+ >>> runner.failures
+ 0
+
+ The comparison between expected outputs and actual outputs is done
+ by an `OutputChecker`. This comparison may be customized with a
+ number of option flags; see the documentation for `testmod` for
+ more information. If the option flags are insufficient, then the
+ comparison may also be customized by passing a subclass of
+ `OutputChecker` to the constructor.
+
+ The test runner's display output can be controlled in two ways.
+ First, an output function (`out) can be passed to
+ `TestRunner.run`; this function will be called with strings that
+ should be displayed. It defaults to `sys.stdout.write`. If
+ capturing the output is not sufficient, then the display output
+ can be also customized by subclassing DocTestRunner, and
+ overriding the methods `report_start`, `report_success`,
+ `report_unexpected_exception`, and `report_failure`.
+ """
+ # This divider string is used to separate failure messages, and to
+ # separate sections of the summary.
+ DIVIDER = "*" * 70
+
+ def __init__(self, checker=None, verbose=None, optionflags=0):
+ """
+ Create a new test runner.
+
+ Optional keyword arg `checker` is the `OutputChecker` that
+ should be used to compare the expected outputs and actual
+ outputs of doctest examples.
+
+ Optional keyword arg 'verbose' prints lots of stuff if true,
+ only failures if false; by default, it's true iff '-v' is in
+ sys.argv.
+
+ Optional argument `optionflags` can be used to control how the
+ test runner compares expected output to actual output, and how
+ it displays failures. See the documentation for `testmod` for
+ more information.
+ """
+ self._checker = checker or OutputChecker()
+ if verbose is None:
+ verbose = '-v' in sys.argv
+ self._verbose = verbose
+ self.optionflags = optionflags
+ self.original_optionflags = optionflags
+
+ # Keep track of the examples we've run.
+ self.tries = 0
+ self.failures = 0
+ self._name2ft = {}
+
+ # Create a fake output target for capturing doctest output.
+ self._fakeout = _SpoofOut()
+
+ #/////////////////////////////////////////////////////////////////
+ # Reporting methods
+ #/////////////////////////////////////////////////////////////////
+
+ def report_start(self, out, test, example):
+ """
+ Report that the test runner is about to process the given
+ example. (Only displays a message if verbose=True)
+ """
+ if self._verbose:
+ if example.want:
+ out('Trying:\n' + _indent(example.source) +
+ 'Expecting:\n' + _indent(example.want))
+ else:
+ out('Trying:\n' + _indent(example.source) +
+ 'Expecting nothing\n')
+
+ def report_success(self, out, test, example, got):
+ """
+ Report that the given example ran successfully. (Only
+ displays a message if verbose=True)
+ """
+ if self._verbose:
+ out("ok\n")
+
+ def report_failure(self, out, test, example, got):
+ """
+ Report that the given example failed.
+ """
+ out(self._failure_header(test, example) +
+ self._checker.output_difference(example, got, self.optionflags))
+
+ def report_unexpected_exception(self, out, test, example, exc_info):
+ """
+ Report that the given example raised an unexpected exception.
+ """
+ out(self._failure_header(test, example) +
+ 'Exception raised:\n' + _indent(_exception_traceback(exc_info)))
+
+ def _failure_header(self, test, example):
+ out = [self.DIVIDER]
+ if test.filename:
+ if test.lineno is not None and example.lineno is not None:
+ lineno = test.lineno + example.lineno + 1
+ else:
+ lineno = '?'
+ out.append('File "%s", line %s, in %s' %
+ (test.filename, lineno, test.name))
+ else:
+ out.append('Line %s, in %s' % (example.lineno+1, test.name))
+ out.append('Failed example:')
+ source = example.source
+ out.append(_indent(source))
+ return '\n'.join(out)
+
+ #/////////////////////////////////////////////////////////////////
+ # DocTest Running
+ #/////////////////////////////////////////////////////////////////
+
+ def __run(self, test, compileflags, out):
+ """
+ Run the examples in `test`. Write the outcome of each example
+ with one of the `DocTestRunner.report_*` methods, using the
+ writer function `out`. `compileflags` is the set of compiler
+ flags that should be used to execute examples. Return a tuple
+ `(f, t)`, where `t` is the number of examples tried, and `f`
+ is the number of examples that failed. The examples are run
+ in the namespace `test.globs`.
+ """
+ # Keep track of the number of failures and tries.
+ failures = tries = 0
+
+ # Save the option flags (since option directives can be used
+ # to modify them).
+ original_optionflags = self.optionflags
+
+ SUCCESS, FAILURE, BOOM = range(3) # `outcome` state
+
+ check = self._checker.check_output
+
+ # Process each example.
+ for examplenum, example in enumerate(test.examples):
+
+ # If REPORT_ONLY_FIRST_FAILURE is set, then supress
+ # reporting after the first failure.
+ quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and
+ failures > 0)
+
+ # Merge in the example's options.
+ self.optionflags = original_optionflags
+ if example.options:
+ for (optionflag, val) in example.options.items():
+ if val:
+ self.optionflags |= optionflag
+ else:
+ self.optionflags &= ~optionflag
+
+ # Record that we started this example.
+ tries += 1
+ if not quiet:
+ self.report_start(out, test, example)
+
+ # Use a special filename for compile(), so we can retrieve
+ # the source code during interactive debugging (see
+ # __patched_linecache_getlines).
+ filename = '<doctest %s[%d]>' % (test.name, examplenum)
+
+ # Run the example in the given context (globs), and record
+ # any exception that gets raised. (But don't intercept
+ # keyboard interrupts.)
+ try:
+ # Don't blink! This is where the user's code gets run.
+ exec compile(example.source, filename, "single",
+ compileflags, 1) in test.globs
+ self.debugger.set_continue() # ==== Example Finished ====
+ exception = None
+ except KeyboardInterrupt:
+ raise
+ except:
+ exception = sys.exc_info()
+ self.debugger.set_continue() # ==== Example Finished ====
+
+ got = self._fakeout.getvalue() # the actual output
+ self._fakeout.truncate(0)
+ outcome = FAILURE # guilty until proved innocent or insane
+
+ # If the example executed without raising any exceptions,
+ # verify its output.
+ if exception is None:
+ if check(example.want, got, self.optionflags):
+ outcome = SUCCESS
+
+ # The example raised an exception: check if it was expected.
+ else:
+ exc_info = sys.exc_info()
+ exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
+ if not quiet:
+ got += _exception_traceback(exc_info)
+
+ # If `example.exc_msg` is None, then we weren't expecting
+ # an exception.
+ if example.exc_msg is None:
+ outcome = BOOM
+
+ # We expected an exception: see whether it matches.
+ elif check(example.exc_msg, exc_msg, self.optionflags):
+ outcome = SUCCESS
+
+ # Another chance if they didn't care about the detail.
+ elif self.optionflags & IGNORE_EXCEPTION_DETAIL:
+ m1 = re.match(r'[^:]*:', example.exc_msg)
+ m2 = re.match(r'[^:]*:', exc_msg)
+ if m1 and m2 and check(m1.group(0), m2.group(0),
+ self.optionflags):
+ outcome = SUCCESS
+
+ # Report the outcome.
+ if outcome is SUCCESS:
+ if not quiet:
+ self.report_success(out, test, example, got)
+ elif outcome is FAILURE:
+ if not quiet:
+ self.report_failure(out, test, example, got)
+ failures += 1
+ elif outcome is BOOM:
+ if not quiet:
+ self.report_unexpected_exception(out, test, example,
+ exc_info)
+ failures += 1
+ else:
+ assert False, ("unknown outcome", outcome)
+
+ # Restore the option flags (in case they were modified)
+ self.optionflags = original_optionflags
+
+ # Record and return the number of failures and tries.
+ self.__record_outcome(test, failures, tries)
+ return failures, tries
+
+ def __record_outcome(self, test, f, t):
+ """
+ Record the fact that the given DocTest (`test`) generated `f`
+ failures out of `t` tried examples.
+ """
+ f2, t2 = self._name2ft.get(test.name, (0,0))
+ self._name2ft[test.name] = (f+f2, t+t2)
+ self.failures += f
+ self.tries += t
+
+ __LINECACHE_FILENAME_RE = re.compile(r'<doctest '
+ r'(?P<name>[\w\.]+)'
+ r'\[(?P<examplenum>\d+)\]>$')
+ def __patched_linecache_getlines(self, filename, module_globals=None):
+ m = self.__LINECACHE_FILENAME_RE.match(filename)
+ if m and m.group('name') == self.test.name:
+ example = self.test.examples[int(m.group('examplenum'))]
+ return example.source.splitlines(True)
+ else:
+ return self.save_linecache_getlines(filename)#?, module_globals)
+
+ def run(self, test, compileflags=None, out=None, clear_globs=True):
+ """
+ Run the examples in `test`, and display the results using the
+ writer function `out`.
+
+ The examples are run in the namespace `test.globs`. If
+ `clear_globs` is true (the default), then this namespace will
+ be cleared after the test runs, to help with garbage
+ collection. If you would like to examine the namespace after
+ the test completes, then use `clear_globs=False`.
+
+ `compileflags` gives the set of flags that should be used by
+ the Python compiler when running the examples. If not
+ specified, then it will default to the set of future-import
+ flags that apply to `globs`.
+
+ The output of each example is checked using
+ `DocTestRunner.check_output`, and the results are formatted by
+ the `DocTestRunner.report_*` methods.
+ """
+ self.test = test
+
+ if compileflags is None:
+ compileflags = _extract_future_flags(test.globs)
+
+ save_stdout = sys.stdout
+ if out is None:
+ out = save_stdout.write
+ sys.stdout = self._fakeout
+
+ # Patch pdb.set_trace to restore sys.stdout during interactive
+ # debugging (so it's not still redirected to self._fakeout).
+ # Note that the interactive output will go to *our*
+ # save_stdout, even if that's not the real sys.stdout; this
+ # allows us to write test cases for the set_trace behavior.
+ save_set_trace = pdb.set_trace
+ self.debugger = _OutputRedirectingPdb(save_stdout)
+ self.debugger.reset()
+ pdb.set_trace = self.debugger.set_trace
+
+ # Patch linecache.getlines, so we can see the example's source
+ # when we're inside the debugger.
+ self.save_linecache_getlines = linecache.getlines
+ linecache.getlines = self.__patched_linecache_getlines
+
+ try:
+ return self.__run(test, compileflags, out)
+ finally:
+ sys.stdout = save_stdout
+ pdb.set_trace = save_set_trace
+ linecache.getlines = self.save_linecache_getlines
+ if clear_globs:
+ test.globs.clear()
+
+ #/////////////////////////////////////////////////////////////////
+ # Summarization
+ #/////////////////////////////////////////////////////////////////
+ def summarize(self, verbose=None):
+ """
+ Print a summary of all the test cases that have been run by
+ this DocTestRunner, and return a tuple `(f, t)`, where `f` is
+ the total number of failed examples, and `t` is the total
+ number of tried examples.
+
+ The optional `verbose` argument controls how detailed the
+ summary is. If the verbosity is not specified, then the
+ DocTestRunner's verbosity is used.
+ """
+ if verbose is None:
+ verbose = self._verbose
+ notests = []
+ passed = []
+ failed = []
+ totalt = totalf = 0
+ for x in self._name2ft.items():
+ name, (f, t) = x
+ assert f <= t
+ totalt += t
+ totalf += f
+ if t == 0:
+ notests.append(name)
+ elif f == 0:
+ passed.append( (name, t) )
+ else:
+ failed.append(x)
+ if verbose:
+ if notests:
+ print len(notests), "items had no tests:"
+ notests.sort()
+ for thing in notests:
+ print " ", thing
+ if passed:
+ print len(passed), "items passed all tests:"
+ passed.sort()
+ for thing, count in passed:
+ print " %3d tests in %s" % (count, thing)
+ if failed:
+ print self.DIVIDER
+ print len(failed), "items had failures:"
+ failed.sort()
+ for thing, (f, t) in failed:
+ print " %3d of %3d in %s" % (f, t, thing)
+ if verbose:
+ print totalt, "tests in", len(self._name2ft), "items."
+ print totalt - totalf, "passed and", totalf, "failed."
+ if totalf:
+ print "***Test Failed***", totalf, "failures."
+ elif verbose:
+ print "Test passed."
+ return totalf, totalt
+
+ #/////////////////////////////////////////////////////////////////
+ # Backward compatibility cruft to maintain doctest.master.
+ #/////////////////////////////////////////////////////////////////
+ def merge(self, other):
+ d = self._name2ft
+ for name, (f, t) in other._name2ft.items():
+ if name in d:
+ print "*** DocTestRunner.merge: '" + name + "' in both" \
+ " testers; summing outcomes."
+ f2, t2 = d[name]
+ f = f + f2
+ t = t + t2
+ d[name] = f, t
+
+class OutputChecker:
+ """
+ A class used to check the whether the actual output from a doctest
+ example matches the expected output. `OutputChecker` defines two
+ methods: `check_output`, which compares a given pair of outputs,
+ and returns true if they match; and `output_difference`, which
+ returns a string describing the differences between two outputs.
+ """
+ def check_output(self, want, got, optionflags):
+ """
+ Return True iff the actual output from an example (`got`)
+ matches the expected output (`want`). These strings are
+ always considered to match if they are identical; but
+ depending on what option flags the test runner is using,
+ several non-exact match types are also possible. See the
+ documentation for `TestRunner` for more information about
+ option flags.
+ """
+ # Handle the common case first, for efficiency:
+ # if they're string-identical, always return true.
+ if got == want:
+ return True
+
+ # The values True and False replaced 1 and 0 as the return
+ # value for boolean comparisons in Python 2.3.
+ if not (optionflags & DONT_ACCEPT_TRUE_FOR_1):
+ if (got,want) == ("True\n", "1\n"):
+ return True
+ if (got,want) == ("False\n", "0\n"):
+ return True
+
+ # <BLANKLINE> can be used as a special sequence to signify a
+ # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used.
+ if not (optionflags & DONT_ACCEPT_BLANKLINE):
+ # Replace <BLANKLINE> in want with a blank line.
+ want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER),
+ '', want)
+ # If a line in got contains only spaces, then remove the
+ # spaces.
+ got = re.sub('(?m)^\s*?$', '', got)
+ if got == want:
+ return True
+
+ # This flag causes doctest to ignore any differences in the
+ # contents of whitespace strings. Note that this can be used
+ # in conjunction with the ELLIPSIS flag.
+ if optionflags & NORMALIZE_WHITESPACE:
+ got = ' '.join(got.split())
+ want = ' '.join(want.split())
+ if got == want:
+ return True
+
+ # The ELLIPSIS flag says to let the sequence "..." in `want`
+ # match any substring in `got`.
+ if optionflags & ELLIPSIS:
+ if _ellipsis_match(want, got):
+ return True
+
+ # We didn't find any match; return false.
+ return False
+
+ # Should we do a fancy diff?
+ def _do_a_fancy_diff(self, want, got, optionflags):
+ # Not unless they asked for a fancy diff.
+ if not optionflags & (REPORT_UDIFF |
+ REPORT_CDIFF |
+ REPORT_NDIFF):
+ return False
+
+ # If expected output uses ellipsis, a meaningful fancy diff is
+ # too hard ... or maybe not. In two real-life failures Tim saw,
+ # a diff was a major help anyway, so this is commented out.
+ # [todo] _ellipsis_match() knows which pieces do and don't match,
+ # and could be the basis for a kick-ass diff in this case.
+ ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want:
+ ## return False
+
+ # ndiff does intraline difference marking, so can be useful even
+ # for 1-line differences.
+ if optionflags & REPORT_NDIFF:
+ return True
+
+ # The other diff types need at least a few lines to be helpful.
+ return want.count('\n') > 2 and got.count('\n') > 2
+
+ def output_difference(self, example, got, optionflags):
+ """
+ Return a string describing the differences between the
+ expected output for a given example (`example`) and the actual
+ output (`got`). `optionflags` is the set of option flags used
+ to compare `want` and `got`.
+ """
+ want = example.want
+ # If <BLANKLINE>s are being used, then replace blank lines
+ # with <BLANKLINE> in the actual output string.
+ if not (optionflags & DONT_ACCEPT_BLANKLINE):
+ got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got)
+
+ # Check if we should use diff.
+ if self._do_a_fancy_diff(want, got, optionflags):
+ # Split want & got into lines.
+ want_lines = want.splitlines(True) # True == keep line ends
+ got_lines = got.splitlines(True)
+ # Use difflib to find their differences.
+ if optionflags & REPORT_UDIFF:
+ diff = difflib.unified_diff(want_lines, got_lines, n=2)
+ diff = list(diff)[2:] # strip the diff header
+ kind = 'unified diff with -expected +actual'
+ elif optionflags & REPORT_CDIFF:
+ diff = difflib.context_diff(want_lines, got_lines, n=2)
+ diff = list(diff)[2:] # strip the diff header
+ kind = 'context diff with expected followed by actual'
+ elif optionflags & REPORT_NDIFF:
+ engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
+ diff = list(engine.compare(want_lines, got_lines))
+ kind = 'ndiff with -expected +actual'
+ else:
+ assert 0, 'Bad diff option'
+ # Remove trailing whitespace on diff output.
+ diff = [line.rstrip() + '\n' for line in diff]
+ return 'Differences (%s):\n' % kind + _indent(''.join(diff))
+
+ # If we're not using diff, then simply list the expected
+ # output followed by the actual output.
+ if want and got:
+ return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got))
+ elif want:
+ return 'Expected:\n%sGot nothing\n' % _indent(want)
+ elif got:
+ return 'Expected nothing\nGot:\n%s' % _indent(got)
+ else:
+ return 'Expected nothing\nGot nothing\n'
+
+class DocTestFailure(Exception):
+ """A DocTest example has failed in debugging mode.
+
+ The exception instance has variables:
+
+ - test: the DocTest object being run
+
+ - excample: the Example object that failed
+
+ - got: the actual output
+ """
+ def __init__(self, test, example, got):
+ self.test = test
+ self.example = example
+ self.got = got
+
+ def __str__(self):
+ return str(self.test)
+
+class UnexpectedException(Exception):
+ """A DocTest example has encountered an unexpected exception
+
+ The exception instance has variables:
+
+ - test: the DocTest object being run
+
+ - excample: the Example object that failed
+
+ - exc_info: the exception info
+ """
+ def __init__(self, test, example, exc_info):
+ self.test = test
+ self.example = example
+ self.exc_info = exc_info
+
+ def __str__(self):
+ return str(self.test)
+
+class DebugRunner(DocTestRunner):
+ r"""Run doc tests but raise an exception as soon as there is a failure.
+
+ If an unexpected exception occurs, an UnexpectedException is raised.
+ It contains the test, the example, and the original exception:
+
+ >>> runner = DebugRunner(verbose=False)
+ >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
+ ... {}, 'foo', 'foo.py', 0)
+ >>> try:
+ ... runner.run(test)
+ ... except UnexpectedException, failure:
+ ... pass
+
+ >>> failure.test is test
+ True
+
+ >>> failure.example.want
+ '42\n'
+
+ >>> exc_info = failure.exc_info
+ >>> raise exc_info[0], exc_info[1], exc_info[2]
+ Traceback (most recent call last):
+ ...
+ KeyError
+
+ We wrap the original exception to give the calling application
+ access to the test and example information.
+
+ If the output doesn't match, then a DocTestFailure is raised:
+
+ >>> test = DocTestParser().get_doctest('''
+ ... >>> x = 1
+ ... >>> x
+ ... 2
+ ... ''', {}, 'foo', 'foo.py', 0)
+
+ >>> try:
+ ... runner.run(test)
+ ... except DocTestFailure, failure:
+ ... pass
+
+ DocTestFailure objects provide access to the test:
+
+ >>> failure.test is test
+ True
+
+ As well as to the example:
+
+ >>> failure.example.want
+ '2\n'
+
+ and the actual output:
+
+ >>> failure.got
+ '1\n'
+
+ If a failure or error occurs, the globals are left intact:
+
+ >>> del test.globs['__builtins__']
+ >>> test.globs
+ {'x': 1}
+
+ >>> test = DocTestParser().get_doctest('''
+ ... >>> x = 2
+ ... >>> raise KeyError
+ ... ''', {}, 'foo', 'foo.py', 0)
+
+ >>> runner.run(test)
+ Traceback (most recent call last):
+ ...
+ UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
+
+ >>> del test.globs['__builtins__']
+ >>> test.globs
+ {'x': 2}
+
+ But the globals are cleared if there is no error:
+
+ >>> test = DocTestParser().get_doctest('''
+ ... >>> x = 2
+ ... ''', {}, 'foo', 'foo.py', 0)
+
+ >>> runner.run(test)
+ (0, 1)
+
+ >>> test.globs
+ {}
+
+ """
+
+ def run(self, test, compileflags=None, out=None, clear_globs=True):
+ r = DocTestRunner.run(self, test, compileflags, out, False)
+ if clear_globs:
+ test.globs.clear()
+ return r
+
+ def report_unexpected_exception(self, out, test, example, exc_info):
+ raise UnexpectedException(test, example, exc_info)
+
+ def report_failure(self, out, test, example, got):
+ raise DocTestFailure(test, example, got)
+
+######################################################################
+## 6. Test Functions
+######################################################################
+# These should be backwards compatible.
+
+# For backward compatibility, a global instance of a DocTestRunner
+# class, updated by testmod.
+master = None
+
+def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
+ report=True, optionflags=0, extraglobs=None,
+ raise_on_error=False, exclude_empty=False):
+ """m=None, name=None, globs=None, verbose=None, isprivate=None,
+ report=True, optionflags=0, extraglobs=None, raise_on_error=False,
+ exclude_empty=False
+
+ Test examples in docstrings in functions and classes reachable
+ from module m (or the current module if m is not supplied), starting
+ with m.__doc__. Unless isprivate is specified, private names
+ are not skipped.
+
+ Also test examples reachable from dict m.__test__ if it exists and is
+ not None. m.__test__ maps names to functions, classes and strings;
+ function and class docstrings are tested even if the name is private;
+ strings are tested directly, as if they were docstrings.
+
+ Return (#failures, #tests).
+
+ See doctest.__doc__ for an overview.
+
+ Optional keyword arg "name" gives the name of the module; by default
+ use m.__name__.
+
+ Optional keyword arg "globs" gives a dict to be used as the globals
+ when executing examples; by default, use m.__dict__. A copy of this
+ dict is actually used for each docstring, so that each docstring's
+ examples start with a clean slate.
+
+ Optional keyword arg "extraglobs" gives a dictionary that should be
+ merged into the globals that are used to execute examples. By
+ default, no extra globals are used. This is new in 2.4.
+
+ Optional keyword arg "verbose" prints lots of stuff if true, prints
+ only failures if false; by default, it's true iff "-v" is in sys.argv.
+
+ Optional keyword arg "report" prints a summary at the end when true,
+ else prints nothing at the end. In verbose mode, the summary is
+ detailed, else very brief (in fact, empty if all tests passed).
+
+ Optional keyword arg "optionflags" or's together module constants,
+ and defaults to 0. This is new in 2.3. Possible values (see the
+ docs for details):
+
+ DONT_ACCEPT_TRUE_FOR_1
+ DONT_ACCEPT_BLANKLINE
+ NORMALIZE_WHITESPACE
+ ELLIPSIS
+ IGNORE_EXCEPTION_DETAIL
+ REPORT_UDIFF
+ REPORT_CDIFF
+ REPORT_NDIFF
+ REPORT_ONLY_FIRST_FAILURE
+
+ Optional keyword arg "raise_on_error" raises an exception on the
+ first unexpected exception or failure. This allows failures to be
+ post-mortem debugged.
+
+ Deprecated in Python 2.4:
+ Optional keyword arg "isprivate" specifies a function used to
+ determine whether a name is private. The default function is
+ treat all functions as public. Optionally, "isprivate" can be
+ set to doctest.is_private to skip over functions marked as private
+ using the underscore naming convention; see its docs for details.
+
+ Advanced tomfoolery: testmod runs methods of a local instance of
+ class doctest.Tester, then merges the results into (or creates)
+ global Tester instance doctest.master. Methods of doctest.master
+ can be called directly too, if you want to do something unusual.
+ Passing report=0 to testmod is especially useful then, to delay
+ displaying a summary. Invoke doctest.master.summarize(verbose)
+ when you're done fiddling.
+ """
+ global master
+
+ if isprivate is not None:
+ warnings.warn("the isprivate argument is deprecated; "
+ "examine DocTestFinder.find() lists instead",
+ DeprecationWarning)
+
+ # If no module was given, then use __main__.
+ if m is None:
+ # DWA - m will still be None if this wasn't invoked from the command
+ # line, in which case the following TypeError is about as good an error
+ # as we should expect
+ m = sys.modules.get('__main__')
+
+ # Check that we were actually given a module.
+ if not inspect.ismodule(m):
+ raise TypeError("testmod: module required; %r" % (m,))
+
+ # If no name was given, then use the module's name.
+ if name is None:
+ name = m.__name__
+
+ # Find, parse, and run all tests in the given module.
+ finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty)
+
+ if raise_on_error:
+ runner = DebugRunner(verbose=verbose, optionflags=optionflags)
+ else:
+ runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
+
+ for test in finder.find(m, name, globs=globs, extraglobs=extraglobs):
+ runner.run(test)
+
+ if report:
+ runner.summarize()
+
+ if master is None:
+ master = runner
+ else:
+ master.merge(runner)
+
+ return runner.failures, runner.tries
+
+def testfile(filename, module_relative=True, name=None, package=None,
+ globs=None, verbose=None, report=True, optionflags=0,
+ extraglobs=None, raise_on_error=False, parser=DocTestParser()):
+ """
+ Test examples in the given file. Return (#failures, #tests).
+
+ Optional keyword arg "module_relative" specifies how filenames
+ should be interpreted:
+
+ - If "module_relative" is True (the default), then "filename"
+ specifies a module-relative path. By default, this path is
+ relative to the calling module's directory; but if the
+ "package" argument is specified, then it is relative to that
+ package. To ensure os-independence, "filename" should use
+ "/" characters to separate path segments, and should not
+ be an absolute path (i.e., it may not begin with "/").
+
+ - If "module_relative" is False, then "filename" specifies an
+ os-specific path. The path may be absolute or relative (to
+ the current working directory).
+
+ Optional keyword arg "name" gives the name of the test; by default
+ use the file's basename.
+
+ Optional keyword argument "package" is a Python package or the
+ name of a Python package whose directory should be used as the
+ base directory for a module relative filename. If no package is
+ specified, then the calling module's directory is used as the base
+ directory for module relative filenames. It is an error to
+ specify "package" if "module_relative" is False.
+
+ Optional keyword arg "globs" gives a dict to be used as the globals
+ when executing examples; by default, use {}. A copy of this dict
+ is actually used for each docstring, so that each docstring's
+ examples start with a clean slate.
+
+ Optional keyword arg "extraglobs" gives a dictionary that should be
+ merged into the globals that are used to execute examples. By
+ default, no extra globals are used.
+
+ Optional keyword arg "verbose" prints lots of stuff if true, prints
+ only failures if false; by default, it's true iff "-v" is in sys.argv.
+
+ Optional keyword arg "report" prints a summary at the end when true,
+ else prints nothing at the end. In verbose mode, the summary is
+ detailed, else very brief (in fact, empty if all tests passed).
+
+ Optional keyword arg "optionflags" or's together module constants,
+ and defaults to 0. Possible values (see the docs for details):
+
+ DONT_ACCEPT_TRUE_FOR_1
+ DONT_ACCEPT_BLANKLINE
+ NORMALIZE_WHITESPACE
+ ELLIPSIS
+ IGNORE_EXCEPTION_DETAIL
+ REPORT_UDIFF
+ REPORT_CDIFF
+ REPORT_NDIFF
+ REPORT_ONLY_FIRST_FAILURE
+
+ Optional keyword arg "raise_on_error" raises an exception on the
+ first unexpected exception or failure. This allows failures to be
+ post-mortem debugged.
+
+ Optional keyword arg "parser" specifies a DocTestParser (or
+ subclass) that should be used to extract tests from the files.
+
+ Advanced tomfoolery: testmod runs methods of a local instance of
+ class doctest.Tester, then merges the results into (or creates)
+ global Tester instance doctest.master. Methods of doctest.master
+ can be called directly too, if you want to do something unusual.
+ Passing report=0 to testmod is especially useful then, to delay
+ displaying a summary. Invoke doctest.master.summarize(verbose)
+ when you're done fiddling.
+ """
+ global master
+
+ if package and not module_relative:
+ raise ValueError("Package may only be specified for module-"
+ "relative paths.")
+
+ # Relativize the path
+ if module_relative:
+ package = _normalize_module(package)
+ filename = _module_relative_path(package, filename)
+
+ # If no name was given, then use the file's name.
+ if name is None:
+ name = os.path.basename(filename)
+
+ # Assemble the globals.
+ if globs is None:
+ globs = {}
+ else:
+ globs = globs.copy()
+ if extraglobs is not None:
+ globs.update(extraglobs)
+
+ if raise_on_error:
+ runner = DebugRunner(verbose=verbose, optionflags=optionflags)
+ else:
+ runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
+
+ # Read the file, convert it to a test, and run it.
+ s = open(filename).read()
+ test = parser.get_doctest(s, globs, name, filename, 0)
+ runner.run(test)
+
+ if report:
+ runner.summarize()
+
+ if master is None:
+ master = runner
+ else:
+ master.merge(runner)
+
+ return runner.failures, runner.tries
+
+def run_docstring_examples(f, globs, verbose=False, name="NoName",
+ compileflags=None, optionflags=0):
+ """
+ Test examples in the given object's docstring (`f`), using `globs`
+ as globals. Optional argument `name` is used in failure messages.
+ If the optional argument `verbose` is true, then generate output
+ even if there are no failures.
+
+ `compileflags` gives the set of flags that should be used by the
+ Python compiler when running the examples. If not specified, then
+ it will default to the set of future-import flags that apply to
+ `globs`.
+
+ Optional keyword arg `optionflags` specifies options for the
+ testing and output. See the documentation for `testmod` for more
+ information.
+ """
+ # Find, parse, and run all tests in the given module.
+ finder = DocTestFinder(verbose=verbose, recurse=False)
+ runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
+ for test in finder.find(f, name, globs=globs):
+ runner.run(test, compileflags=compileflags)
+
+######################################################################
+## 7. Tester
+######################################################################
+# This is provided only for backwards compatibility. It's not
+# actually used in any way.
+
+class Tester:
+ def __init__(self, mod=None, globs=None, verbose=None,
+ isprivate=None, optionflags=0):
+
+ warnings.warn("class Tester is deprecated; "
+ "use class doctest.DocTestRunner instead",
+ DeprecationWarning, stacklevel=2)
+ if mod is None and globs is None:
+ raise TypeError("Tester.__init__: must specify mod or globs")
+ if mod is not None and not inspect.ismodule(mod):
+ raise TypeError("Tester.__init__: mod must be a module; %r" %
+ (mod,))
+ if globs is None:
+ globs = mod.__dict__
+ self.globs = globs
+
+ self.verbose = verbose
+ self.isprivate = isprivate
+ self.optionflags = optionflags
+ self.testfinder = DocTestFinder(_namefilter=isprivate)
+ self.testrunner = DocTestRunner(verbose=verbose,
+ optionflags=optionflags)
+
+ def runstring(self, s, name):
+ test = DocTestParser().get_doctest(s, self.globs, name, None, None)
+ if self.verbose:
+ print "Running string", name
+ (f,t) = self.testrunner.run(test)
+ if self.verbose:
+ print f, "of", t, "examples failed in string", name
+ return (f,t)
+
+ def rundoc(self, object, name=None, module=None):
+ f = t = 0
+ tests = self.testfinder.find(object, name, module=module,
+ globs=self.globs)
+ for test in tests:
+ (f2, t2) = self.testrunner.run(test)
+ (f,t) = (f+f2, t+t2)
+ return (f,t)
+
+ def rundict(self, d, name, module=None):
+ import new
+ m = new.module(name)
+ m.__dict__.update(d)
+ if module is None:
+ module = False
+ return self.rundoc(m, name, module)
+
+ def run__test__(self, d, name):
+ import new
+ m = new.module(name)
+ m.__test__ = d
+ return self.rundoc(m, name)
+
+ def summarize(self, verbose=None):
+ return self.testrunner.summarize(verbose)
+
+ def merge(self, other):
+ self.testrunner.merge(other.testrunner)
+
+######################################################################
+## 8. Unittest Support
+######################################################################
+
+_unittest_reportflags = 0
+
+def set_unittest_reportflags(flags):
+ """Sets the unittest option flags.
+
+ The old flag is returned so that a runner could restore the old
+ value if it wished to:
+
+ >>> old = _unittest_reportflags
+ >>> set_unittest_reportflags(REPORT_NDIFF |
+ ... REPORT_ONLY_FIRST_FAILURE) == old
+ True
+
+ >>> import doctest
+ >>> doctest._unittest_reportflags == (REPORT_NDIFF |
+ ... REPORT_ONLY_FIRST_FAILURE)
+ True
+
+ Only reporting flags can be set:
+
+ >>> set_unittest_reportflags(ELLIPSIS)
+ Traceback (most recent call last):
+ ...
+ ValueError: ('Only reporting flags allowed', 8)
+
+ >>> set_unittest_reportflags(old) == (REPORT_NDIFF |
+ ... REPORT_ONLY_FIRST_FAILURE)
+ True
+ """
+ global _unittest_reportflags
+
+ if (flags & REPORTING_FLAGS) != flags:
+ raise ValueError("Only reporting flags allowed", flags)
+ old = _unittest_reportflags
+ _unittest_reportflags = flags
+ return old
+
+
+class DocTestCase(unittest.TestCase):
+
+ def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
+ checker=None):
+
+ unittest.TestCase.__init__(self)
+ self._dt_optionflags = optionflags
+ self._dt_checker = checker
+ self._dt_test = test
+ self._dt_setUp = setUp
+ self._dt_tearDown = tearDown
+
+ def setUp(self):
+ test = self._dt_test
+
+ if self._dt_setUp is not None:
+ self._dt_setUp(test)
+
+ def tearDown(self):
+ test = self._dt_test
+
+ if self._dt_tearDown is not None:
+ self._dt_tearDown(test)
+
+ test.globs.clear()
+
+ def runTest(self):
+ test = self._dt_test
+ old = sys.stdout
+ new = StringIO()
+ optionflags = self._dt_optionflags
+
+ if not (optionflags & REPORTING_FLAGS):
+ # The option flags don't include any reporting flags,
+ # so add the default reporting flags
+ optionflags |= _unittest_reportflags
+
+ runner = DocTestRunner(optionflags=optionflags,
+ checker=self._dt_checker, verbose=False)
+
+ try:
+ runner.DIVIDER = "-"*70
+ failures, tries = runner.run(
+ test, out=new.write, clear_globs=False)
+ finally:
+ sys.stdout = old
+
+ if failures:
+ raise self.failureException(self.format_failure(new.getvalue()))
+
+ def format_failure(self, err):
+ test = self._dt_test
+ if test.lineno is None:
+ lineno = 'unknown line number'
+ else:
+ lineno = '%s' % test.lineno
+ lname = '.'.join(test.name.split('.')[-1:])
+ return ('Failed doctest test for %s\n'
+ ' File "%s", line %s, in %s\n\n%s'
+ % (test.name, test.filename, lineno, lname, err)
+ )
+
+ def debug(self):
+ r"""Run the test case without results and without catching exceptions
+
+ The unit test framework includes a debug method on test cases
+ and test suites to support post-mortem debugging. The test code
+ is run in such a way that errors are not caught. This way a
+ caller can catch the errors and initiate post-mortem debugging.
+
+ The DocTestCase provides a debug method that raises
+ UnexpectedException errors if there is an unexepcted
+ exception:
+
+ >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
+ ... {}, 'foo', 'foo.py', 0)
+ >>> case = DocTestCase(test)
+ >>> try:
+ ... case.debug()
+ ... except UnexpectedException, failure:
+ ... pass
+
+ The UnexpectedException contains the test, the example, and
+ the original exception:
+
+ >>> failure.test is test
+ True
+
+ >>> failure.example.want
+ '42\n'
+
+ >>> exc_info = failure.exc_info
+ >>> raise exc_info[0], exc_info[1], exc_info[2]
+ Traceback (most recent call last):
+ ...
+ KeyError
+
+ If the output doesn't match, then a DocTestFailure is raised:
+
+ >>> test = DocTestParser().get_doctest('''
+ ... >>> x = 1
+ ... >>> x
+ ... 2
+ ... ''', {}, 'foo', 'foo.py', 0)
+ >>> case = DocTestCase(test)
+
+ >>> try:
+ ... case.debug()
+ ... except DocTestFailure, failure:
+ ... pass
+
+ DocTestFailure objects provide access to the test:
+
+ >>> failure.test is test
+ True
+
+ As well as to the example:
+
+ >>> failure.example.want
+ '2\n'
+
+ and the actual output:
+
+ >>> failure.got
+ '1\n'
+
+ """
+
+ self.setUp()
+ runner = DebugRunner(optionflags=self._dt_optionflags,
+ checker=self._dt_checker, verbose=False)
+ runner.run(self._dt_test)
+ self.tearDown()
+
+ def id(self):
+ return self._dt_test.name
+
+ def __repr__(self):
+ name = self._dt_test.name.split('.')
+ return "%s (%s)" % (name[-1], '.'.join(name[:-1]))
+
+ __str__ = __repr__
+
+ def shortDescription(self):
+ return "Doctest: " + self._dt_test.name
+
+def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None,
+ **options):
+ """
+ Convert doctest tests for a module to a unittest test suite.
+
+ This converts each documentation string in a module that
+ contains doctest tests to a unittest test case. If any of the
+ tests in a doc string fail, then the test case fails. An exception
+ is raised showing the name of the file containing the test and a
+ (sometimes approximate) line number.
+
+ The `module` argument provides the module to be tested. The argument
+ can be either a module or a module name.
+
+ If no argument is given, the calling module is used.
+
+ A number of options may be provided as keyword arguments:
+
+ setUp
+ A set-up function. This is called before running the
+ tests in each file. The setUp function will be passed a DocTest
+ object. The setUp function can access the test globals as the
+ globs attribute of the test passed.
+
+ tearDown
+ A tear-down function. This is called after running the
+ tests in each file. The tearDown function will be passed a DocTest
+ object. The tearDown function can access the test globals as the
+ globs attribute of the test passed.
+
+ globs
+ A dictionary containing initial global variables for the tests.
+
+ optionflags
+ A set of doctest option flags expressed as an integer.
+ """
+
+ if test_finder is None:
+ test_finder = DocTestFinder()
+
+ module = _normalize_module(module)
+ tests = test_finder.find(module, globs=globs, extraglobs=extraglobs)
+ if globs is None:
+ globs = module.__dict__
+ if not tests:
+ # Why do we want to do this? Because it reveals a bug that might
+ # otherwise be hidden.
+ raise ValueError(module, "has no tests")
+
+ tests.sort()
+ suite = unittest.TestSuite()
+ for test in tests:
+ if len(test.examples) == 0:
+ continue
+ if not test.filename:
+ filename = module.__file__
+ if filename[-4:] in (".pyc", ".pyo"):
+ filename = filename[:-1]
+ test.filename = filename
+ suite.addTest(DocTestCase(test, **options))
+
+ return suite
+
+class DocFileCase(DocTestCase):
+
+ def id(self):
+ return '_'.join(self._dt_test.name.split('.'))
+
+ def __repr__(self):
+ return self._dt_test.filename
+ __str__ = __repr__
+
+ def format_failure(self, err):
+ return ('Failed doctest test for %s\n File "%s", line 0\n\n%s'
+ % (self._dt_test.name, self._dt_test.filename, err)
+ )
+
+def DocFileTest(path, module_relative=True, package=None,
+ globs=None, parser=DocTestParser(), **options):
+ if globs is None:
+ globs = {}
+
+ if package and not module_relative:
+ raise ValueError("Package may only be specified for module-"
+ "relative paths.")
+
+ # Relativize the path.
+ if module_relative:
+ package = _normalize_module(package)
+ path = _module_relative_path(package, path)
+
+ # Find the file and read it.
+ name = os.path.basename(path)
+ doc = open(path).read()
+
+ # Convert it to a test, and wrap it in a DocFileCase.
+ test = parser.get_doctest(doc, globs, name, path, 0)
+ return DocFileCase(test, **options)
+
+def DocFileSuite(*paths, **kw):
+ """A unittest suite for one or more doctest files.
+
+ The path to each doctest file is given as a string; the
+ interpretation of that string depends on the keyword argument
+ "module_relative".
+
+ A number of options may be provided as keyword arguments:
+
+ module_relative
+ If "module_relative" is True, then the given file paths are
+ interpreted as os-independent module-relative paths. By
+ default, these paths are relative to the calling module's
+ directory; but if the "package" argument is specified, then
+ they are relative to that package. To ensure os-independence,
+ "filename" should use "/" characters to separate path
+ segments, and may not be an absolute path (i.e., it may not
+ begin with "/").
+
+ If "module_relative" is False, then the given file paths are
+ interpreted as os-specific paths. These paths may be absolute
+ or relative (to the current working directory).
+
+ package
+ A Python package or the name of a Python package whose directory
+ should be used as the base directory for module relative paths.
+ If "package" is not specified, then the calling module's
+ directory is used as the base directory for module relative
+ filenames. It is an error to specify "package" if
+ "module_relative" is False.
+
+ setUp
+ A set-up function. This is called before running the
+ tests in each file. The setUp function will be passed a DocTest
+ object. The setUp function can access the test globals as the
+ globs attribute of the test passed.
+
+ tearDown
+ A tear-down function. This is called after running the
+ tests in each file. The tearDown function will be passed a DocTest
+ object. The tearDown function can access the test globals as the
+ globs attribute of the test passed.
+
+ globs
+ A dictionary containing initial global variables for the tests.
+
+ optionflags
+ A set of doctest option flags expressed as an integer.
+
+ parser
+ A DocTestParser (or subclass) that should be used to extract
+ tests from the files.
+ """
+ suite = unittest.TestSuite()
+
+ # We do this here so that _normalize_module is called at the right
+ # level. If it were called in DocFileTest, then this function
+ # would be the caller and we might guess the package incorrectly.
+ if kw.get('module_relative', True):
+ kw['package'] = _normalize_module(kw.get('package'))
+
+ for path in paths:
+ suite.addTest(DocFileTest(path, **kw))
+
+ return suite
+
+######################################################################
+## 9. Debugging Support
+######################################################################
+
+def script_from_examples(s):
+ r"""Extract script from text with examples.
+
+ Converts text with examples to a Python script. Example input is
+ converted to regular code. Example output and all other words
+ are converted to comments:
+
+ >>> text = '''
+ ... Here are examples of simple math.
+ ...
+ ... Python has super accurate integer addition
+ ...
+ ... >>> 2 + 2
+ ... 5
+ ...
+ ... And very friendly error messages:
+ ...
+ ... >>> 1/0
+ ... To Infinity
+ ... And
+ ... Beyond
+ ...
+ ... You can use logic if you want:
+ ...
+ ... >>> if 0:
+ ... ... blah
+ ... ... blah
+ ... ...
+ ...
+ ... Ho hum
+ ... '''
+
+ >>> print script_from_examples(text)
+ # Here are examples of simple math.
+ #
+ # Python has super accurate integer addition
+ #
+ 2 + 2
+ # Expected:
+ ## 5
+ #
+ # And very friendly error messages:
+ #
+ 1/0
+ # Expected:
+ ## To Infinity
+ ## And
+ ## Beyond
+ #
+ # You can use logic if you want:
+ #
+ if 0:
+ blah
+ blah
+ #
+ # Ho hum
+ """
+ output = []
+ for piece in DocTestParser().parse(s):
+ if isinstance(piece, Example):
+ # Add the example's source code (strip trailing NL)
+ output.append(piece.source[:-1])
+ # Add the expected output:
+ want = piece.want
+ if want:
+ output.append('# Expected:')
+ output += ['## '+l for l in want.split('\n')[:-1]]
+ else:
+ # Add non-example text.
+ output += [_comment_line(l)
+ for l in piece.split('\n')[:-1]]
+
+ # Trim junk on both ends.
+ while output and output[-1] == '#':
+ output.pop()
+ while output and output[0] == '#':
+ output.pop(0)
+ # Combine the output, and return it.
+ return '\n'.join(output)
+
+def testsource(module, name):
+ """Extract the test sources from a doctest docstring as a script.
+
+ Provide the module (or dotted name of the module) containing the
+ test to be debugged and the name (within the module) of the object
+ with the doc string with tests to be debugged.
+ """
+ module = _normalize_module(module)
+ tests = DocTestFinder().find(module)
+ test = [t for t in tests if t.name == name]
+ if not test:
+ raise ValueError(name, "not found in tests")
+ test = test[0]
+ testsrc = script_from_examples(test.docstring)
+ return testsrc
+
+def debug_src(src, pm=False, globs=None):
+ """Debug a single doctest docstring, in argument `src`'"""
+ testsrc = script_from_examples(src)
+ debug_script(testsrc, pm, globs)
+
+def debug_script(src, pm=False, globs=None):
+ "Debug a test script. `src` is the script, as a string."
+ import pdb
+
+ # Note that tempfile.NameTemporaryFile() cannot be used. As the
+ # docs say, a file so created cannot be opened by name a second time
+ # on modern Windows boxes, and execfile() needs to open it.
+ srcfilename = tempfile.mktemp(".py", "doctestdebug")
+ f = open(srcfilename, 'w')
+ f.write(src)
+ f.close()
+
+ try:
+ if globs:
+ globs = globs.copy()
+ else:
+ globs = {}
+
+ if pm:
+ try:
+ execfile(srcfilename, globs, globs)
+ except:
+ print sys.exc_info()[1]
+ pdb.post_mortem(sys.exc_info()[2])
+ else:
+ # Note that %r is vital here. '%s' instead can, e.g., cause
+ # backslashes to get treated as metacharacters on Windows.
+ pdb.run("execfile(%r)" % srcfilename, globs, globs)
+
+ finally:
+ os.remove(srcfilename)
+
+def debug(module, name, pm=False):
+ """Debug a single doctest docstring.
+
+ Provide the module (or dotted name of the module) containing the
+ test to be debugged and the name (within the module) of the object
+ with the docstring with tests to be debugged.
+ """
+ module = _normalize_module(module)
+ testsrc = testsource(module, name)
+ debug_script(testsrc, pm, module.__dict__)
+
+######################################################################
+## 10. Example Usage
+######################################################################
+class _TestClass:
+ """
+ A pointless class, for sanity-checking of docstring testing.
+
+ Methods:
+ square()
+ get()
+
+ >>> _TestClass(13).get() + _TestClass(-12).get()
+ 1
+ >>> hex(_TestClass(13).square().get())
+ '0xa9'
+ """
+
+ def __init__(self, val):
+ """val -> _TestClass object with associated value val.
+
+ >>> t = _TestClass(123)
+ >>> print t.get()
+ 123
+ """
+
+ self.val = val
+
+ def square(self):
+ """square() -> square TestClass's associated value
+
+ >>> _TestClass(13).square().get()
+ 169
+ """
+
+ self.val = self.val ** 2
+ return self
+
+ def get(self):
+ """get() -> return TestClass's associated value.
+
+ >>> x = _TestClass(-42)
+ >>> print x.get()
+ -42
+ """
+
+ return self.val
+
+__test__ = {"_TestClass": _TestClass,
+ "string": r"""
+ Example of a string object, searched as-is.
+ >>> x = 1; y = 2
+ >>> x + y, x * y
+ (3, 2)
+ """,
+
+ "bool-int equivalence": r"""
+ In 2.2, boolean expressions displayed
+ 0 or 1. By default, we still accept
+ them. This can be disabled by passing
+ DONT_ACCEPT_TRUE_FOR_1 to the new
+ optionflags argument.
+ >>> 4 == 4
+ 1
+ >>> 4 == 4
+ True
+ >>> 4 > 4
+ 0
+ >>> 4 > 4
+ False
+ """,
+
+ "blank lines": r"""
+ Blank lines can be marked with <BLANKLINE>:
+ >>> print 'foo\n\nbar\n'
+ foo
+ <BLANKLINE>
+ bar
+ <BLANKLINE>
+ """,
+
+ "ellipsis": r"""
+ If the ellipsis flag is used, then '...' can be used to
+ elide substrings in the desired output:
+ >>> print range(1000) #doctest: +ELLIPSIS
+ [0, 1, 2, ..., 999]
+ """,
+
+ "whitespace normalization": r"""
+ If the whitespace normalization flag is used, then
+ differences in whitespace are ignored.
+ >>> print range(30) #doctest: +NORMALIZE_WHITESPACE
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29]
+ """,
+ }
+
+def _test():
+ r = unittest.TextTestRunner()
+ r.run(DocTestSuite())
+
+if __name__ == "__main__":
+ _test()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/filemixin.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/filemixin.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/filemixin.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,53 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+class FileMixin(object):
+
+ """
+ Used to provide auxiliary methods to objects simulating files.
+ Objects must implement write, and read if they are input files.
+ Also they should implement close.
+
+ Other methods you may wish to override:
+ * flush()
+ * seek(offset[, whence])
+ * tell()
+ * truncate([size])
+
+ Attributes you may wish to provide:
+ * closed
+ * encoding (you should also respect that in write())
+ * mode
+ * newlines (hard to support)
+ * softspace
+ """
+
+ def flush(self):
+ pass
+
+ def next(self):
+ return self.readline()
+
+ def readline(self, size=None):
+ # @@: This is a lame implementation; but a buffer would probably
+ # be necessary for a better implementation
+ output = []
+ while 1:
+ next = self.read(1)
+ if not next:
+ return ''.join(output)
+ output.append(next)
+ if size and size > 0 and len(output) >= size:
+ return ''.join(output)
+ if next == '\n':
+ # @@: also \r?
+ return ''.join(output)
+
+ def xreadlines(self):
+ return self
+
+ def writelines(self, lines):
+ for line in lines:
+ self.write(line)
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/finddata.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/finddata.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/finddata.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,99 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# Note: you may want to copy this into your setup.py file verbatim, as
+# you can't import this from another package, when you don't know if
+# that package is installed yet.
+
+import os
+import sys
+from fnmatch import fnmatchcase
+from distutils.util import convert_path
+
+# Provided as an attribute, so you can append to these instead
+# of replicating them:
+standard_exclude = ('*.py', '*.pyc', '*$py.class', '*~', '.*', '*.bak')
+standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
+ './dist', 'EGG-INFO', '*.egg-info')
+
+def find_package_data(
+ where='.', package='',
+ exclude=standard_exclude,
+ exclude_directories=standard_exclude_directories,
+ only_in_packages=True,
+ show_ignored=False):
+ """
+ Return a dictionary suitable for use in ``package_data``
+ in a distutils ``setup.py`` file.
+
+ The dictionary looks like::
+
+ {'package': [files]}
+
+ Where ``files`` is a list of all the files in that package that
+ don't match anything in ``exclude``.
+
+ If ``only_in_packages`` is true, then top-level directories that
+ are not packages won't be included (but directories under packages
+ will).
+
+ Directories matching any pattern in ``exclude_directories`` will
+ be ignored; by default directories with leading ``.``, ``CVS``,
+ and ``_darcs`` will be ignored.
+
+ If ``show_ignored`` is true, then all the files that aren't
+ included in package data are shown on stderr (for debugging
+ purposes).
+
+ Note patterns use wildcards, or can be exact paths (including
+ leading ``./``), and all searching is case-insensitive.
+ """
+
+ out = {}
+ stack = [(convert_path(where), '', package, only_in_packages)]
+ while stack:
+ where, prefix, package, only_in_packages = stack.pop(0)
+ for name in os.listdir(where):
+ fn = os.path.join(where, name)
+ if os.path.isdir(fn):
+ bad_name = False
+ for pattern in exclude_directories:
+ if (fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "Directory %s ignored by pattern %s"
+ % (fn, pattern))
+ break
+ if bad_name:
+ continue
+ if (os.path.isfile(os.path.join(fn, '__init__.py'))
+ and not prefix):
+ if not package:
+ new_package = name
+ else:
+ new_package = package + '.' + name
+ stack.append((fn, '', new_package, False))
+ else:
+ stack.append((fn, prefix + name + '/', package, only_in_packages))
+ elif package or not only_in_packages:
+ # is a file
+ bad_name = False
+ for pattern in exclude:
+ if (fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "File %s ignored by pattern %s"
+ % (fn, pattern))
+ break
+ if bad_name:
+ continue
+ out.setdefault(package, []).append(prefix+name)
+ return out
+
+if __name__ == '__main__':
+ import pprint
+ pprint.pprint(
+ find_package_data(show_ignored=True))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/findpackage.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/findpackage.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/findpackage.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,26 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+import sys
+import os
+
+def find_package(dir):
+ """
+ Given a directory, finds the equivalent package name. If it
+ is directly in sys.path, returns ''.
+ """
+ dir = os.path.abspath(dir)
+ orig_dir = dir
+ path = map(os.path.abspath, sys.path)
+ packages = []
+ last_dir = None
+ while 1:
+ if dir in path:
+ return '.'.join(packages)
+ packages.insert(0, os.path.basename(dir))
+ dir = os.path.dirname(dir)
+ if last_dir == dir:
+ raise ValueError(
+ "%s is not under any path found in sys.path" % orig_dir)
+ last_dir = dir
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/import_string.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/import_string.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/import_string.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,95 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+'imports' a string -- converts a string to a Python object, importing
+any necessary modules and evaluating the expression. Everything
+before the : in an import expression is the module path; everything
+after is an expression to be evaluated in the namespace of that
+module.
+
+Alternately, if no : is present, then import the modules and get the
+attributes as necessary. Arbitrary expressions are not allowed in
+that case.
+"""
+
+def eval_import(s):
+ """
+ Import a module, or import an object from a module.
+
+ A module name like ``foo.bar:baz()`` can be used, where
+ ``foo.bar`` is the module, and ``baz()`` is an expression
+ evaluated in the context of that module. Note this is not safe on
+ arbitrary strings because of the eval.
+ """
+ if ':' not in s:
+ return simple_import(s)
+ module_name, expr = s.split(':', 1)
+ module = import_module(module_name)
+ obj = eval(expr, module.__dict__)
+ return obj
+
+def simple_import(s):
+ """
+ Import a module, or import an object from a module.
+
+ A name like ``foo.bar.baz`` can be a module ``foo.bar.baz`` or a
+ module ``foo.bar`` with an object ``baz`` in it, or a module
+ ``foo`` with an object ``bar`` with an attribute ``baz``.
+ """
+ parts = s.split('.')
+ module = import_module(parts[0])
+ name = parts[0]
+ parts = parts[1:]
+ last_import_error = None
+ while parts:
+ name += '.' + parts[0]
+ try:
+ module = import_module(name)
+ parts = parts[1:]
+ except ImportError, e:
+ last_import_error = e
+ break
+ obj = module
+ while parts:
+ try:
+ obj = getattr(module, parts[0])
+ except AttributeError:
+ raise ImportError(
+ "Cannot find %s in module %r (stopped importing modules with error %s)" % (parts[0], module, last_import_error))
+ parts = parts[1:]
+ return obj
+
+def import_module(s):
+ """
+ Import a module.
+ """
+ mod = __import__(s)
+ parts = s.split('.')
+ for part in parts[1:]:
+ mod = getattr(mod, part)
+ return mod
+
+def try_import_module(module_name):
+ """
+ Imports a module, but catches import errors. Only catches errors
+ when that module doesn't exist; if that module itself has an
+ import error it will still get raised. Returns None if the module
+ doesn't exist.
+ """
+ try:
+ return import_module(module_name)
+ except ImportError, e:
+ if not getattr(e, 'args', None):
+ raise
+ desc = e.args[0]
+ if not desc.startswith('No module named '):
+ raise
+ desc = desc[len('No module named '):]
+ # If you import foo.bar.baz, the bad import could be any
+ # of foo.bar.baz, bar.baz, or baz; we'll test them all:
+ parts = module_name.split('.')
+ for i in range(len(parts)):
+ if desc == '.'.join(parts[i:]):
+ return None
+ raise
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/intset.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/intset.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/intset.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,511 @@
+# -*- coding: iso-8859-15 -*-
+"""Immutable integer set type.
+
+Integer set class.
+
+Copyright (C) 2006, Heiko Wundram.
+Released under the MIT license.
+"""
+
+# Version information
+# -------------------
+
+__author__ = "Heiko Wundram <me at modelnine.org>"
+__version__ = "0.2"
+__revision__ = "6"
+__date__ = "2006-01-20"
+
+
+# Utility classes
+# ---------------
+
+class _Infinity(object):
+ """Internal type used to represent infinity values."""
+
+ __slots__ = ["_neg"]
+
+ def __init__(self,neg):
+ self._neg = neg
+
+ def __lt__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return ( self._neg and
+ not ( isinstance(value,_Infinity) and value._neg ) )
+
+ def __le__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return self._neg
+
+ def __gt__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return not ( self._neg or
+ ( isinstance(value,_Infinity) and not value._neg ) )
+
+ def __ge__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return not self._neg
+
+ def __eq__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return isinstance(value,_Infinity) and self._neg == value._neg
+
+ def __ne__(self,value):
+ if not isinstance(value,(int,long,_Infinity)):
+ return NotImplemented
+ return not isinstance(value,_Infinity) or self._neg <> value._neg
+
+ def __repr__(self):
+ return "None"
+
+
+# Constants
+# ---------
+
+_MININF = _Infinity(True)
+_MAXINF = _Infinity(False)
+
+
+# Integer set class
+# -----------------
+
+class IntSet(object):
+ """Integer set class with efficient storage in a RLE format of ranges.
+ Supports minus and plus infinity in the range."""
+
+ __slots__ = ["_ranges","_min","_max","_hash"]
+
+ def __init__(self,*args,**kwargs):
+ """Initialize an integer set. The constructor accepts an unlimited
+ number of arguments that may either be tuples in the form of
+ (start,stop) where either start or stop may be a number or None to
+ represent maximum/minimum in that direction. The range specified by
+ (start,stop) is always inclusive (differing from the builtin range
+ operator).
+
+ Keyword arguments that can be passed to an integer set are min and
+ max, which specify the minimum and maximum number in the set,
+ respectively. You can also pass None here to represent minus or plus
+ infinity, which is also the default.
+ """
+
+ # Special case copy constructor.
+ if len(args) == 1 and isinstance(args[0],IntSet):
+ if kwargs:
+ raise ValueError("No keyword arguments for copy constructor.")
+ self._min = args[0]._min
+ self._max = args[0]._max
+ self._ranges = args[0]._ranges
+ self._hash = args[0]._hash
+ return
+
+ # Initialize set.
+ self._ranges = []
+
+ # Process keyword arguments.
+ self._min = kwargs.pop("min",_MININF)
+ self._max = kwargs.pop("max",_MAXINF)
+ if self._min is None:
+ self._min = _MININF
+ if self._max is None:
+ self._max = _MAXINF
+
+ # Check keyword arguments.
+ if kwargs:
+ raise ValueError("Invalid keyword argument.")
+ if not ( isinstance(self._min,(int,long)) or self._min is _MININF ):
+ raise TypeError("Invalid type of min argument.")
+ if not ( isinstance(self._max,(int,long)) or self._max is _MAXINF ):
+ raise TypeError("Invalid type of max argument.")
+ if ( self._min is not _MININF and self._max is not _MAXINF and
+ self._min > self._max ):
+ raise ValueError("Minimum is not smaller than maximum.")
+ if isinstance(self._max,(int,long)):
+ self._max += 1
+
+ # Process arguments.
+ for arg in args:
+ if isinstance(arg,(int,long)):
+ start, stop = arg, arg+1
+ elif isinstance(arg,tuple):
+ if len(arg) <> 2:
+ raise ValueError("Invalid tuple, must be (start,stop).")
+
+ # Process argument.
+ start, stop = arg
+ if start is None:
+ start = self._min
+ if stop is None:
+ stop = self._max
+
+ # Check arguments.
+ if not ( isinstance(start,(int,long)) or start is _MININF ):
+ raise TypeError("Invalid type of tuple start.")
+ if not ( isinstance(stop,(int,long)) or stop is _MAXINF ):
+ raise TypeError("Invalid type of tuple stop.")
+ if ( start is not _MININF and stop is not _MAXINF and
+ start > stop ):
+ continue
+ if isinstance(stop,(int,long)):
+ stop += 1
+ else:
+ raise TypeError("Invalid argument.")
+
+ if start > self._max:
+ continue
+ elif start < self._min:
+ start = self._min
+ if stop < self._min:
+ continue
+ elif stop > self._max:
+ stop = self._max
+ self._ranges.append((start,stop))
+
+ # Normalize set.
+ self._normalize()
+
+ # Utility functions for set operations
+ # ------------------------------------
+
+ def _iterranges(self,r1,r2,minval=_MININF,maxval=_MAXINF):
+ curval = minval
+ curstates = {"r1":False,"r2":False}
+ imax, jmax = 2*len(r1), 2*len(r2)
+ i, j = 0, 0
+ while i < imax or j < jmax:
+ if i < imax and ( ( j < jmax and
+ r1[i>>1][i&1] < r2[j>>1][j&1] ) or
+ j == jmax ):
+ cur_r, newname, newstate = r1[i>>1][i&1], "r1", not (i&1)
+ i += 1
+ else:
+ cur_r, newname, newstate = r2[j>>1][j&1], "r2", not (j&1)
+ j += 1
+ if curval < cur_r:
+ if cur_r > maxval:
+ break
+ yield curstates, (curval,cur_r)
+ curval = cur_r
+ curstates[newname] = newstate
+ if curval < maxval:
+ yield curstates, (curval,maxval)
+
+ def _normalize(self):
+ self._ranges.sort()
+ i = 1
+ while i < len(self._ranges):
+ if self._ranges[i][0] < self._ranges[i-1][1]:
+ self._ranges[i-1] = (self._ranges[i-1][0],
+ max(self._ranges[i-1][1],
+ self._ranges[i][1]))
+ del self._ranges[i]
+ else:
+ i += 1
+ self._ranges = tuple(self._ranges)
+ self._hash = hash(self._ranges)
+
+ def __coerce__(self,other):
+ if isinstance(other,IntSet):
+ return self, other
+ elif isinstance(other,(int,long,tuple)):
+ try:
+ return self, self.__class__(other)
+ except TypeError:
+ # Catch a type error, in that case the structure specified by
+ # other is something we can't coerce, return NotImplemented.
+ # ValueErrors are not caught, they signal that the data was
+ # invalid for the constructor. This is appropriate to signal
+ # as a ValueError to the caller.
+ return NotImplemented
+ elif isinstance(other,list):
+ try:
+ return self, self.__class__(*other)
+ except TypeError:
+ # See above.
+ return NotImplemented
+ return NotImplemented
+
+ # Set function definitions
+ # ------------------------
+
+ def _make_function(name,type,doc,pall,pany=None):
+ """Makes a function to match two ranges. Accepts two types: either
+ 'set', which defines a function which returns a set with all ranges
+ matching pall (pany is ignored), or 'bool', which returns True if pall
+ matches for all ranges and pany matches for any one range. doc is the
+ dostring to give this function. pany may be none to ignore the any
+ match.
+
+ The predicates get a dict with two keys, 'r1', 'r2', which denote
+ whether the current range is present in range1 (self) and/or range2
+ (other) or none of the two, respectively."""
+
+ if type == "set":
+ def f(self,other):
+ coerced = self.__coerce__(other)
+ if coerced is NotImplemented:
+ return NotImplemented
+ other = coerced[1]
+ newset = self.__class__.__new__(self.__class__)
+ newset._min = min(self._min,other._min)
+ newset._max = max(self._max,other._max)
+ newset._ranges = []
+ for states, (start,stop) in \
+ self._iterranges(self._ranges,other._ranges,
+ newset._min,newset._max):
+ if pall(states):
+ if newset._ranges and newset._ranges[-1][1] == start:
+ newset._ranges[-1] = (newset._ranges[-1][0],stop)
+ else:
+ newset._ranges.append((start,stop))
+ newset._ranges = tuple(newset._ranges)
+ newset._hash = hash(self._ranges)
+ return newset
+ elif type == "bool":
+ def f(self,other):
+ coerced = self.__coerce__(other)
+ if coerced is NotImplemented:
+ return NotImplemented
+ other = coerced[1]
+ _min = min(self._min,other._min)
+ _max = max(self._max,other._max)
+ found = not pany
+ for states, (start,stop) in \
+ self._iterranges(self._ranges,other._ranges,_min,_max):
+ if not pall(states):
+ return False
+ found = found or pany(states)
+ return found
+ else:
+ raise ValueError("Invalid type of function to create.")
+ try:
+ f.func_name = name
+ except TypeError:
+ pass
+ f.func_doc = doc
+ return f
+
+ # Intersection.
+ __and__ = _make_function("__and__","set",
+ "Intersection of two sets as a new set.",
+ lambda s: s["r1"] and s["r2"])
+ __rand__ = _make_function("__rand__","set",
+ "Intersection of two sets as a new set.",
+ lambda s: s["r1"] and s["r2"])
+ intersection = _make_function("intersection","set",
+ "Intersection of two sets as a new set.",
+ lambda s: s["r1"] and s["r2"])
+
+ # Union.
+ __or__ = _make_function("__or__","set",
+ "Union of two sets as a new set.",
+ lambda s: s["r1"] or s["r2"])
+ __ror__ = _make_function("__ror__","set",
+ "Union of two sets as a new set.",
+ lambda s: s["r1"] or s["r2"])
+ union = _make_function("union","set",
+ "Union of two sets as a new set.",
+ lambda s: s["r1"] or s["r2"])
+
+ # Difference.
+ __sub__ = _make_function("__sub__","set",
+ "Difference of two sets as a new set.",
+ lambda s: s["r1"] and not s["r2"])
+ __rsub__ = _make_function("__rsub__","set",
+ "Difference of two sets as a new set.",
+ lambda s: s["r2"] and not s["r1"])
+ difference = _make_function("difference","set",
+ "Difference of two sets as a new set.",
+ lambda s: s["r1"] and not s["r2"])
+
+ # Symmetric difference.
+ __xor__ = _make_function("__xor__","set",
+ "Symmetric difference of two sets as a new set.",
+ lambda s: s["r1"] ^ s["r2"])
+ __rxor__ = _make_function("__rxor__","set",
+ "Symmetric difference of two sets as a new set.",
+ lambda s: s["r1"] ^ s["r2"])
+ symmetric_difference = _make_function("symmetric_difference","set",
+ "Symmetric difference of two sets as a new set.",
+ lambda s: s["r1"] ^ s["r2"])
+
+ # Containership testing.
+ __contains__ = _make_function("__contains__","bool",
+ "Returns true if self is superset of other.",
+ lambda s: s["r1"] or not s["r2"])
+ issubset = _make_function("issubset","bool",
+ "Returns true if self is subset of other.",
+ lambda s: s["r2"] or not s["r1"])
+ istruesubset = _make_function("istruesubset","bool",
+ "Returns true if self is true subset of other.",
+ lambda s: s["r2"] or not s["r1"],
+ lambda s: s["r2"] and not s["r1"])
+ issuperset = _make_function("issuperset","bool",
+ "Returns true if self is superset of other.",
+ lambda s: s["r1"] or not s["r2"])
+ istruesuperset = _make_function("istruesuperset","bool",
+ "Returns true if self is true superset of other.",
+ lambda s: s["r1"] or not s["r2"],
+ lambda s: s["r1"] and not s["r2"])
+ overlaps = _make_function("overlaps","bool",
+ "Returns true if self overlaps with other.",
+ lambda s: True,
+ lambda s: s["r1"] and s["r2"])
+
+ # Comparison.
+ __eq__ = _make_function("__eq__","bool",
+ "Returns true if self is equal to other.",
+ lambda s: not ( s["r1"] ^ s["r2"] ))
+ __ne__ = _make_function("__ne__","bool",
+ "Returns true if self is different to other.",
+ lambda s: True,
+ lambda s: s["r1"] ^ s["r2"])
+
+ # Clean up namespace.
+ del _make_function
+
+ # Define other functions.
+ def inverse(self):
+ """Inverse of set as a new set."""
+
+ newset = self.__class__.__new__(self.__class__)
+ newset._min = self._min
+ newset._max = self._max
+ newset._ranges = []
+ laststop = self._min
+ for r in self._ranges:
+ if laststop < r[0]:
+ newset._ranges.append((laststop,r[0]))
+ laststop = r[1]
+ if laststop < self._max:
+ newset._ranges.append((laststop,self._max))
+ return newset
+
+ __invert__ = inverse
+
+ # Hashing
+ # -------
+
+ def __hash__(self):
+ """Returns a hash value representing this integer set. As the set is
+ always stored normalized, the hash value is guaranteed to match for
+ matching ranges."""
+
+ return self._hash
+
+ # Iterating
+ # ---------
+
+ def __len__(self):
+ """Get length of this integer set. In case the length is larger than
+ 2**31 (including infinitely sized integer sets), it raises an
+ OverflowError. This is due to len() restricting the size to
+ 0 <= len < 2**31."""
+
+ if not self._ranges:
+ return 0
+ if self._ranges[0][0] is _MININF or self._ranges[-1][1] is _MAXINF:
+ raise OverflowError("Infinitely sized integer set.")
+ rlen = 0
+ for r in self._ranges:
+ rlen += r[1]-r[0]
+ if rlen >= 2**31:
+ raise OverflowError("Integer set bigger than 2**31.")
+ return rlen
+
+ def len(self):
+ """Returns the length of this integer set as an integer. In case the
+ length is infinite, returns -1. This function exists because of a
+ limitation of the builtin len() function which expects values in
+ the range 0 <= len < 2**31. Use this function in case your integer
+ set might be larger."""
+
+ if not self._ranges:
+ return 0
+ if self._ranges[0][0] is _MININF or self._ranges[-1][1] is _MAXINF:
+ return -1
+ rlen = 0
+ for r in self._ranges:
+ rlen += r[1]-r[0]
+ return rlen
+
+ def __nonzero__(self):
+ """Returns true if this integer set contains at least one item."""
+
+ return bool(self._ranges)
+
+ def __iter__(self):
+ """Iterate over all values in this integer set. Iteration always starts
+ by iterating from lowest to highest over the ranges that are bounded.
+ After processing these, all ranges that are unbounded (maximum 2) are
+ yielded intermixed."""
+
+ ubranges = []
+ for r in self._ranges:
+ if r[0] is _MININF:
+ if r[1] is _MAXINF:
+ ubranges.extend(([0,1],[-1,-1]))
+ else:
+ ubranges.append([r[1]-1,-1])
+ elif r[1] is _MAXINF:
+ ubranges.append([r[0],1])
+ else:
+ for val in xrange(r[0],r[1]):
+ yield val
+ if ubranges:
+ while True:
+ for ubrange in ubranges:
+ yield ubrange[0]
+ ubrange[0] += ubrange[1]
+
+ # Printing
+ # --------
+
+ def __repr__(self):
+ """Return a representation of this integer set. The representation is
+ executable to get an equal integer set."""
+
+ rv = []
+ for start, stop in self._ranges:
+ if ( isinstance(start,(int,long)) and isinstance(stop,(int,long))
+ and stop-start == 1 ):
+ rv.append("%r" % start)
+ elif isinstance(stop,(int,long)):
+ rv.append("(%r,%r)" % (start,stop-1))
+ else:
+ rv.append("(%r,%r)" % (start,stop))
+ if self._min is not _MININF:
+ rv.append("min=%r" % self._min)
+ if self._max is not _MAXINF:
+ rv.append("max=%r" % self._max)
+ return "%s(%s)" % (self.__class__.__name__,",".join(rv))
+
+if __name__ == "__main__":
+ # Little test script demonstrating functionality.
+ x = IntSet((10,20),30)
+ y = IntSet((10,20))
+ z = IntSet((10,20),30,(15,19),min=0,max=40)
+ print x
+ print x&110
+ print x|110
+ print x^(15,25)
+ print x-12
+ print 12 in x
+ print x.issubset(x)
+ print y.issubset(x)
+ print x.istruesubset(x)
+ print y.istruesubset(x)
+ for val in x:
+ print val
+ print x.inverse()
+ print x == z
+ print x == y
+ print x <> y
+ print hash(x)
+ print hash(z)
+ print len(x)
+ print x.len()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/ip4.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/ip4.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/ip4.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,273 @@
+# -*- coding: iso-8859-15 -*-
+"""IP4 address range set implementation.
+
+Implements an IPv4-range type.
+
+Copyright (C) 2006, Heiko Wundram.
+Released under the MIT-license.
+"""
+
+# Version information
+# -------------------
+
+__author__ = "Heiko Wundram <me at modelnine.org>"
+__version__ = "0.2"
+__revision__ = "3"
+__date__ = "2006-01-20"
+
+
+# Imports
+# -------
+
+import intset
+import socket
+
+
+# IP4Range class
+# --------------
+
+class IP4Range(intset.IntSet):
+ """IP4 address range class with efficient storage of address ranges.
+ Supports all set operations."""
+
+ _MINIP4 = 0
+ _MAXIP4 = (1<<32) - 1
+ _UNITYTRANS = "".join([chr(n) for n in range(256)])
+ _IPREMOVE = "0123456789."
+
+ def __init__(self,*args):
+ """Initialize an ip4range class. The constructor accepts an unlimited
+ number of arguments that may either be tuples in the form (start,stop),
+ integers, longs or strings, where start and stop in a tuple may
+ also be of the form integer, long or string.
+
+ Passing an integer or long means passing an IPv4-address that's already
+ been converted to integer notation, whereas passing a string specifies
+ an address where this conversion still has to be done. A string
+ address may be in the following formats:
+
+ - 1.2.3.4 - a plain address, interpreted as a single address
+ - 1.2.3 - a set of addresses, interpreted as 1.2.3.0-1.2.3.255
+ - localhost - hostname to look up, interpreted as single address
+ - 1.2.3<->5 - a set of addresses, interpreted as 1.2.3.0-1.2.5.255
+ - 1.2.0.0/16 - a set of addresses, interpreted as 1.2.0.0-1.2.255.255
+
+ Only the first three notations are valid if you use a string address in
+ a tuple, whereby notation 2 is interpreted as 1.2.3.0 if specified as
+ lower bound and 1.2.3.255 if specified as upper bound, not as a range
+ of addresses.
+
+ Specifying a range is done with the <-> operator. This is necessary
+ because '-' might be present in a hostname. '<->' shouldn't be, ever.
+ """
+
+ # Special case copy constructor.
+ if len(args) == 1 and isinstance(args[0],IP4Range):
+ super(IP4Range,self).__init__(args[0])
+ return
+
+ # Convert arguments to tuple syntax.
+ args = list(args)
+ for i in range(len(args)):
+ argval = args[i]
+ if isinstance(argval,str):
+ if "<->" in argval:
+ # Type 4 address.
+ args[i] = self._parseRange(*argval.split("<->",1))
+ continue
+ elif "/" in argval:
+ # Type 5 address.
+ args[i] = self._parseMask(*argval.split("/",1))
+ else:
+ # Type 1, 2 or 3.
+ args[i] = self._parseAddrRange(argval)
+ elif isinstance(argval,tuple):
+ if len(tuple) <> 2:
+ raise ValueError("Tuple is of invalid length.")
+ addr1, addr2 = argval
+ if isinstance(addr1,str):
+ addr1 = self._parseAddrRange(addr1)[0]
+ elif not isinstance(addr1,(int,long)):
+ raise TypeError("Invalid argument.")
+ if isinstance(addr2,str):
+ addr2 = self._parseAddrRange(addr2)[1]
+ elif not isinstance(addr2,(int,long)):
+ raise TypeError("Invalid argument.")
+ args[i] = (addr1,addr2)
+ elif not isinstance(argval,(int,long)):
+ raise TypeError("Invalid argument.")
+
+ # Initialize the integer set.
+ super(IP4Range,self).__init__(min=self._MINIP4,max=self._MAXIP4,*args)
+
+ # Parsing functions
+ # -----------------
+
+ def _parseRange(self,addr1,addr2):
+ naddr1, naddr1len = _parseAddr(addr1)
+ naddr2, naddr2len = _parseAddr(addr2)
+ if naddr2len < naddr1len:
+ naddr2 += naddr1&(((1<<((naddr1len-naddr2len)*8))-1)<<
+ (naddr2len*8))
+ naddr2len = naddr1len
+ elif naddr2len > naddr1len:
+ raise ValueError("Range has more dots than address.")
+ naddr1 <<= (4-naddr1len)*8
+ naddr2 <<= (4-naddr2len)*8
+ naddr2 += (1<<((4-naddr2len)*8))-1
+ return (naddr1,naddr2)
+
+ def _parseMask(self,addr,mask):
+ naddr, naddrlen = _parseAddr(addr)
+ naddr <<= (4-naddrlen)*8
+ try:
+ if not mask:
+ masklen = 0
+ else:
+ masklen = int(mask)
+ if not 0 <= masklen <= 32:
+ raise ValueError
+ except ValueError:
+ try:
+ mask = _parseAddr(mask,False)
+ except ValueError:
+ raise ValueError("Mask isn't parseable.")
+ remaining = 0
+ masklen = 0
+ if not mask:
+ masklen = 0
+ else:
+ while not (mask&1):
+ remaining += 1
+ while (mask&1):
+ mask >>= 1
+ masklen += 1
+ if remaining+masklen <> 32:
+ raise ValueError("Mask isn't a proper host mask.")
+ naddr1 = naddr & (((1<<masklen)-1)<<(32-masklen))
+ naddr2 = naddr1 + (1<<(32-masklen)) - 1
+ return (naddr1,naddr2)
+
+ def _parseAddrRange(self,addr):
+ naddr, naddrlen = _parseAddr(addr)
+ naddr1 = naddr<<((4-naddrlen)*8)
+ naddr2 = ( (naddr<<((4-naddrlen)*8)) +
+ (1<<((4-naddrlen)*8)) - 1 )
+ return (naddr1,naddr2)
+
+ # Utility functions
+ # -----------------
+
+ def _int2ip(self,num):
+ rv = []
+ for i in range(4):
+ rv.append(str(num&255))
+ num >>= 8
+ return ".".join(reversed(rv))
+
+ # Iterating
+ # ---------
+
+ def iteraddresses(self):
+ """Returns an iterator which iterates over ips in this iprange. An
+ IP is returned in string form (e.g. '1.2.3.4')."""
+
+ for v in super(IP4Range,self).__iter__():
+ yield self._int2ip(v)
+
+ def iterranges(self):
+ """Returns an iterator which iterates over ip-ip ranges which build
+ this iprange if combined. An ip-ip pair is returned in string form
+ (e.g. '1.2.3.4-2.3.4.5')."""
+
+ for r in self._ranges:
+ if r[1]-r[0] == 1:
+ yield self._int2ip(r[0])
+ else:
+ yield '%s-%s' % (self._int2ip(r[0]),self._int2ip(r[1]-1))
+
+ def itermasks(self):
+ """Returns an iterator which iterates over ip/mask pairs which build
+ this iprange if combined. An IP/Mask pair is returned in string form
+ (e.g. '1.2.3.0/24')."""
+
+ for r in self._ranges:
+ for v in self._itermasks(r):
+ yield v
+
+ def _itermasks(self,r):
+ ranges = [r]
+ while ranges:
+ cur = ranges.pop()
+ curmask = 0
+ while True:
+ curmasklen = 1<<(32-curmask)
+ start = (cur[0]+curmasklen-1)&(((1<<curmask)-1)<<(32-curmask))
+ if start >= cur[0] and start+curmasklen <= cur[1]:
+ break
+ else:
+ curmask += 1
+ yield "%s/%s" % (self._int2ip(start),curmask)
+ if cur[0] < start:
+ ranges.append((cur[0],start))
+ if cur[1] > start+curmasklen:
+ ranges.append((start+curmasklen,cur[1]))
+
+ __iter__ = iteraddresses
+
+ # Printing
+ # --------
+
+ def __repr__(self):
+ """Returns a string which can be used to reconstruct this iprange."""
+
+ rv = []
+ for start, stop in self._ranges:
+ if stop-start == 1:
+ rv.append("%r" % (self._int2ip(start),))
+ else:
+ rv.append("(%r,%r)" % (self._int2ip(start),
+ self._int2ip(stop-1)))
+ return "%s(%s)" % (self.__class__.__name__,",".join(rv))
+
+def _parseAddr(addr,lookup=True):
+ if lookup and addr.translate(IP4Range._UNITYTRANS, IP4Range._IPREMOVE):
+ try:
+ addr = socket.gethostbyname(addr)
+ except socket.error:
+ raise ValueError("Invalid Hostname as argument.")
+ naddr = 0
+ for naddrpos, part in enumerate(addr.split(".")):
+ if naddrpos >= 4:
+ raise ValueError("Address contains more than four parts.")
+ try:
+ if not part:
+ part = 0
+ else:
+ part = int(part)
+ if not 0 <= part < 256:
+ raise ValueError
+ except ValueError:
+ raise ValueError("Address part out of range.")
+ naddr <<= 8
+ naddr += part
+ return naddr, naddrpos+1
+
+def ip2int(addr, lookup=True):
+ return _parseAddr(addr, lookup=lookup)[0]
+
+if __name__ == "__main__":
+ # Little test script.
+ x = IP4Range("172.22.162.250/24")
+ y = IP4Range("172.22.162.250","172.22.163.250","172.22.163.253<->255")
+ print x
+ for val in x.itermasks():
+ print val
+ for val in y.itermasks():
+ print val
+ for val in (x|y).itermasks():
+ print val
+ for val in (x^y).iterranges():
+ print val
+ for val in x:
+ print val
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/killthread.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/killthread.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/killthread.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+"""
+Kill a thread, from http://sebulba.wikispaces.com/recipe+thread2
+"""
+import types
+try:
+ import ctypes
+except ImportError:
+ raise ImportError(
+ "You cannot use paste.util.killthread without ctypes installed")
+if not hasattr(ctypes, 'pythonapi'):
+ raise ImportError(
+ "You cannot use paste.util.killthread without ctypes.pythonapi")
+
+def async_raise(tid, exctype):
+ """raises the exception, performs cleanup if needed.
+
+ tid is the value given by thread.get_ident() (an integer).
+ Raise SystemExit to kill a thread."""
+ if not isinstance(exctype, (types.ClassType, type)):
+ raise TypeError("Only types can be raised (not instances)")
+ if not isinstance(tid, int):
+ raise TypeError("tid must be an integer")
+ res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
+ if res == 0:
+ raise ValueError("invalid thread id")
+ elif res != 1:
+ # """if it returns a number greater than one, you're in trouble,
+ # and you should call it again with exc=NULL to revert the effect"""
+ ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), 0)
+ raise SystemError("PyThreadState_SetAsyncExc failed")
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/looper.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/looper.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/looper.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,152 @@
+"""
+Helper for looping over sequences, particular in templates.
+
+Often in a loop in a template it's handy to know what's next up,
+previously up, if this is the first or last item in the sequence, etc.
+These can be awkward to manage in a normal Python loop, but using the
+looper you can get a better sense of the context. Use like::
+
+ >>> for loop, item in looper(['a', 'b', 'c']):
+ ... print loop.number, item
+ ... if not loop.last:
+ ... print '---'
+ 1 a
+ ---
+ 2 b
+ ---
+ 3 c
+
+"""
+
+__all__ = ['looper']
+
+class looper(object):
+ """
+ Helper for looping (particularly in templates)
+
+ Use this like::
+
+ for loop, item in looper(seq):
+ if loop.first:
+ ...
+ """
+
+ def __init__(self, seq):
+ self.seq = seq
+
+ def __iter__(self):
+ return looper_iter(self.seq)
+
+ def __repr__(self):
+ return '<%s for %r>' % (
+ self.__class__.__name__, self.seq)
+
+class looper_iter(object):
+
+ def __init__(self, seq):
+ self.seq = list(seq)
+ self.pos = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.pos >= len(self.seq):
+ raise StopIteration
+ result = loop_pos(self.seq, self.pos), self.seq[self.pos]
+ self.pos += 1
+ return result
+
+class loop_pos(object):
+
+ def __init__(self, seq, pos):
+ self.seq = seq
+ self.pos = pos
+
+ def __repr__(self):
+ return '<loop pos=%r at %r>' % (
+ self.seq[pos], pos)
+
+ def index(self):
+ return self.pos
+ index = property(index)
+
+ def number(self):
+ return self.pos + 1
+ number = property(number)
+
+ def item(self):
+ return self.seq[self.pos]
+ item = property(item)
+
+ def next(self):
+ try:
+ return self.seq[self.pos+1]
+ except IndexError:
+ return None
+ next = property(next)
+
+ def previous(self):
+ if self.pos == 0:
+ return None
+ return self.seq[self.pos-1]
+ previous = property(previous)
+
+ def odd(self):
+ return not self.pos % 2
+ odd = property(odd)
+
+ def even(self):
+ return self.pos % 2
+ even = property(even)
+
+ def first(self):
+ return self.pos == 0
+ first = property(first)
+
+ def last(self):
+ return self.pos == len(self.seq)-1
+ last = property(last)
+
+ def length(self):
+ return len(self.seq)
+ length = property(length)
+
+ def first_group(self, getter=None):
+ """
+ Returns true if this item is the start of a new group,
+ where groups mean that some attribute has changed. The getter
+ can be None (the item itself changes), an attribute name like
+ ``'.attr'``, a function, or a dict key or list index.
+ """
+ if self.first:
+ return True
+ return self._compare_group(self.item, self.previous, getter)
+
+ def last_group(self, getter=None):
+ """
+ Returns true if this item is the end of a new group,
+ where groups mean that some attribute has changed. The getter
+ can be None (the item itself changes), an attribute name like
+ ``'.attr'``, a function, or a dict key or list index.
+ """
+ if self.last:
+ return True
+ return self._compare_group(self.item, self.next, getter)
+
+ def _compare_group(self, item, other, getter):
+ if getter is None:
+ return item != other
+ elif (isinstance(getter, basestring)
+ and getter.startswith('.')):
+ getter = getter[1:]
+ if getter.endswith('()'):
+ getter = getter[:-2]
+ return getattr(item, getter)() != getattr(other, getter)()
+ else:
+ return getattr(item, getter) != getattr(other, getter)
+ elif callable(getter):
+ return getter(item) != getter(other)
+ else:
+ return item[getter] != other[getter]
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/mimeparse.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/mimeparse.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/mimeparse.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,160 @@
+"""MIME-Type Parser
+
+This module provides basic functions for handling mime-types. It can handle
+matching mime-types against a list of media-ranges. See section 14.1 of
+the HTTP specification [RFC 2616] for a complete explanation.
+
+ http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
+
+Based on mimeparse 0.1.2 by Joe Gregorio:
+
+ http://code.google.com/p/mimeparse/
+
+Contents:
+ - parse_mime_type(): Parses a mime-type into its component parts.
+ - parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q' quality parameter.
+ - quality(): Determines the quality ('q') of a mime-type when compared against a list of media-ranges.
+ - quality_parsed(): Just like quality() except the second parameter must be pre-parsed.
+ - best_match(): Choose the mime-type with the highest quality ('q') from a list of candidates.
+ - desired_matches(): Filter against a list of desired mime-types in the order the server prefers.
+
+"""
+
+
+def parse_mime_type(mime_type):
+ """Carves up a mime-type and returns a tuple of the
+ (type, subtype, params) where 'params' is a dictionary
+ of all the parameters for the media range.
+ For example, the media range 'application/xhtml;q=0.5' would
+ get parsed into:
+
+ ('application', 'xhtml', {'q', '0.5'})
+ """
+ type = mime_type.split(';')
+ type, plist = type[0], type[1:]
+ try:
+ type, subtype = type.split('/', 1)
+ except ValueError:
+ type, subtype = type.strip() or '*', '*'
+ else:
+ type = type.strip() or '*'
+ subtype = subtype.strip() or '*'
+ params = {}
+ for param in plist:
+ param = param.split('=', 1)
+ if len(param) == 2:
+ key, value = param[0].strip(), param[1].strip()
+ if key and value:
+ params[key] = value
+ return type, subtype, params
+
+def parse_media_range(range):
+ """Carves up a media range and returns a tuple of the
+ (type, subtype, params) where 'params' is a dictionary
+ of all the parameters for the media range.
+ For example, the media range 'application/*;q=0.5' would
+ get parsed into:
+
+ ('application', '*', {'q', '0.5'})
+
+ In addition this function also guarantees that there
+ is a value for 'q' in the params dictionary, filling it
+ in with a proper default if necessary.
+ """
+ type, subtype, params = parse_mime_type(range)
+ try:
+ if not 0 <= float(params['q']) <= 1:
+ raise ValueError
+ except (KeyError, ValueError):
+ params['q'] = '1'
+ return type, subtype, params
+
+def fitness_and_quality_parsed(mime_type, parsed_ranges):
+ """Find the best match for a given mime-type against
+ a list of media_ranges that have already been
+ parsed by parse_media_range(). Returns a tuple of
+ the fitness value and the value of the 'q' quality
+ parameter of the best match, or (-1, 0) if no match
+ was found. Just as for quality_parsed(), 'parsed_ranges'
+ must be a list of parsed media ranges."""
+ best_fitness, best_fit_q = -1, 0
+ target_type, target_subtype, target_params = parse_media_range(mime_type)
+ for type, subtype, params in parsed_ranges:
+ if (type == target_type
+ or type == '*' or target_type == '*') and (
+ subtype == target_subtype
+ or subtype == '*' or target_subtype == '*'):
+ fitness = 0
+ if type == target_type:
+ fitness += 100
+ if subtype == target_subtype:
+ fitness += 10
+ for key in target_params:
+ if key != 'q' and key in params:
+ if params[key] == target_params[key]:
+ fitness += 1
+ if fitness > best_fitness:
+ best_fitness = fitness
+ best_fit_q = params['q']
+ return best_fitness, float(best_fit_q)
+
+def quality_parsed(mime_type, parsed_ranges):
+ """Find the best match for a given mime-type against
+ a list of media_ranges that have already been
+ parsed by parse_media_range(). Returns the
+ 'q' quality parameter of the best match, 0 if no
+ match was found. This function behaves the same as quality()
+ except that 'parsed_ranges' must be a list of
+ parsed media ranges."""
+ return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]
+
+def quality(mime_type, ranges):
+ """Returns the quality 'q' of a mime-type when compared
+ against the media-ranges in ranges. For example:
+
+ >>> quality('text/html','text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
+ 0.7
+
+ """
+ parsed_ranges = map(parse_media_range, ranges.split(','))
+ return quality_parsed(mime_type, parsed_ranges)
+
+def best_match(supported, header):
+ """Takes a list of supported mime-types and finds the best
+ match for all the media-ranges listed in header. In case of
+ ambiguity, whatever comes first in the list will be chosen.
+ The value of header must be a string that conforms to the format
+ of the HTTP Accept: header. The value of 'supported' is a list
+ of mime-types.
+
+ >>> best_match(['application/xbel+xml', 'text/xml'], 'text/*;q=0.5,*/*; q=0.1')
+ 'text/xml'
+ """
+ if not supported:
+ return ''
+ parsed_header = map(parse_media_range, header.split(','))
+ best_type = max([
+ (fitness_and_quality_parsed(mime_type, parsed_header), -n)
+ for n, mime_type in enumerate(supported)])
+ return best_type[0][1] and supported[-best_type[1]] or ''
+
+def desired_matches(desired, header):
+ """Takes a list of desired mime-types in the order the server prefers to
+ send them regardless of the browsers preference.
+
+ Browsers (such as Firefox) technically want XML over HTML depending on how
+ one reads the specification. This function is provided for a server to
+ declare a set of desired mime-types it supports, and returns a subset of
+ the desired list in the same order should each one be Accepted by the
+ browser.
+
+ >>> desired_matches(['text/html', 'application/xml'], \
+ ... 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png')
+ ['text/html', 'application/xml']
+ >>> desired_matches(['text/html', 'application/xml'], 'application/xml,application/json')
+ ['application/xml']
+ """
+ parsed_ranges = map(parse_media_range, header.split(','))
+ return [mimetype for mimetype in desired
+ if quality_parsed(mimetype, parsed_ranges)]
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/multidict.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/multidict.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/multidict.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,397 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import cgi
+import copy
+import sys
+from UserDict import DictMixin
+
+class MultiDict(DictMixin):
+
+ """
+ An ordered dictionary that can have multiple values for each key.
+ Adds the methods getall, getone, mixed, and add to the normal
+ dictionary interface.
+ """
+
+ def __init__(self, *args, **kw):
+ if len(args) > 1:
+ raise TypeError(
+ "MultiDict can only be called with one positional argument")
+ if args:
+ if hasattr(args[0], 'iteritems'):
+ items = list(args[0].iteritems())
+ elif hasattr(args[0], 'items'):
+ items = args[0].items()
+ else:
+ items = list(args[0])
+ self._items = items
+ else:
+ self._items = []
+ self._items.extend(kw.iteritems())
+
+ def __getitem__(self, key):
+ for k, v in self._items:
+ if k == key:
+ return v
+ raise KeyError(repr(key))
+
+ def __setitem__(self, key, value):
+ try:
+ del self[key]
+ except KeyError:
+ pass
+ self._items.append((key, value))
+
+ def add(self, key, value):
+ """
+ Add the key and value, not overwriting any previous value.
+ """
+ self._items.append((key, value))
+
+ def getall(self, key):
+ """
+ Return a list of all values matching the key (may be an empty list)
+ """
+ result = []
+ for k, v in self._items:
+ if key == k:
+ result.append(v)
+ return result
+
+ def getone(self, key):
+ """
+ Get one value matching the key, raising a KeyError if multiple
+ values were found.
+ """
+ v = self.getall(key)
+ if not v:
+ raise KeyError('Key not found: %r' % key)
+ if len(v) > 1:
+ raise KeyError('Multiple values match %r: %r' % (key, v))
+ return v[0]
+
+ def mixed(self):
+ """
+ Returns a dictionary where the values are either single
+ values, or a list of values when a key/value appears more than
+ once in this dictionary. This is similar to the kind of
+ dictionary often used to represent the variables in a web
+ request.
+ """
+ result = {}
+ multi = {}
+ for key, value in self._items:
+ if key in result:
+ # We do this to not clobber any lists that are
+ # *actual* values in this dictionary:
+ if key in multi:
+ result[key].append(value)
+ else:
+ result[key] = [result[key], value]
+ multi[key] = None
+ else:
+ result[key] = value
+ return result
+
+ def dict_of_lists(self):
+ """
+ Returns a dictionary where each key is associated with a
+ list of values.
+ """
+ result = {}
+ for key, value in self._items:
+ if key in result:
+ result[key].append(value)
+ else:
+ result[key] = [value]
+ return result
+
+ def __delitem__(self, key):
+ items = self._items
+ found = False
+ for i in range(len(items)-1, -1, -1):
+ if items[i][0] == key:
+ del items[i]
+ found = True
+ if not found:
+ raise KeyError(repr(key))
+
+ def __contains__(self, key):
+ for k, v in self._items:
+ if k == key:
+ return True
+ return False
+
+ has_key = __contains__
+
+ def clear(self):
+ self._items = []
+
+ def copy(self):
+ return MultiDict(self)
+
+ def setdefault(self, key, default=None):
+ for k, v in self._items:
+ if key == k:
+ return v
+ self._items.append((key, default))
+ return default
+
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError, "pop expected at most 2 arguments, got "\
+ + repr(1 + len(args))
+ for i in range(len(self._items)):
+ if self._items[i][0] == key:
+ v = self._items[i][1]
+ del self._items[i]
+ return v
+ if args:
+ return args[0]
+ else:
+ raise KeyError(repr(key))
+
+ def popitem(self):
+ return self._items.pop()
+
+ def update(self, other=None, **kwargs):
+ if other is None:
+ pass
+ elif hasattr(other, 'items'):
+ self._items.extend(other.items())
+ elif hasattr(other, 'keys'):
+ for k in other.keys():
+ self._items.append((k, other[k]))
+ else:
+ for k, v in other:
+ self._items.append((k, v))
+ if kwargs:
+ self.update(kwargs)
+
+ def __repr__(self):
+ items = ', '.join(['(%r, %r)' % v for v in self._items])
+ return '%s([%s])' % (self.__class__.__name__, items)
+
+ def __len__(self):
+ return len(self._items)
+
+ ##
+ ## All the iteration:
+ ##
+
+ def keys(self):
+ return [k for k, v in self._items]
+
+ def iterkeys(self):
+ for k, v in self._items:
+ yield k
+
+ __iter__ = iterkeys
+
+ def items(self):
+ return self._items[:]
+
+ def iteritems(self):
+ return iter(self._items)
+
+ def values(self):
+ return [v for k, v in self._items]
+
+ def itervalues(self):
+ for k, v in self._items:
+ yield v
+
+class UnicodeMultiDict(DictMixin):
+ """
+ A MultiDict wrapper that decodes returned values to unicode on the
+ fly. Decoding is not applied to assigned values.
+
+ The key/value contents are assumed to be ``str``/``strs`` or
+ ``str``/``FieldStorages`` (as is returned by the ``paste.request.parse_``
+ functions).
+
+ Can optionally also decode keys when the ``decode_keys`` argument is
+ True.
+
+ ``FieldStorage`` instances are cloned, and the clone's ``filename``
+ variable is decoded. Its ``name`` variable is decoded when ``decode_keys``
+ is enabled.
+
+ """
+ def __init__(self, multi=None, encoding=None, errors='strict',
+ decode_keys=False):
+ self.multi = multi
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ self.encoding = encoding
+ self.errors = errors
+ self.decode_keys = decode_keys
+
+ def _decode_key(self, key):
+ if self.decode_keys:
+ try:
+ key = key.decode(self.encoding, self.errors)
+ except AttributeError:
+ pass
+ return key
+
+ def _decode_value(self, value):
+ """
+ Decode the specified value to unicode. Assumes value is a ``str`` or
+ `FieldStorage`` object.
+
+ ``FieldStorage`` objects are specially handled.
+ """
+ if isinstance(value, cgi.FieldStorage):
+ # decode FieldStorage's field name and filename
+ value = copy.copy(value)
+ if self.decode_keys:
+ value.name = value.name.decode(self.encoding, self.errors)
+ value.filename = value.filename.decode(self.encoding, self.errors)
+ else:
+ try:
+ value = value.decode(self.encoding, self.errors)
+ except AttributeError:
+ pass
+ return value
+
+ def __getitem__(self, key):
+ return self._decode_value(self.multi.__getitem__(key))
+
+ def __setitem__(self, key, value):
+ self.multi.__setitem__(key, value)
+
+ def add(self, key, value):
+ """
+ Add the key and value, not overwriting any previous value.
+ """
+ self.multi.add(key, value)
+
+ def getall(self, key):
+ """
+ Return a list of all values matching the key (may be an empty list)
+ """
+ return [self._decode_value(v) for v in self.multi.getall(key)]
+
+ def getone(self, key):
+ """
+ Get one value matching the key, raising a KeyError if multiple
+ values were found.
+ """
+ return self._decode_value(self.multi.getone(key))
+
+ def mixed(self):
+ """
+ Returns a dictionary where the values are either single
+ values, or a list of values when a key/value appears more than
+ once in this dictionary. This is similar to the kind of
+ dictionary often used to represent the variables in a web
+ request.
+ """
+ unicode_mixed = {}
+ for key, value in self.multi.mixed().iteritems():
+ if isinstance(value, list):
+ value = [self._decode_value(value) for value in value]
+ else:
+ value = self._decode_value(value)
+ unicode_mixed[self._decode_key(key)] = value
+ return unicode_mixed
+
+ def dict_of_lists(self):
+ """
+ Returns a dictionary where each key is associated with a
+ list of values.
+ """
+ unicode_dict = {}
+ for key, value in self.multi.dict_of_lists().iteritems():
+ value = [self._decode_value(value) for value in value]
+ unicode_dict[self._decode_key(key)] = value
+ return unicode_dict
+
+ def __delitem__(self, key):
+ self.multi.__delitem__(key)
+
+ def __contains__(self, key):
+ return self.multi.__contains__(key)
+
+ has_key = __contains__
+
+ def clear(self):
+ self.multi.clear()
+
+ def copy(self):
+ return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors)
+
+ def setdefault(self, key, default=None):
+ return self._decode_value(self.multi.setdefault(key, default))
+
+ def pop(self, key, *args):
+ return self._decode_value(self.multi.pop(key, *args))
+
+ def popitem(self):
+ k, v = self.multi.popitem()
+ return (self._decode_key(k), self._decode_value(v))
+
+ def __repr__(self):
+ items = ', '.join(['(%r, %r)' % v for v in self.items()])
+ return '%s([%s])' % (self.__class__.__name__, items)
+
+ def __len__(self):
+ return self.multi.__len__()
+
+ ##
+ ## All the iteration:
+ ##
+
+ def keys(self):
+ return [self._decode_key(k) for k in self.multi.iterkeys()]
+
+ def iterkeys(self):
+ for k in self.multi.iterkeys():
+ yield self._decode_key(k)
+
+ __iter__ = iterkeys
+
+ def items(self):
+ return [(self._decode_key(k), self._decode_value(v)) for \
+ k, v in self.multi.iteritems()]
+
+ def iteritems(self):
+ for k, v in self.multi.iteritems():
+ yield (self._decode_key(k), self._decode_value(v))
+
+ def values(self):
+ return [self._decode_value(v) for v in self.multi.itervalues()]
+
+ def itervalues(self):
+ for v in self.multi.itervalues():
+ yield self._decode_value(v)
+
+__test__ = {
+ 'general': """
+ >>> d = MultiDict(a=1, b=2)
+ >>> d['a']
+ 1
+ >>> d.getall('c')
+ []
+ >>> d.add('a', 2)
+ >>> d['a']
+ 1
+ >>> d.getall('a')
+ [1, 2]
+ >>> d['b'] = 4
+ >>> d.getall('b')
+ [4]
+ >>> d.keys()
+ ['a', 'a', 'b']
+ >>> d.items()
+ [('a', 1), ('a', 2), ('b', 4)]
+ >>> d.mixed()
+ {'a': [1, 2], 'b': 4}
+ >>> MultiDict([('a', 'b')], c=2)
+ MultiDict([('a', 'b'), ('c', 2)])
+ """}
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/quoting.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/quoting.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/quoting.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,98 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+import cgi
+import htmlentitydefs
+import urllib
+import re
+
+__all__ = ['html_quote', 'html_unquote', 'url_quote', 'url_unquote',
+ 'strip_html']
+
+default_encoding = 'UTF-8'
+
+def html_quote(v, encoding=None):
+ r"""
+ Quote the value (turned to a string) as HTML. This quotes <, >,
+ and quotes:
+
+ >>> html_quote(1)
+ '1'
+ >>> html_quote(None)
+ ''
+ >>> html_quote('<hey!>')
+ '<hey!>'
+ >>> html_quote(u'\u1029')
+ '\xe1\x80\xa9'
+ """
+ encoding = encoding or default_encoding
+ if v is None:
+ return ''
+ elif isinstance(v, str):
+ return cgi.escape(v, 1)
+ elif isinstance(v, unicode):
+ return cgi.escape(v.encode(encoding), 1)
+ else:
+ return cgi.escape(unicode(v).encode(encoding), 1)
+
+_unquote_re = re.compile(r'&([a-zA-Z]+);')
+def _entity_subber(match, name2c=htmlentitydefs.name2codepoint):
+ code = name2c.get(match.group(1))
+ if code:
+ return unichr(code)
+ else:
+ return match.group(0)
+
+def html_unquote(s, encoding=None):
+ r"""
+ Decode the value.
+
+ >>> html_unquote('<hey you>')
+ u'<hey\xa0you>'
+ >>> html_unquote('')
+ u''
+ >>> html_unquote('&blahblah;')
+ u'&blahblah;'
+ >>> html_unquote('\xe1\x80\xa9')
+ u'\u1029'
+ """
+ if isinstance(s, str):
+ if s == '':
+ # workaround re.sub('', '', u'') returning '' < 2.5.2
+ # instead of u'' >= 2.5.2
+ return u''
+ s = s.decode(encoding or default_encoding)
+ return _unquote_re.sub(_entity_subber, s)
+
+def strip_html(s):
+ # should this use html_unquote?
+ s = re.sub('<.*?>', '', s)
+ s = html_unquote(s)
+ return s
+
+def no_quote(s):
+ """
+ Quoting that doesn't do anything
+ """
+ return s
+
+_comment_quote_re = re.compile(r'\-\s*\>')
+# Everything but \r, \n, \t:
+_bad_chars_re = re.compile('[\x00-\x08\x0b-\x0c\x0e-\x1f]')
+def comment_quote(s):
+ """
+ Quote that makes sure text can't escape a comment
+ """
+ comment = str(s)
+ #comment = _bad_chars_re.sub('', comment)
+ #print 'in ', repr(str(s))
+ #print 'out', repr(comment)
+ comment = _comment_quote_re.sub('->', comment)
+ return comment
+
+url_quote = urllib.quote
+url_unquote = urllib.unquote
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/scgiserver.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/scgiserver.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/scgiserver.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,171 @@
+"""
+SCGI-->WSGI application proxy, "SWAP".
+
+(Originally written by Titus Brown.)
+
+This lets an SCGI front-end like mod_scgi be used to execute WSGI
+application objects. To use it, subclass the SWAP class like so::
+
+ class TestAppHandler(swap.SWAP):
+ def __init__(self, *args, **kwargs):
+ self.prefix = '/canal'
+ self.app_obj = TestAppClass
+ swap.SWAP.__init__(self, *args, **kwargs)
+
+where 'TestAppClass' is the application object from WSGI and '/canal'
+is the prefix for what is served by the SCGI Web-server-side process.
+
+Then execute the SCGI handler "as usual" by doing something like this::
+
+ scgi_server.SCGIServer(TestAppHandler, port=4000).serve()
+
+and point mod_scgi (or whatever your SCGI front end is) at port 4000.
+
+Kudos to the WSGI folk for writing a nice PEP & the Quixote folk for
+writing a nice extensible SCGI server for Python!
+"""
+
+import sys
+import time
+from scgi import scgi_server
+
+def debug(msg):
+ timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
+ time.localtime(time.time()))
+ sys.stderr.write("[%s] %s\n" % (timestamp, msg))
+
+class SWAP(scgi_server.SCGIHandler):
+ """
+ SCGI->WSGI application proxy: let an SCGI server execute WSGI
+ application objects.
+ """
+ app_obj = None
+ prefix = None
+
+ def __init__(self, *args, **kwargs):
+ assert self.app_obj, "must set app_obj"
+ assert self.prefix is not None, "must set prefix"
+ args = (self,) + args
+ scgi_server.SCGIHandler.__init__(*args, **kwargs)
+
+ def handle_connection(self, conn):
+ """
+ Handle an individual connection.
+ """
+ input = conn.makefile("r")
+ output = conn.makefile("w")
+
+ environ = self.read_env(input)
+ environ['wsgi.input'] = input
+ environ['wsgi.errors'] = sys.stderr
+ environ['wsgi.version'] = (1, 0)
+ environ['wsgi.multithread'] = False
+ environ['wsgi.multiprocess'] = True
+ environ['wsgi.run_once'] = False
+
+ # dunno how SCGI does HTTPS signalling; can't test it myself... @CTB
+ if environ.get('HTTPS','off') in ('on','1'):
+ environ['wsgi.url_scheme'] = 'https'
+ else:
+ environ['wsgi.url_scheme'] = 'http'
+
+ ## SCGI does some weird environ manglement. We need to set
+ ## SCRIPT_NAME from 'prefix' and then set PATH_INFO from
+ ## REQUEST_URI.
+
+ prefix = self.prefix
+ path = environ['REQUEST_URI'][len(prefix):].split('?', 1)[0]
+
+ environ['SCRIPT_NAME'] = prefix
+ environ['PATH_INFO'] = path
+
+ headers_set = []
+ headers_sent = []
+ chunks = []
+ def write(data):
+ chunks.append(data)
+
+ def start_response(status, response_headers, exc_info=None):
+ if exc_info:
+ try:
+ if headers_sent:
+ # Re-raise original exception if headers sent
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ exc_info = None # avoid dangling circular ref
+ elif headers_set:
+ raise AssertionError("Headers already set!")
+
+ headers_set[:] = [status, response_headers]
+ return write
+
+ ###
+
+ result = self.app_obj(environ, start_response)
+ try:
+ for data in result:
+ chunks.append(data)
+
+ # Before the first output, send the stored headers
+ if not headers_set:
+ # Error -- the app never called start_response
+ status = '500 Server Error'
+ response_headers = [('Content-type', 'text/html')]
+ chunks = ["XXX start_response never called"]
+ else:
+ status, response_headers = headers_sent[:] = headers_set
+
+ output.write('Status: %s\r\n' % status)
+ for header in response_headers:
+ output.write('%s: %s\r\n' % header)
+ output.write('\r\n')
+
+ for data in chunks:
+ output.write(data)
+ finally:
+ if hasattr(result,'close'):
+ result.close()
+
+ # SCGI backends use connection closing to signal 'fini'.
+ try:
+ input.close()
+ output.close()
+ conn.close()
+ except IOError, err:
+ debug("IOError while closing connection ignored: %s" % err)
+
+
+def serve_application(application, prefix, port=None, host=None, max_children=None):
+ """
+ Serve the specified WSGI application via SCGI proxy.
+
+ ``application``
+ The WSGI application to serve.
+
+ ``prefix``
+ The prefix for what is served by the SCGI Web-server-side process.
+
+ ``port``
+ Optional port to bind the SCGI proxy to. Defaults to SCGIServer's
+ default port value.
+
+ ``host``
+ Optional host to bind the SCGI proxy to. Defaults to SCGIServer's
+ default host value.
+
+ ``host``
+ Optional maximum number of child processes the SCGIServer will
+ spawn. Defaults to SCGIServer's default max_children value.
+ """
+ class SCGIAppHandler(SWAP):
+ def __init__ (self, *args, **kwargs):
+ self.prefix = prefix
+ self.app_obj = application
+ SWAP.__init__(self, *args, **kwargs)
+
+ kwargs = dict(handler_class=SCGIAppHandler)
+ for kwarg in ('host', 'port', 'max_children'):
+ if locals()[kwarg] is not None:
+ kwargs[kwarg] = locals()[kwarg]
+
+ scgi_server.SCGIServer(**kwargs).serve()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/string24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/string24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/string24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,531 @@
+"""A collection of string operations (most are no longer used).
+
+Warning: most of the code you see here isn't normally used nowadays.
+Beginning with Python 1.6, many of these functions are implemented as
+methods on the standard string object. They used to be implemented by
+a built-in module called strop, but strop is now obsolete itself.
+
+Public module variables:
+
+whitespace -- a string containing all characters considered whitespace
+lowercase -- a string containing all characters considered lowercase letters
+uppercase -- a string containing all characters considered uppercase letters
+letters -- a string containing all characters considered letters
+digits -- a string containing all characters considered decimal digits
+hexdigits -- a string containing all characters considered hexadecimal digits
+octdigits -- a string containing all characters considered octal digits
+punctuation -- a string containing all characters considered punctuation
+printable -- a string containing all characters considered printable
+
+"""
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n\r\v\f'
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+letters = lowercase + uppercase
+ascii_lowercase = lowercase
+ascii_uppercase = uppercase
+ascii_letters = ascii_lowercase + ascii_uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+printable = digits + letters + punctuation + whitespace
+
+# Case conversion helpers
+# Use str to convert Unicode literal in case of -U
+# Note that Cookie.py bogusly uses _idmap :(
+l = map(chr, xrange(256))
+_idmap = str('').join(l)
+del l
+
+# Functions which aren't available as string methods.
+
+# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
+# See also regsub.capwords().
+def capwords(s, sep=None):
+ """capwords(s, [sep]) -> string
+
+ Split the argument into words using split, capitalize each
+ word using capitalize, and join the capitalized words using
+ join. Note that this replaces runs of whitespace characters by
+ a single space.
+
+ """
+ return (sep or ' ').join([x.capitalize() for x in s.split(sep)])
+
+
+# Construct a translation string
+_idmapL = None
+def maketrans(fromstr, tostr):
+ """maketrans(frm, to) -> string
+
+ Return a translation table (a string of 256 bytes long)
+ suitable for use in string.translate. The strings frm and to
+ must be of the same length.
+
+ """
+ if len(fromstr) != len(tostr):
+ raise ValueError, "maketrans arguments must have same length"
+ global _idmapL
+ if not _idmapL:
+ _idmapL = map(None, _idmap)
+ L = _idmapL[:]
+ fromstr = map(ord, fromstr)
+ for i in range(len(fromstr)):
+ L[fromstr[i]] = tostr[i]
+ return ''.join(L)
+
+
+
+####################################################################
+import re as _re
+
+class _multimap:
+ """Helper class for combining multiple mappings.
+
+ Used by .{safe_,}substitute() to combine the mapping and keyword
+ arguments.
+ """
+ def __init__(self, primary, secondary):
+ self._primary = primary
+ self._secondary = secondary
+
+ def __getitem__(self, key):
+ try:
+ return self._primary[key]
+ except KeyError:
+ return self._secondary[key]
+
+
+class _TemplateMetaclass(type):
+ pattern = r"""
+ %(delim)s(?:
+ (?P<escaped>%(delim)s) | # Escape sequence of two delimiters
+ (?P<named>%(id)s) | # delimiter and a Python identifier
+ {(?P<braced>%(id)s)} | # delimiter and a braced identifier
+ (?P<invalid>) # Other ill-formed delimiter exprs
+ )
+ """
+
+ def __init__(cls, name, bases, dct):
+ super(_TemplateMetaclass, cls).__init__(name, bases, dct)
+ if 'pattern' in dct:
+ pattern = cls.pattern
+ else:
+ pattern = _TemplateMetaclass.pattern % {
+ 'delim' : _re.escape(cls.delimiter),
+ 'id' : cls.idpattern,
+ }
+ cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
+
+
+class Template:
+ """A string class for supporting $-substitutions."""
+ __metaclass__ = _TemplateMetaclass
+
+ delimiter = '$'
+ idpattern = r'[_a-z][_a-z0-9]*'
+
+ def __init__(self, template):
+ self.template = template
+
+ # Search for $$, $identifier, ${identifier}, and any bare $'s
+
+ def _invalid(self, mo):
+ i = mo.start('invalid')
+ lines = self.template[:i].splitlines(True)
+ if not lines:
+ colno = 1
+ lineno = 1
+ else:
+ colno = i - len(''.join(lines[:-1]))
+ lineno = len(lines)
+ raise ValueError('Invalid placeholder in string: line %d, col %d' %
+ (lineno, colno))
+
+ def substitute(self, *args, **kws):
+ if len(args) > 1:
+ raise TypeError('Too many positional arguments')
+ if not args:
+ mapping = kws
+ elif kws:
+ mapping = _multimap(kws, args[0])
+ else:
+ mapping = args[0]
+ # Helper function for .sub()
+ def convert(mo):
+ # Check the most common path first.
+ named = mo.group('named') or mo.group('braced')
+ if named is not None:
+ val = mapping[named]
+ # We use this idiom instead of str() because the latter will
+ # fail if val is a Unicode containing non-ASCII characters.
+ return '%s' % val
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ self._invalid(mo)
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+ def safe_substitute(self, *args, **kws):
+ if len(args) > 1:
+ raise TypeError('Too many positional arguments')
+ if not args:
+ mapping = kws
+ elif kws:
+ mapping = _multimap(kws, args[0])
+ else:
+ mapping = args[0]
+ # Helper function for .sub()
+ def convert(mo):
+ named = mo.group('named')
+ if named is not None:
+ try:
+ # We use this idiom instead of str() because the latter
+ # will fail if val is a Unicode containing non-ASCII
+ return '%s' % mapping[named]
+ except KeyError:
+ return self.delimiter + named
+ braced = mo.group('braced')
+ if braced is not None:
+ try:
+ return '%s' % mapping[braced]
+ except KeyError:
+ return self.delimiter + '{' + braced + '}'
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ return self.delimiter
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+
+
+####################################################################
+# NOTE: Everything below here is deprecated. Use string methods instead.
+# This stuff will go away in Python 3.0.
+
+# Backward compatible names for exceptions
+index_error = ValueError
+atoi_error = ValueError
+atof_error = ValueError
+atol_error = ValueError
+
+# convert UPPER CASE letters to lower case
+def lower(s):
+ """lower(s) -> string
+
+ Return a copy of the string s converted to lowercase.
+
+ """
+ return s.lower()
+
+# Convert lower case letters to UPPER CASE
+def upper(s):
+ """upper(s) -> string
+
+ Return a copy of the string s converted to uppercase.
+
+ """
+ return s.upper()
+
+# Swap lower case letters and UPPER CASE
+def swapcase(s):
+ """swapcase(s) -> string
+
+ Return a copy of the string s with upper case characters
+ converted to lowercase and vice versa.
+
+ """
+ return s.swapcase()
+
+# Strip leading and trailing tabs and spaces
+def strip(s, chars=None):
+ """strip(s [,chars]) -> string
+
+ Return a copy of the string s with leading and trailing
+ whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+ If chars is unicode, S will be converted to unicode before stripping.
+
+ """
+ return s.strip(chars)
+
+# Strip leading tabs and spaces
+def lstrip(s, chars=None):
+ """lstrip(s [,chars]) -> string
+
+ Return a copy of the string s with leading whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+
+ """
+ return s.lstrip(chars)
+
+# Strip trailing tabs and spaces
+def rstrip(s, chars=None):
+ """rstrip(s [,chars]) -> string
+
+ Return a copy of the string s with trailing whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+
+ """
+ return s.rstrip(chars)
+
+
+# Split a string into a list of space/tab-separated words
+def split(s, sep=None, maxsplit=-1):
+ """split(s [,sep [,maxsplit]]) -> list of strings
+
+ Return a list of the words in the string s, using sep as the
+ delimiter string. If maxsplit is given, splits at no more than
+ maxsplit places (resulting in at most maxsplit+1 words). If sep
+ is not specified or is None, any whitespace string is a separator.
+
+ (split and splitfields are synonymous)
+
+ """
+ return s.split(sep, maxsplit)
+splitfields = split
+
+# Split a string into a list of space/tab-separated words
+def rsplit(s, sep=None, maxsplit=-1):
+ """rsplit(s [,sep [,maxsplit]]) -> list of strings
+
+ Return a list of the words in the string s, using sep as the
+ delimiter string, starting at the end of the string and working
+ to the front. If maxsplit is given, at most maxsplit splits are
+ done. If sep is not specified or is None, any whitespace string
+ is a separator.
+ """
+ return s.rsplit(sep, maxsplit)
+
+# Join fields with optional separator
+def join(words, sep = ' '):
+ """join(list [,sep]) -> string
+
+ Return a string composed of the words in list, with
+ intervening occurrences of sep. The default separator is a
+ single space.
+
+ (joinfields and join are synonymous)
+
+ """
+ return sep.join(words)
+joinfields = join
+
+# Find substring, raise exception if not found
+def index(s, *args):
+ """index(s, sub [,start [,end]]) -> int
+
+ Like find but raises ValueError when the substring is not found.
+
+ """
+ return s.index(*args)
+
+# Find last substring, raise exception if not found
+def rindex(s, *args):
+ """rindex(s, sub [,start [,end]]) -> int
+
+ Like rfind but raises ValueError when the substring is not found.
+
+ """
+ return s.rindex(*args)
+
+# Count non-overlapping occurrences of substring
+def count(s, *args):
+ """count(s, sub[, start[,end]]) -> int
+
+ Return the number of occurrences of substring sub in string
+ s[start:end]. Optional arguments start and end are
+ interpreted as in slice notation.
+
+ """
+ return s.count(*args)
+
+# Find substring, return -1 if not found
+def find(s, *args):
+ """find(s, sub [,start [,end]]) -> in
+
+ Return the lowest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return s.find(*args)
+
+# Find last substring, return -1 if not found
+def rfind(s, *args):
+ """rfind(s, sub [,start [,end]]) -> int
+
+ Return the highest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return s.rfind(*args)
+
+# for a bit of speed
+_float = float
+_int = int
+_long = long
+
+# Convert string to float
+def atof(s):
+ """atof(s) -> float
+
+ Return the floating point number represented by the string s.
+
+ """
+ return _float(s)
+
+
+# Convert string to integer
+def atoi(s , base=10):
+ """atoi(s [,base]) -> int
+
+ Return the integer represented by the string s in the given
+ base, which defaults to 10. The string s must consist of one
+ or more digits, possibly preceded by a sign. If base is 0, it
+ is chosen from the leading characters of s, 0 for octal, 0x or
+ 0X for hexadecimal. If base is 16, a preceding 0x or 0X is
+ accepted.
+
+ """
+ return _int(s, base)
+
+
+# Convert string to long integer
+def atol(s, base=10):
+ """atol(s [,base]) -> long
+
+ Return the long integer represented by the string s in the
+ given base, which defaults to 10. The string s must consist
+ of one or more digits, possibly preceded by a sign. If base
+ is 0, it is chosen from the leading characters of s, 0 for
+ octal, 0x or 0X for hexadecimal. If base is 16, a preceding
+ 0x or 0X is accepted. A trailing L or l is not accepted,
+ unless base is 0.
+
+ """
+ return _long(s, base)
+
+
+# Left-justify a string
+def ljust(s, width, *args):
+ """ljust(s, width[, fillchar]) -> string
+
+ Return a left-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.ljust(width, *args)
+
+# Right-justify a string
+def rjust(s, width, *args):
+ """rjust(s, width[, fillchar]) -> string
+
+ Return a right-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.rjust(width, *args)
+
+# Center a string
+def center(s, width, *args):
+ """center(s, width[, fillchar]) -> string
+
+ Return a center version of s, in a field of the specified
+ width. padded with spaces as needed. The string is never
+ truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.center(width, *args)
+
+# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
+# Decadent feature: the argument may be a string or a number
+# (Use of this is deprecated; it should be a string as with ljust c.s.)
+def zfill(x, width):
+ """zfill(x, width) -> string
+
+ Pad a numeric string x with zeros on the left, to fill a field
+ of the specified width. The string x is never truncated.
+
+ """
+ if not isinstance(x, basestring):
+ x = repr(x)
+ return x.zfill(width)
+
+# Expand tabs in a string.
+# Doesn't take non-printing chars into account, but does understand \n.
+def expandtabs(s, tabsize=8):
+ """expandtabs(s [,tabsize]) -> string
+
+ Return a copy of the string s with all tab characters replaced
+ by the appropriate number of spaces, depending on the current
+ column, and the tabsize (default 8).
+
+ """
+ return s.expandtabs(tabsize)
+
+# Character translation through look-up table.
+def translate(s, table, deletions=""):
+ """translate(s,table [,deletions]) -> string
+
+ Return a copy of the string s, where all characters occurring
+ in the optional argument deletions are removed, and the
+ remaining characters have been mapped through the given
+ translation table, which must be a string of length 256. The
+ deletions argument is not allowed for Unicode strings.
+
+ """
+ if deletions:
+ return s.translate(table, deletions)
+ else:
+ # Add s[:0] so that if s is Unicode and table is an 8-bit string,
+ # table is converted to Unicode. This means that table *cannot*
+ # be a dictionary -- for that feature, use u.translate() directly.
+ return s.translate(table + s[:0])
+
+# Capitalize a string, e.g. "aBc dEf" -> "Abc def".
+def capitalize(s):
+ """capitalize(s) -> string
+
+ Return a copy of the string s with only its first character
+ capitalized.
+
+ """
+ return s.capitalize()
+
+# Substring replacement (global)
+def replace(s, old, new, maxsplit=-1):
+ """replace (str, old, new[, maxsplit]) -> string
+
+ Return a copy of string str with all occurrences of substring
+ old replaced by new. If the optional argument maxsplit is
+ given, only the first maxsplit occurrences are replaced.
+
+ """
+ return s.replace(old, new, maxsplit)
+
+
+# Try importing optional built-in module "strop" -- if it exists,
+# it redefines some string operations that are 100-1000 times faster.
+# It also defines values for whitespace, lowercase and uppercase
+# that match <ctype.h>'s definitions.
+
+try:
+ from strop import maketrans, lowercase, uppercase, whitespace
+ letters = lowercase + uppercase
+except ImportError:
+ pass # Use the original versions
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/subprocess24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/subprocess24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/subprocess24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1152 @@
+# subprocess - Subprocesses with accessible I/O streams
+#
+# For more information about this module, see PEP 324.
+#
+# This module should remain compatible with Python 2.2, see PEP 291.
+#
+# Copyright (c) 2003-2005 by Peter Astrand <astrand at lysator.liu.se>
+#
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/2.4/license for licensing details.
+
+r"""subprocess - Subprocesses with accessible I/O streams
+
+This module allows you to spawn processes, connect to their
+input/output/error pipes, and obtain their return codes. This module
+intends to replace several other, older modules and functions, like:
+
+os.system
+os.spawn*
+os.popen*
+popen2.*
+commands.*
+
+Information about how the subprocess module can be used to replace these
+modules and functions can be found below.
+
+
+
+Using the subprocess module
+===========================
+This module defines one class called Popen:
+
+class Popen(args, bufsize=0, executable=None,
+ stdin=None, stdout=None, stderr=None,
+ preexec_fn=None, close_fds=False, shell=False,
+ cwd=None, env=None, universal_newlines=False,
+ startupinfo=None, creationflags=0):
+
+
+Arguments are:
+
+args should be a string, or a sequence of program arguments. The
+program to execute is normally the first item in the args sequence or
+string, but can be explicitly set by using the executable argument.
+
+On UNIX, with shell=False (default): In this case, the Popen class
+uses os.execvp() to execute the child program. args should normally
+be a sequence. A string will be treated as a sequence with the string
+as the only item (the program to execute).
+
+On UNIX, with shell=True: If args is a string, it specifies the
+command string to execute through the shell. If args is a sequence,
+the first item specifies the command string, and any additional items
+will be treated as additional shell arguments.
+
+On Windows: the Popen class uses CreateProcess() to execute the child
+program, which operates on strings. If args is a sequence, it will be
+converted to a string using the list2cmdline method. Please note that
+not all MS Windows applications interpret the command line the same
+way: The list2cmdline is designed for applications using the same
+rules as the MS C runtime.
+
+bufsize, if given, has the same meaning as the corresponding argument
+to the built-in open() function: 0 means unbuffered, 1 means line
+buffered, any other positive value means use a buffer of
+(approximately) that size. A negative bufsize means to use the system
+default, which usually means fully buffered. The default value for
+bufsize is 0 (unbuffered).
+
+stdin, stdout and stderr specify the executed programs' standard
+input, standard output and standard error file handles, respectively.
+Valid values are PIPE, an existing file descriptor (a positive
+integer), an existing file object, and None. PIPE indicates that a
+new pipe to the child should be created. With None, no redirection
+will occur; the child's file handles will be inherited from the
+parent. Additionally, stderr can be STDOUT, which indicates that the
+stderr data from the applications should be captured into the same
+file handle as for stdout.
+
+If preexec_fn is set to a callable object, this object will be called
+in the child process just before the child is executed.
+
+If close_fds is true, all file descriptors except 0, 1 and 2 will be
+closed before the child process is executed.
+
+if shell is true, the specified command will be executed through the
+shell.
+
+If cwd is not None, the current directory will be changed to cwd
+before the child is executed.
+
+If env is not None, it defines the environment variables for the new
+process.
+
+If universal_newlines is true, the file objects stdout and stderr are
+opened as a text files, but lines may be terminated by any of '\n',
+the Unix end-of-line convention, '\r', the Macintosh convention or
+'\r\n', the Windows convention. All of these external representations
+are seen as '\n' by the Python program. Note: This feature is only
+available if Python is built with universal newline support (the
+default). Also, the newlines attribute of the file objects stdout,
+stdin and stderr are not updated by the communicate() method.
+
+The startupinfo and creationflags, if given, will be passed to the
+underlying CreateProcess() function. They can specify things such as
+appearance of the main window and priority for the new process.
+(Windows only)
+
+
+This module also defines two shortcut functions:
+
+call(*args, **kwargs):
+ Run command with arguments. Wait for command to complete, then
+ return the returncode attribute. The arguments are the same as for
+ the Popen constructor. Example:
+
+ retcode = call(["ls", "-l"])
+
+
+Exceptions
+----------
+Exceptions raised in the child process, before the new program has
+started to execute, will be re-raised in the parent. Additionally,
+the exception object will have one extra attribute called
+'child_traceback', which is a string containing traceback information
+from the childs point of view.
+
+The most common exception raised is OSError. This occurs, for
+example, when trying to execute a non-existent file. Applications
+should prepare for OSErrors.
+
+A ValueError will be raised if Popen is called with invalid arguments.
+
+
+Security
+--------
+Unlike some other popen functions, this implementation will never call
+/bin/sh implicitly. This means that all characters, including shell
+metacharacters, can safely be passed to child processes.
+
+
+Popen objects
+=============
+Instances of the Popen class have the following methods:
+
+poll()
+ Check if child process has terminated. Returns returncode
+ attribute.
+
+wait()
+ Wait for child process to terminate. Returns returncode attribute.
+
+communicate(input=None)
+ Interact with process: Send data to stdin. Read data from stdout
+ and stderr, until end-of-file is reached. Wait for process to
+ terminate. The optional stdin argument should be a string to be
+ sent to the child process, or None, if no data should be sent to
+ the child.
+
+ communicate() returns a tuple (stdout, stderr).
+
+ Note: The data read is buffered in memory, so do not use this
+ method if the data size is large or unlimited.
+
+The following attributes are also available:
+
+stdin
+ If the stdin argument is PIPE, this attribute is a file object
+ that provides input to the child process. Otherwise, it is None.
+
+stdout
+ If the stdout argument is PIPE, this attribute is a file object
+ that provides output from the child process. Otherwise, it is
+ None.
+
+stderr
+ If the stderr argument is PIPE, this attribute is file object that
+ provides error output from the child process. Otherwise, it is
+ None.
+
+pid
+ The process ID of the child process.
+
+returncode
+ The child return code. A None value indicates that the process
+ hasn't terminated yet. A negative value -N indicates that the
+ child was terminated by signal N (UNIX only).
+
+
+Replacing older functions with the subprocess module
+====================================================
+In this section, "a ==> b" means that b can be used as a replacement
+for a.
+
+Note: All functions in this section fail (more or less) silently if
+the executed program cannot be found; this module raises an OSError
+exception.
+
+In the following examples, we assume that the subprocess module is
+imported with "from subprocess import *".
+
+
+Replacing /bin/sh shell backquote
+---------------------------------
+output=`mycmd myarg`
+==>
+output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
+
+
+Replacing shell pipe line
+-------------------------
+output=`dmesg | grep hda`
+==>
+p1 = Popen(["dmesg"], stdout=PIPE)
+p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+output = p2.communicate()[0]
+
+
+Replacing os.system()
+---------------------
+sts = os.system("mycmd" + " myarg")
+==>
+p = Popen("mycmd" + " myarg", shell=True)
+sts = os.waitpid(p.pid, 0)
+
+Note:
+
+* Calling the program through the shell is usually not required.
+
+* It's easier to look at the returncode attribute than the
+ exitstatus.
+
+A more real-world example would look like this:
+
+try:
+ retcode = call("mycmd" + " myarg", shell=True)
+ if retcode < 0:
+ print >>sys.stderr, "Child was terminated by signal", -retcode
+ else:
+ print >>sys.stderr, "Child returned", retcode
+except OSError, e:
+ print >>sys.stderr, "Execution failed:", e
+
+
+Replacing os.spawn*
+-------------------
+P_NOWAIT example:
+
+pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+pid = Popen(["/bin/mycmd", "myarg"]).pid
+
+
+P_WAIT example:
+
+retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+retcode = call(["/bin/mycmd", "myarg"])
+
+
+Vector example:
+
+os.spawnvp(os.P_NOWAIT, path, args)
+==>
+Popen([path] + args[1:])
+
+
+Environment example:
+
+os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
+==>
+Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
+
+
+Replacing os.popen*
+-------------------
+pipe = os.popen(cmd, mode='r', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
+
+pipe = os.popen(cmd, mode='w', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
+
+
+(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdin, child_stdout) = (p.stdin, p.stdout)
+
+
+(child_stdin,
+ child_stdout,
+ child_stderr) = os.popen3(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
+(child_stdin,
+ child_stdout,
+ child_stderr) = (p.stdin, p.stdout, p.stderr)
+
+
+(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
+
+
+Replacing popen2.*
+------------------
+Note: If the cmd argument to popen2 functions is a string, the command
+is executed through /bin/sh. If it is a list, the command is directly
+executed.
+
+(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
+==>
+p = Popen(["somestring"], shell=True, bufsize=bufsize
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+
+(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
+==>
+p = Popen(["mycmd", "myarg"], bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
+except that:
+
+* subprocess.Popen raises an exception if the execution fails
+* the capturestderr argument is replaced with the stderr argument.
+* stdin=PIPE and stdout=PIPE must be specified.
+* popen2 closes all filedescriptors by default, but you have to specify
+ close_fds=True with subprocess.Popen.
+
+
+"""
+
+import sys
+mswindows = (sys.platform == "win32")
+
+import os
+import types
+import traceback
+
+if mswindows:
+ import threading
+ import msvcrt
+ ## @@: Changed in Paste
+ ## Since this module is only used on pre-python-2.4 systems, they probably
+ ## don't have _subprocess installed, but hopefully have the win32 stuff
+ ## installed.
+ if 1: # <-- change this to use pywin32 instead of the _subprocess driver
+ import pywintypes
+ from win32api import GetStdHandle, STD_INPUT_HANDLE, \
+ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
+ from win32api import GetCurrentProcess, DuplicateHandle, \
+ GetModuleFileName, GetVersion
+ from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE
+ from win32pipe import CreatePipe
+ from win32process import CreateProcess, STARTUPINFO, \
+ GetExitCodeProcess, STARTF_USESTDHANDLES, \
+ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
+ from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
+ else:
+ from _subprocess import *
+ class STARTUPINFO:
+ dwFlags = 0
+ hStdInput = None
+ hStdOutput = None
+ hStdError = None
+ class pywintypes:
+ error = IOError
+else:
+ import select
+ import errno
+ import fcntl
+ import pickle
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call"]
+
+try:
+ MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+ MAXFD = 256
+
+# True/False does not exist on 2.2.0
+try:
+ False
+except NameError:
+ False = 0
+ True = 1
+
+_active = []
+
+def _cleanup():
+ for inst in _active[:]:
+ inst.poll()
+
+PIPE = -1
+STDOUT = -2
+
+
+def call(*args, **kwargs):
+ """Run command with arguments. Wait for command to complete, then
+ return the returncode attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ retcode = call(["ls", "-l"])
+ """
+ return Popen(*args, **kwargs).wait()
+
+
+def list2cmdline(seq):
+ """
+ Translate a sequence of arguments into a command line
+ string, using the same rules as the MS C runtime:
+
+ 1) Arguments are delimited by white space, which is either a
+ space or a tab.
+
+ 2) A string surrounded by double quotation marks is
+ interpreted as a single argument, regardless of white space
+ contained within. A quoted string can be embedded in an
+ argument.
+
+ 3) A double quotation mark preceded by a backslash is
+ interpreted as a literal double quotation mark.
+
+ 4) Backslashes are interpreted literally, unless they
+ immediately precede a double quotation mark.
+
+ 5) If backslashes immediately precede a double quotation mark,
+ every pair of backslashes is interpreted as a literal
+ backslash. If the number of backslashes is odd, the last
+ backslash escapes the next double quotation mark as
+ described in rule 3.
+ """
+
+ # See
+ # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
+ result = []
+ needquote = False
+ for arg in seq:
+ bs_buf = []
+
+ # Add a space to separate this argument from the others
+ if result:
+ result.append(' ')
+
+ needquote = (" " in arg) or ("\t" in arg)
+ if needquote:
+ result.append('"')
+
+ for c in arg:
+ if c == '\\':
+ # Don't know if we need to double yet.
+ bs_buf.append(c)
+ elif c == '"':
+ # Double backspaces.
+ result.append('\\' * len(bs_buf)*2)
+ bs_buf = []
+ result.append('\\"')
+ else:
+ # Normal char
+ if bs_buf:
+ result.extend(bs_buf)
+ bs_buf = []
+ result.append(c)
+
+ # Add remaining backspaces, if any.
+ if bs_buf:
+ result.extend(bs_buf)
+
+ if needquote:
+ result.extend(bs_buf)
+ result.append('"')
+
+ return ''.join(result)
+
+
+class Popen(object):
+ def __init__(self, args, bufsize=0, executable=None,
+ stdin=None, stdout=None, stderr=None,
+ preexec_fn=None, close_fds=False, shell=False,
+ cwd=None, env=None, universal_newlines=False,
+ startupinfo=None, creationflags=0):
+ """Create new Popen instance."""
+ _cleanup()
+
+ if not isinstance(bufsize, (int, long)):
+ raise TypeError("bufsize must be an integer")
+
+ if mswindows:
+ if preexec_fn is not None:
+ raise ValueError("preexec_fn is not supported on Windows "
+ "platforms")
+ if close_fds:
+ raise ValueError("close_fds is not supported on Windows "
+ "platforms")
+ else:
+ # POSIX
+ if startupinfo is not None:
+ raise ValueError("startupinfo is only supported on Windows "
+ "platforms")
+ if creationflags != 0:
+ raise ValueError("creationflags is only supported on Windows "
+ "platforms")
+
+ self.stdin = None
+ self.stdout = None
+ self.stderr = None
+ self.pid = None
+ self.returncode = None
+ self.universal_newlines = universal_newlines
+
+ # Input and output objects. The general principle is like
+ # this:
+ #
+ # Parent Child
+ # ------ -----
+ # p2cwrite ---stdin---> p2cread
+ # c2pread <--stdout--- c2pwrite
+ # errread <--stderr--- errwrite
+ #
+ # On POSIX, the child objects are file descriptors. On
+ # Windows, these are Windows file handles. The parent objects
+ # are file descriptors on both platforms. The parent objects
+ # are None when not using PIPEs. The child objects are None
+ # when not redirecting.
+
+ (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+ self._execute_child(args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+ if p2cwrite:
+ self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
+ if c2pread:
+ if universal_newlines:
+ self.stdout = os.fdopen(c2pread, 'rU', bufsize)
+ else:
+ self.stdout = os.fdopen(c2pread, 'rb', bufsize)
+ if errread:
+ if universal_newlines:
+ self.stderr = os.fdopen(errread, 'rU', bufsize)
+ else:
+ self.stderr = os.fdopen(errread, 'rb', bufsize)
+
+ _active.append(self)
+
+
+ def _translate_newlines(self, data):
+ data = data.replace("\r\n", "\n")
+ data = data.replace("\r", "\n")
+ return data
+
+
+ if mswindows:
+ #
+ # Windows methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tupel with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ if stdin == None and stdout == None and stderr == None:
+ return (None, None, None, None, None, None)
+
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+ errread, errwrite = None, None
+
+ if stdin == None:
+ p2cread = GetStdHandle(STD_INPUT_HANDLE)
+ elif stdin == PIPE:
+ p2cread, p2cwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ p2cwrite = p2cwrite.Detach()
+ p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+ elif type(stdin) == types.IntType:
+ p2cread = msvcrt.get_osfhandle(stdin)
+ else:
+ # Assuming file-like object
+ p2cread = msvcrt.get_osfhandle(stdin.fileno())
+ p2cread = self._make_inheritable(p2cread)
+
+ if stdout == None:
+ c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
+ elif stdout == PIPE:
+ c2pread, c2pwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ c2pread = c2pread.Detach()
+ c2pread = msvcrt.open_osfhandle(c2pread, 0)
+ elif type(stdout) == types.IntType:
+ c2pwrite = msvcrt.get_osfhandle(stdout)
+ else:
+ # Assuming file-like object
+ c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+ c2pwrite = self._make_inheritable(c2pwrite)
+
+ if stderr == None:
+ errwrite = GetStdHandle(STD_ERROR_HANDLE)
+ elif stderr == PIPE:
+ errread, errwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ errread = errread.Detach()
+ errread = msvcrt.open_osfhandle(errread, 0)
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif type(stderr) == types.IntType:
+ errwrite = msvcrt.get_osfhandle(stderr)
+ else:
+ # Assuming file-like object
+ errwrite = msvcrt.get_osfhandle(stderr.fileno())
+ errwrite = self._make_inheritable(errwrite)
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _make_inheritable(self, handle):
+ """Return a duplicate of handle, which is inheritable"""
+ return DuplicateHandle(GetCurrentProcess(), handle,
+ GetCurrentProcess(), 0, 1,
+ DUPLICATE_SAME_ACCESS)
+
+
+ def _find_w9xpopen(self):
+ """Find and return absolut path to w9xpopen.exe"""
+ w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
+ "w9xpopen.exe")
+ if not os.path.exists(w9xpopen):
+ # Eeek - file-not-found - possibly an embedding
+ # situation - see if we can locate it in sys.exec_prefix
+ w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
+ "w9xpopen.exe")
+ if not os.path.exists(w9xpopen):
+ raise RuntimeError("Cannot locate w9xpopen.exe, which is "
+ "needed for Popen to work with your "
+ "shell or platform.")
+ return w9xpopen
+
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ """Execute program (MS Windows version)"""
+
+ if not isinstance(args, types.StringTypes):
+ args = list2cmdline(args)
+
+ # Process startup details
+ default_startupinfo = STARTUPINFO()
+ if startupinfo == None:
+ startupinfo = default_startupinfo
+ if not None in (p2cread, c2pwrite, errwrite):
+ startupinfo.dwFlags |= STARTF_USESTDHANDLES
+ startupinfo.hStdInput = p2cread
+ startupinfo.hStdOutput = c2pwrite
+ startupinfo.hStdError = errwrite
+
+ if shell:
+ default_startupinfo.dwFlags |= STARTF_USESHOWWINDOW
+ default_startupinfo.wShowWindow = SW_HIDE
+ comspec = os.environ.get("COMSPEC", "cmd.exe")
+ args = comspec + " /c " + args
+ if (GetVersion() >= 0x80000000L or
+ os.path.basename(comspec).lower() == "command.com"):
+ # Win9x, or using command.com on NT. We need to
+ # use the w9xpopen intermediate program. For more
+ # information, see KB Q150956
+ # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
+ w9xpopen = self._find_w9xpopen()
+ args = '"%s" %s' % (w9xpopen, args)
+ # Not passing CREATE_NEW_CONSOLE has been known to
+ # cause random failures on win9x. Specifically a
+ # dialog: "Your program accessed mem currently in
+ # use at xxx" and a hopeful warning about the
+ # stability of your system. Cost is Ctrl+C wont
+ # kill children.
+ creationflags |= CREATE_NEW_CONSOLE
+
+ # Start the process
+ try:
+ hp, ht, pid, tid = CreateProcess(executable, args,
+ # no special security
+ None, None,
+ # must inherit handles to pass std
+ # handles
+ 1,
+ creationflags,
+ env,
+ cwd,
+ startupinfo)
+ except pywintypes.error, e:
+ # Translate pywintypes.error to WindowsError, which is
+ # a subclass of OSError. FIXME: We should really
+ # translate errno using _sys_errlist (or simliar), but
+ # how can this be done from Python?
+ raise WindowsError(*e.args)
+
+ # Retain the process handle, but close the thread handle
+ self._handle = hp
+ self.pid = pid
+ ht.Close()
+
+ # Child is launched. Close the parent's copy of those pipe
+ # handles that only the child should have open. You need
+ # to make sure that no handles to the write end of the
+ # output pipe are maintained in this process or else the
+ # pipe will not close when the child process exits and the
+ # ReadFile will hang.
+ if p2cread != None:
+ p2cread.Close()
+ if c2pwrite != None:
+ c2pwrite.Close()
+ if errwrite != None:
+ errwrite.Close()
+
+
+ def poll(self):
+ """Check if child process has terminated. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
+ self.returncode = GetExitCodeProcess(self._handle)
+ _active.remove(self)
+ return self.returncode
+
+
+ def wait(self):
+ """Wait for child process to terminate. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ obj = WaitForSingleObject(self._handle, INFINITE)
+ self.returncode = GetExitCodeProcess(self._handle)
+ _active.remove(self)
+ return self.returncode
+
+
+ def _readerthread(self, fh, buffer):
+ buffer.append(fh.read())
+
+
+ def communicate(self, input=None):
+ """Interact with process: Send data to stdin. Read data from
+ stdout and stderr, until end-of-file is reached. Wait for
+ process to terminate. The optional input argument should be a
+ string to be sent to the child process, or None, if no data
+ should be sent to the child.
+
+ communicate() returns a tuple (stdout, stderr)."""
+ stdout = None # Return
+ stderr = None # Return
+
+ if self.stdout:
+ stdout = []
+ stdout_thread = threading.Thread(target=self._readerthread,
+ args=(self.stdout, stdout))
+ stdout_thread.setDaemon(True)
+ stdout_thread.start()
+ if self.stderr:
+ stderr = []
+ stderr_thread = threading.Thread(target=self._readerthread,
+ args=(self.stderr, stderr))
+ stderr_thread.setDaemon(True)
+ stderr_thread.start()
+
+ if self.stdin:
+ if input != None:
+ self.stdin.write(input)
+ self.stdin.close()
+
+ if self.stdout:
+ stdout_thread.join()
+ if self.stderr:
+ stderr_thread.join()
+
+ # All data exchanged. Translate lists into strings.
+ if stdout != None:
+ stdout = stdout[0]
+ if stderr != None:
+ stderr = stderr[0]
+
+ # Translate newlines, if requested. We cannot let the file
+ # object do the translation: It is based on stdio, which is
+ # impossible to combine with select (unless forcing no
+ # buffering).
+ if self.universal_newlines and hasattr(open, 'newlines'):
+ if stdout:
+ stdout = self._translate_newlines(stdout)
+ if stderr:
+ stderr = self._translate_newlines(stderr)
+
+ self.wait()
+ return (stdout, stderr)
+
+ else:
+ #
+ # POSIX methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tupel with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+ errread, errwrite = None, None
+
+ if stdin == None:
+ pass
+ elif stdin == PIPE:
+ p2cread, p2cwrite = os.pipe()
+ elif type(stdin) == types.IntType:
+ p2cread = stdin
+ else:
+ # Assuming file-like object
+ p2cread = stdin.fileno()
+
+ if stdout == None:
+ pass
+ elif stdout == PIPE:
+ c2pread, c2pwrite = os.pipe()
+ elif type(stdout) == types.IntType:
+ c2pwrite = stdout
+ else:
+ # Assuming file-like object
+ c2pwrite = stdout.fileno()
+
+ if stderr == None:
+ pass
+ elif stderr == PIPE:
+ errread, errwrite = os.pipe()
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif type(stderr) == types.IntType:
+ errwrite = stderr
+ else:
+ # Assuming file-like object
+ errwrite = stderr.fileno()
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _set_cloexec_flag(self, fd):
+ try:
+ cloexec_flag = fcntl.FD_CLOEXEC
+ except AttributeError:
+ cloexec_flag = 1
+
+ old = fcntl.fcntl(fd, fcntl.F_GETFD)
+ fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
+
+
+ def _close_fds(self, but):
+ for i in range(3, MAXFD):
+ if i == but:
+ continue
+ try:
+ os.close(i)
+ except:
+ pass
+
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ """Execute program (POSIX version)"""
+
+ if isinstance(args, types.StringTypes):
+ args = [args]
+
+ if shell:
+ args = ["/bin/sh", "-c"] + args
+
+ if executable == None:
+ executable = args[0]
+
+ # For transferring possible exec failure from child to parent
+ # The first char specifies the exception type: 0 means
+ # OSError, 1 means some other error.
+ errpipe_read, errpipe_write = os.pipe()
+ self._set_cloexec_flag(errpipe_write)
+
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ try:
+ # Close parent's pipe ends
+ if p2cwrite:
+ os.close(p2cwrite)
+ if c2pread:
+ os.close(c2pread)
+ if errread:
+ os.close(errread)
+ os.close(errpipe_read)
+
+ # Dup fds for child
+ if p2cread:
+ os.dup2(p2cread, 0)
+ if c2pwrite:
+ os.dup2(c2pwrite, 1)
+ if errwrite:
+ os.dup2(errwrite, 2)
+
+ # Close pipe fds. Make sure we doesn't close the same
+ # fd more than once.
+ if p2cread:
+ os.close(p2cread)
+ if c2pwrite and c2pwrite not in (p2cread,):
+ os.close(c2pwrite)
+ if errwrite and errwrite not in (p2cread, c2pwrite):
+ os.close(errwrite)
+
+ # Close all other fds, if asked for
+ if close_fds:
+ self._close_fds(but=errpipe_write)
+
+ if cwd != None:
+ os.chdir(cwd)
+
+ if preexec_fn:
+ apply(preexec_fn)
+
+ if env == None:
+ os.execvp(executable, args)
+ else:
+ os.execvpe(executable, args, env)
+
+ except:
+ exc_type, exc_value, tb = sys.exc_info()
+ # Save the traceback and attach it to the exception object
+ exc_lines = traceback.format_exception(exc_type,
+ exc_value,
+ tb)
+ exc_value.child_traceback = ''.join(exc_lines)
+ os.write(errpipe_write, pickle.dumps(exc_value))
+
+ # This exitcode won't be reported to applications, so it
+ # really doesn't matter what we return.
+ os._exit(255)
+
+ # Parent
+ os.close(errpipe_write)
+ if p2cread and p2cwrite:
+ os.close(p2cread)
+ if c2pwrite and c2pread:
+ os.close(c2pwrite)
+ if errwrite and errread:
+ os.close(errwrite)
+
+ # Wait for exec to fail or succeed; possibly raising exception
+ data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
+ os.close(errpipe_read)
+ if data != "":
+ os.waitpid(self.pid, 0)
+ child_exception = pickle.loads(data)
+ raise child_exception
+
+
+ def _handle_exitstatus(self, sts):
+ if os.WIFSIGNALED(sts):
+ self.returncode = -os.WTERMSIG(sts)
+ elif os.WIFEXITED(sts):
+ self.returncode = os.WEXITSTATUS(sts)
+ else:
+ # Should never happen
+ raise RuntimeError("Unknown child exit status!")
+
+ _active.remove(self)
+
+
+ def poll(self):
+ """Check if child process has terminated. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ try:
+ pid, sts = os.waitpid(self.pid, os.WNOHANG)
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ except os.error:
+ pass
+ return self.returncode
+
+
+ def wait(self):
+ """Wait for child process to terminate. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ pid, sts = os.waitpid(self.pid, 0)
+ self._handle_exitstatus(sts)
+ return self.returncode
+
+
+ def communicate(self, input=None):
+ """Interact with process: Send data to stdin. Read data from
+ stdout and stderr, until end-of-file is reached. Wait for
+ process to terminate. The optional input argument should be a
+ string to be sent to the child process, or None, if no data
+ should be sent to the child.
+
+ communicate() returns a tuple (stdout, stderr)."""
+ read_set = []
+ write_set = []
+ stdout = None # Return
+ stderr = None # Return
+
+ if self.stdin:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ self.stdin.flush()
+ if input:
+ write_set.append(self.stdin)
+ else:
+ self.stdin.close()
+ if self.stdout:
+ read_set.append(self.stdout)
+ stdout = []
+ if self.stderr:
+ read_set.append(self.stderr)
+ stderr = []
+
+ while read_set or write_set:
+ rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+ if self.stdin in wlist:
+ # When select has indicated that the file is writable,
+ # we can write up to PIPE_BUF bytes without risk
+ # blocking. POSIX defines PIPE_BUF >= 512
+ bytes_written = os.write(self.stdin.fileno(), input[:512])
+ input = input[bytes_written:]
+ if not input:
+ self.stdin.close()
+ write_set.remove(self.stdin)
+
+ if self.stdout in rlist:
+ data = os.read(self.stdout.fileno(), 1024)
+ if data == "":
+ self.stdout.close()
+ read_set.remove(self.stdout)
+ stdout.append(data)
+
+ if self.stderr in rlist:
+ data = os.read(self.stderr.fileno(), 1024)
+ if data == "":
+ self.stderr.close()
+ read_set.remove(self.stderr)
+ stderr.append(data)
+
+ # All data exchanged. Translate lists into strings.
+ if stdout != None:
+ stdout = ''.join(stdout)
+ if stderr != None:
+ stderr = ''.join(stderr)
+
+ # Translate newlines, if requested. We cannot let the file
+ # object do the translation: It is based on stdio, which is
+ # impossible to combine with select (unless forcing no
+ # buffering).
+ if self.universal_newlines and hasattr(open, 'newlines'):
+ if stdout:
+ stdout = self._translate_newlines(stdout)
+ if stderr:
+ stderr = self._translate_newlines(stderr)
+
+ self.wait()
+ return (stdout, stderr)
+
+
+def _demo_posix():
+ #
+ # Example 1: Simple redirection: Get process list
+ #
+ plist = Popen(["ps"], stdout=PIPE).communicate()[0]
+ print "Process list:"
+ print plist
+
+ #
+ # Example 2: Change uid before executing child
+ #
+ if os.getuid() == 0:
+ p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
+ p.wait()
+
+ #
+ # Example 3: Connecting several subprocesses
+ #
+ print "Looking for 'hda'..."
+ p1 = Popen(["dmesg"], stdout=PIPE)
+ p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+ print repr(p2.communicate()[0])
+
+ #
+ # Example 4: Catch execution error
+ #
+ print
+ print "Trying a weird file..."
+ try:
+ print Popen(["/this/path/does/not/exist"]).communicate()
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ print "The file didn't exist. I thought so..."
+ print "Child traceback:"
+ print e.child_traceback
+ else:
+ print "Error", e.errno
+ else:
+ print >>sys.stderr, "Gosh. No error."
+
+
+def _demo_windows():
+ #
+ # Example 1: Connecting several subprocesses
+ #
+ print "Looking for 'PROMPT' in set output..."
+ p1 = Popen("set", stdout=PIPE, shell=True)
+ p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
+ print repr(p2.communicate()[0])
+
+ #
+ # Example 2: Simple execution of program
+ #
+ print "Executing calc..."
+ p = Popen("calc")
+ p.wait()
+
+
+if __name__ == "__main__":
+ if mswindows:
+ _demo_windows()
+ else:
+ _demo_posix()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/template.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/template.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/template.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,758 @@
+"""
+A small templating language
+
+This implements a small templating language for use internally in
+Paste and Paste Script. This language implements if/elif/else,
+for/continue/break, expressions, and blocks of Python code. The
+syntax is::
+
+ {{any expression (function calls etc)}}
+ {{any expression | filter}}
+ {{for x in y}}...{{endfor}}
+ {{if x}}x{{elif y}}y{{else}}z{{endif}}
+ {{py:x=1}}
+ {{py:
+ def foo(bar):
+ return 'baz'
+ }}
+ {{default var = default_value}}
+ {{# comment}}
+
+You use this with the ``Template`` class or the ``sub`` shortcut.
+The ``Template`` class takes the template string and the name of
+the template (for errors) and a default namespace. Then (like
+``string.Template``) you can call the ``tmpl.substitute(**kw)``
+method to make a substitution (or ``tmpl.substitute(a_dict)``).
+
+``sub(content, **kw)`` substitutes the template immediately. You
+can use ``__name='tmpl.html'`` to set the name of the template.
+
+If there are syntax errors ``TemplateError`` will be raised.
+"""
+
+import re
+import sys
+import cgi
+import urllib
+from paste.util.looper import looper
+
+__all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
+ 'sub_html', 'html', 'bunch']
+
+token_re = re.compile(r'\{\{|\}\}')
+in_re = re.compile(r'\s+in\s+')
+var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
+
+class TemplateError(Exception):
+ """Exception raised while parsing a template
+ """
+
+ def __init__(self, message, position, name=None):
+ self.message = message
+ self.position = position
+ self.name = name
+
+ def __str__(self):
+ msg = '%s at line %s column %s' % (
+ self.message, self.position[0], self.position[1])
+ if self.name:
+ msg += ' in %s' % self.name
+ return msg
+
+class _TemplateContinue(Exception):
+ pass
+
+class _TemplateBreak(Exception):
+ pass
+
+class Template(object):
+
+ default_namespace = {
+ 'start_braces': '{{',
+ 'end_braces': '}}',
+ 'looper': looper,
+ }
+
+ default_encoding = 'utf8'
+
+ def __init__(self, content, name=None, namespace=None):
+ self.content = content
+ self._unicode = isinstance(content, unicode)
+ self.name = name
+ self._parsed = parse(content, name=name)
+ if namespace is None:
+ namespace = {}
+ self.namespace = namespace
+
+ def from_filename(cls, filename, namespace=None, encoding=None):
+ f = open(filename, 'rb')
+ c = f.read()
+ f.close()
+ if encoding:
+ c = c.decode(encoding)
+ return cls(content=c, name=filename, namespace=namespace)
+
+ from_filename = classmethod(from_filename)
+
+ def __repr__(self):
+ return '<%s %s name=%r>' % (
+ self.__class__.__name__,
+ hex(id(self))[2:], self.name)
+
+ def substitute(self, *args, **kw):
+ if args:
+ if kw:
+ raise TypeError(
+ "You can only give positional *or* keyword arguments")
+ if len(args) > 1:
+ raise TypeError(
+ "You can only give on positional argument")
+ kw = args[0]
+ ns = self.default_namespace.copy()
+ ns.update(self.namespace)
+ ns.update(kw)
+ result = self._interpret(ns)
+ return result
+
+ def _interpret(self, ns):
+ __traceback_hide__ = True
+ parts = []
+ self._interpret_codes(self._parsed, ns, out=parts)
+ return ''.join(parts)
+
+ def _interpret_codes(self, codes, ns, out):
+ __traceback_hide__ = True
+ for item in codes:
+ if isinstance(item, basestring):
+ out.append(item)
+ else:
+ self._interpret_code(item, ns, out)
+
+ def _interpret_code(self, code, ns, out):
+ __traceback_hide__ = True
+ name, pos = code[0], code[1]
+ if name == 'py':
+ self._exec(code[2], ns, pos)
+ elif name == 'continue':
+ raise _TemplateContinue()
+ elif name == 'break':
+ raise _TemplateBreak()
+ elif name == 'for':
+ vars, expr, content = code[2], code[3], code[4]
+ expr = self._eval(expr, ns, pos)
+ self._interpret_for(vars, expr, content, ns, out)
+ elif name == 'cond':
+ parts = code[2:]
+ self._interpret_if(parts, ns, out)
+ elif name == 'expr':
+ parts = code[2].split('|')
+ base = self._eval(parts[0], ns, pos)
+ for part in parts[1:]:
+ func = self._eval(part, ns, pos)
+ base = func(base)
+ out.append(self._repr(base, pos))
+ elif name == 'default':
+ var, expr = code[2], code[3]
+ if var not in ns:
+ result = self._eval(expr, ns, pos)
+ ns[var] = result
+ elif name == 'comment':
+ return
+ else:
+ assert 0, "Unknown code: %r" % name
+
+ def _interpret_for(self, vars, expr, content, ns, out):
+ __traceback_hide__ = True
+ for item in expr:
+ if len(vars) == 1:
+ ns[vars[0]] = item
+ else:
+ if len(vars) != len(item):
+ raise ValueError(
+ 'Need %i items to unpack (got %i items)'
+ % (len(vars), len(item)))
+ for name, value in zip(vars, item):
+ ns[name] = value
+ try:
+ self._interpret_codes(content, ns, out)
+ except _TemplateContinue:
+ continue
+ except _TemplateBreak:
+ break
+
+ def _interpret_if(self, parts, ns, out):
+ __traceback_hide__ = True
+ # @@: if/else/else gets through
+ for part in parts:
+ assert not isinstance(part, basestring)
+ name, pos = part[0], part[1]
+ if name == 'else':
+ result = True
+ else:
+ result = self._eval(part[2], ns, pos)
+ if result:
+ self._interpret_codes(part[3], ns, out)
+ break
+
+ def _eval(self, code, ns, pos):
+ __traceback_hide__ = True
+ try:
+ value = eval(code, ns)
+ return value
+ except:
+ exc_info = sys.exc_info()
+ e = exc_info[1]
+ if getattr(e, 'args'):
+ arg0 = e.args[0]
+ else:
+ arg0 = str(e)
+ e.args = (self._add_line_info(arg0, pos),)
+ raise exc_info[0], e, exc_info[2]
+
+ def _exec(self, code, ns, pos):
+ __traceback_hide__ = True
+ try:
+ exec code in ns
+ except:
+ exc_info = sys.exc_info()
+ e = exc_info[1]
+ e.args = (self._add_line_info(e.args[0], pos),)
+ raise exc_info[0], e, exc_info[2]
+
+ def _repr(self, value, pos):
+ __traceback_hide__ = True
+ try:
+ if value is None:
+ return ''
+ if self._unicode:
+ try:
+ value = unicode(value)
+ except UnicodeDecodeError:
+ value = str(value)
+ else:
+ value = str(value)
+ except:
+ exc_info = sys.exc_info()
+ e = exc_info[1]
+ e.args = (self._add_line_info(e.args[0], pos),)
+ raise exc_info[0], e, exc_info[2]
+ else:
+ if self._unicode and isinstance(value, str):
+ if not self.decode_encoding:
+ raise UnicodeDecodeError(
+ 'Cannot decode str value %r into unicode '
+ '(no default_encoding provided)' % value)
+ value = value.decode(self.default_encoding)
+ elif not self._unicode and isinstance(value, unicode):
+ if not self.decode_encoding:
+ raise UnicodeEncodeError(
+ 'Cannot encode unicode value %r into str '
+ '(no default_encoding provided)' % value)
+ value = value.encode(self.default_encoding)
+ return value
+
+
+ def _add_line_info(self, msg, pos):
+ msg = "%s at line %s column %s" % (
+ msg, pos[0], pos[1])
+ if self.name:
+ msg += " in file %s" % self.name
+ return msg
+
+def sub(content, **kw):
+ name = kw.get('__name')
+ tmpl = Template(content, name=name)
+ return tmpl.substitute(kw)
+ return result
+
+def paste_script_template_renderer(content, vars, filename=None):
+ tmpl = Template(content, name=filename)
+ return tmpl.substitute(vars)
+
+class bunch(dict):
+
+ def __init__(self, **kw):
+ for name, value in kw.items():
+ setattr(self, name, value)
+
+ def __setattr__(self, name, value):
+ self[name] = value
+
+ def __getattr__(self, name):
+ try:
+ return self[name]
+ except KeyError:
+ raise AttributeError(name)
+
+ def __getitem__(self, key):
+ if 'default' in self:
+ try:
+ return dict.__getitem__(self, key)
+ except KeyError:
+ return dict.__getitem__(self, 'default')
+ else:
+ return dict.__getitem__(self, key)
+
+ def __repr__(self):
+ items = [
+ (k, v) for k, v in self.items()]
+ items.sort()
+ return '<%s %s>' % (
+ self.__class__.__name__,
+ ' '.join(['%s=%r' % (k, v) for k, v in items]))
+
+############################################################
+## HTML Templating
+############################################################
+
+class html(object):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return self.value
+ def __repr__(self):
+ return '<%s %r>' % (
+ self.__class__.__name__, self.value)
+
+def html_quote(value):
+ if value is None:
+ return ''
+ if not isinstance(value, basestring):
+ if hasattr(value, '__unicode__'):
+ value = unicode(value)
+ else:
+ value = str(value)
+ value = cgi.escape(value, 1)
+ if isinstance(value, unicode):
+ value = value.encode('ascii', 'xmlcharrefreplace')
+ return value
+
+def url(v):
+ if not isinstance(v, basestring):
+ if hasattr(v, '__unicode__'):
+ v = unicode(v)
+ else:
+ v = str(v)
+ if isinstance(v, unicode):
+ v = v.encode('utf8')
+ return urllib.quote(v)
+
+def attr(**kw):
+ kw = kw.items()
+ kw.sort()
+ parts = []
+ for name, value in kw:
+ if value is None:
+ continue
+ if name.endswith('_'):
+ name = name[:-1]
+ parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
+ return html(' '.join(parts))
+
+class HTMLTemplate(Template):
+
+ default_namespace = Template.default_namespace.copy()
+ default_namespace.update(dict(
+ html=html,
+ attr=attr,
+ url=url,
+ ))
+
+ def _repr(self, value, pos):
+ plain = Template._repr(self, value, pos)
+ if isinstance(value, html):
+ return plain
+ else:
+ return html_quote(plain)
+
+def sub_html(content, **kw):
+ name = kw.get('__name')
+ tmpl = HTMLTemplate(content, name=name)
+ return tmpl.substitute(kw)
+ return result
+
+
+############################################################
+## Lexing and Parsing
+############################################################
+
+def lex(s, name=None, trim_whitespace=True):
+ """
+ Lex a string into chunks:
+
+ >>> lex('hey')
+ ['hey']
+ >>> lex('hey {{you}}')
+ ['hey ', ('you', (1, 7))]
+ >>> lex('hey {{')
+ Traceback (most recent call last):
+ ...
+ TemplateError: No }} to finish last expression at line 1 column 7
+ >>> lex('hey }}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: }} outside expression at line 1 column 7
+ >>> lex('hey {{ {{')
+ Traceback (most recent call last):
+ ...
+ TemplateError: {{ inside expression at line 1 column 10
+
+ """
+ in_expr = False
+ chunks = []
+ last = 0
+ last_pos = (1, 1)
+ for match in token_re.finditer(s):
+ expr = match.group(0)
+ pos = find_position(s, match.end())
+ if expr == '{{' and in_expr:
+ raise TemplateError('{{ inside expression', position=pos,
+ name=name)
+ elif expr == '}}' and not in_expr:
+ raise TemplateError('}} outside expression', position=pos,
+ name=name)
+ if expr == '{{':
+ part = s[last:match.start()]
+ if part:
+ chunks.append(part)
+ in_expr = True
+ else:
+ chunks.append((s[last:match.start()], last_pos))
+ in_expr = False
+ last = match.end()
+ last_pos = pos
+ if in_expr:
+ raise TemplateError('No }} to finish last expression',
+ name=name, position=last_pos)
+ part = s[last:]
+ if part:
+ chunks.append(part)
+ if trim_whitespace:
+ chunks = trim_lex(chunks)
+ return chunks
+
+statement_re = re.compile(r'^(?:if |elif |else |for |py:)')
+single_statements = ['endif', 'endfor', 'continue', 'break']
+trail_whitespace_re = re.compile(r'\n[\t ]*$')
+lead_whitespace_re = re.compile(r'^[\t ]*\n')
+
+def trim_lex(tokens):
+ r"""
+ Takes a lexed set of tokens, and removes whitespace when there is
+ a directive on a line by itself:
+
+ >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
+ >>> tokens
+ [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
+ >>> trim_lex(tokens)
+ [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
+ """
+ for i in range(len(tokens)):
+ current = tokens[i]
+ if isinstance(tokens[i], basestring):
+ # we don't trim this
+ continue
+ item = current[0]
+ if not statement_re.search(item) and item not in single_statements:
+ continue
+ if not i:
+ prev = ''
+ else:
+ prev = tokens[i-1]
+ if i+1 >= len(tokens):
+ next = ''
+ else:
+ next = tokens[i+1]
+ if (not isinstance(next, basestring)
+ or not isinstance(prev, basestring)):
+ continue
+ if ((not prev or trail_whitespace_re.search(prev))
+ and (not next or lead_whitespace_re.search(next))):
+ if prev:
+ m = trail_whitespace_re.search(prev)
+ # +1 to leave the leading \n on:
+ prev = prev[:m.start()+1]
+ tokens[i-1] = prev
+ if next:
+ m = lead_whitespace_re.search(next)
+ next = next[m.end():]
+ tokens[i+1] = next
+ return tokens
+
+
+def find_position(string, index):
+ """Given a string and index, return (line, column)"""
+ leading = string[:index].splitlines()
+ return (len(leading), len(leading[-1])+1)
+
+def parse(s, name=None):
+ r"""
+ Parses a string into a kind of AST
+
+ >>> parse('{{x}}')
+ [('expr', (1, 3), 'x')]
+ >>> parse('foo')
+ ['foo']
+ >>> parse('{{if x}}test{{endif}}')
+ [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
+ >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
+ ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
+ >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
+ [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
+ >>> parse('{{py:x=1}}')
+ [('py', (1, 3), 'x=1')]
+ >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
+ [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
+
+ Some exceptions::
+
+ >>> parse('{{continue}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: continue outside of for loop at line 1 column 3
+ >>> parse('{{if x}}foo')
+ Traceback (most recent call last):
+ ...
+ TemplateError: No {{endif}} at line 1 column 3
+ >>> parse('{{else}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: else outside of an if block at line 1 column 3
+ >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: Unexpected endif at line 1 column 25
+ >>> parse('{{if}}{{endif}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: if with no expression at line 1 column 3
+ >>> parse('{{for x y}}{{endfor}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
+ >>> parse('{{py:x=1\ny=2}}')
+ Traceback (most recent call last):
+ ...
+ TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
+ """
+ tokens = lex(s, name=name)
+ result = []
+ while tokens:
+ next, tokens = parse_expr(tokens, name)
+ result.append(next)
+ return result
+
+def parse_expr(tokens, name, context=()):
+ if isinstance(tokens[0], basestring):
+ return tokens[0], tokens[1:]
+ expr, pos = tokens[0]
+ expr = expr.strip()
+ if expr.startswith('py:'):
+ expr = expr[3:].lstrip(' \t')
+ if expr.startswith('\n'):
+ expr = expr[1:]
+ else:
+ if '\n' in expr:
+ raise TemplateError(
+ 'Multi-line py blocks must start with a newline',
+ position=pos, name=name)
+ return ('py', pos, expr), tokens[1:]
+ elif expr in ('continue', 'break'):
+ if 'for' not in context:
+ raise TemplateError(
+ 'continue outside of for loop',
+ position=pos, name=name)
+ return (expr, pos), tokens[1:]
+ elif expr.startswith('if '):
+ return parse_cond(tokens, name, context)
+ elif (expr.startswith('elif ')
+ or expr == 'else'):
+ raise TemplateError(
+ '%s outside of an if block' % expr.split()[0],
+ position=pos, name=name)
+ elif expr in ('if', 'elif', 'for'):
+ raise TemplateError(
+ '%s with no expression' % expr,
+ position=pos, name=name)
+ elif expr in ('endif', 'endfor'):
+ raise TemplateError(
+ 'Unexpected %s' % expr,
+ position=pos, name=name)
+ elif expr.startswith('for '):
+ return parse_for(tokens, name, context)
+ elif expr.startswith('default '):
+ return parse_default(tokens, name, context)
+ elif expr.startswith('#'):
+ return ('comment', pos, tokens[0][0]), tokens[1:]
+ return ('expr', pos, tokens[0][0]), tokens[1:]
+
+def parse_cond(tokens, name, context):
+ start = tokens[0][1]
+ pieces = []
+ context = context + ('if',)
+ while 1:
+ if not tokens:
+ raise TemplateError(
+ 'Missing {{endif}}',
+ position=start, name=name)
+ if (isinstance(tokens[0], tuple)
+ and tokens[0][0] == 'endif'):
+ return ('cond', start) + tuple(pieces), tokens[1:]
+ next, tokens = parse_one_cond(tokens, name, context)
+ pieces.append(next)
+
+def parse_one_cond(tokens, name, context):
+ (first, pos), tokens = tokens[0], tokens[1:]
+ content = []
+ if first.endswith(':'):
+ first = first[:-1]
+ if first.startswith('if '):
+ part = ('if', pos, first[3:].lstrip(), content)
+ elif first.startswith('elif '):
+ part = ('elif', pos, first[5:].lstrip(), content)
+ elif first == 'else':
+ part = ('else', pos, None, content)
+ else:
+ assert 0, "Unexpected token %r at %s" % (first, pos)
+ while 1:
+ if not tokens:
+ raise TemplateError(
+ 'No {{endif}}',
+ position=pos, name=name)
+ if (isinstance(tokens[0], tuple)
+ and (tokens[0][0] == 'endif'
+ or tokens[0][0].startswith('elif ')
+ or tokens[0][0] == 'else')):
+ return part, tokens
+ next, tokens = parse_expr(tokens, name, context)
+ content.append(next)
+
+def parse_for(tokens, name, context):
+ first, pos = tokens[0]
+ tokens = tokens[1:]
+ context = ('for',) + context
+ content = []
+ assert first.startswith('for ')
+ if first.endswith(':'):
+ first = first[:-1]
+ first = first[3:].strip()
+ match = in_re.search(first)
+ if not match:
+ raise TemplateError(
+ 'Bad for (no "in") in %r' % first,
+ position=pos, name=name)
+ vars = first[:match.start()]
+ if '(' in vars:
+ raise TemplateError(
+ 'You cannot have () in the variable section of a for loop (%r)'
+ % vars, position=pos, name=name)
+ vars = tuple([
+ v.strip() for v in first[:match.start()].split(',')
+ if v.strip()])
+ expr = first[match.end():]
+ while 1:
+ if not tokens:
+ raise TemplateError(
+ 'No {{endfor}}',
+ position=pos, name=name)
+ if (isinstance(tokens[0], tuple)
+ and tokens[0][0] == 'endfor'):
+ return ('for', pos, vars, expr, content), tokens[1:]
+ next, tokens = parse_expr(tokens, name, context)
+ content.append(next)
+
+def parse_default(tokens, name, context):
+ first, pos = tokens[0]
+ assert first.startswith('default ')
+ first = first.split(None, 1)[1]
+ parts = first.split('=', 1)
+ if len(parts) == 1:
+ raise TemplateError(
+ "Expression must be {{default var=value}}; no = found in %r" % first,
+ position=pos, name=name)
+ var = parts[0].strip()
+ if ',' in var:
+ raise TemplateError(
+ "{{default x, y = ...}} is not supported",
+ position=pos, name=name)
+ if not var_re.search(var):
+ raise TemplateError(
+ "Not a valid variable name for {{default}}: %r"
+ % var, position=pos, name=name)
+ expr = parts[1].strip()
+ return ('default', pos, var, expr), tokens[1:]
+
+_fill_command_usage = """\
+%prog [OPTIONS] TEMPLATE arg=value
+
+Use py:arg=value to set a Python value; otherwise all values are
+strings.
+"""
+
+def fill_command(args=None):
+ import sys, optparse, pkg_resources, os
+ if args is None:
+ args = sys.argv[1:]
+ dist = pkg_resources.get_distribution('Paste')
+ parser = optparse.OptionParser(
+ version=str(dist),
+ usage=_fill_command_usage)
+ parser.add_option(
+ '-o', '--output',
+ dest='output',
+ metavar="FILENAME",
+ help="File to write output to (default stdout)")
+ parser.add_option(
+ '--html',
+ dest='use_html',
+ action='store_true',
+ help="Use HTML style filling (including automatic HTML quoting)")
+ parser.add_option(
+ '--env',
+ dest='use_env',
+ action='store_true',
+ help="Put the environment in as top-level variables")
+ options, args = parser.parse_args(args)
+ if len(args) < 1:
+ print 'You must give a template filename'
+ print dir(parser)
+ assert 0
+ template_name = args[0]
+ args = args[1:]
+ vars = {}
+ if options.use_env:
+ vars.update(os.environ)
+ for value in args:
+ if '=' not in value:
+ print 'Bad argument: %r' % value
+ sys.exit(2)
+ name, value = value.split('=', 1)
+ if name.startswith('py:'):
+ name = name[:3]
+ value = eval(value)
+ vars[name] = value
+ if template_name == '-':
+ template_content = sys.stdin.read()
+ template_name = '<stdin>'
+ else:
+ f = open(template_name, 'rb')
+ template_content = f.read()
+ f.close()
+ if options.use_html:
+ TemplateClass = HTMLTemplate
+ else:
+ TemplateClass = Template
+ template = TemplateClass(template_content, name=template_name)
+ result = template.substitute(vars)
+ if options.output:
+ f = open(options.output, 'wb')
+ f.write(result)
+ f.close()
+ else:
+ sys.stdout.write(result)
+
+if __name__ == '__main__':
+ from paste.util.template import fill_command
+ fill_command()
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadedprint.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadedprint.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadedprint.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,250 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+threadedprint.py
+================
+
+:author: Ian Bicking
+:date: 12 Jul 2004
+
+Multi-threaded printing; allows the output produced via print to be
+separated according to the thread.
+
+To use this, you must install the catcher, like::
+
+ threadedprint.install()
+
+The installation optionally takes one of three parameters:
+
+default
+ The default destination for print statements (e.g., ``sys.stdout``).
+factory
+ A function that will produce the stream for a thread, given the
+ thread's name.
+paramwriter
+ Instead of writing to a file-like stream, this function will be
+ called like ``paramwriter(thread_name, text)`` for every write.
+
+The thread name is the value returned by
+``threading.currentThread().getName()``, a string (typically something
+like Thread-N).
+
+You can also submit file-like objects for specific threads, which will
+override any of these parameters. To do this, call ``register(stream,
+[threadName])``. ``threadName`` is optional, and if not provided the
+stream will be registered for the current thread.
+
+If no specific stream is registered for a thread, and no default has
+been provided, then an error will occur when anything is written to
+``sys.stdout`` (or printed).
+
+Note: the stream's ``write`` method will be called in the thread the
+text came from, so you should consider thread safety, especially if
+multiple threads share the same writer.
+
+Note: if you want access to the original standard out, use
+``sys.__stdout__``.
+
+You may also uninstall this, via::
+
+ threadedprint.uninstall()
+
+TODO
+----
+
+* Something with ``sys.stderr``.
+* Some default handlers. Maybe something that hooks into `logging`.
+* Possibly cache the results of ``factory`` calls. This would be a
+ semantic change.
+
+"""
+
+import threading
+import sys
+from paste.util import filemixin
+
+class PrintCatcher(filemixin.FileMixin):
+
+ def __init__(self, default=None, factory=None, paramwriter=None,
+ leave_stdout=False):
+ assert len(filter(lambda x: x is not None,
+ [default, factory, paramwriter])) <= 1, (
+ "You can only provide one of default, factory, or paramwriter")
+ if leave_stdout:
+ assert not default, (
+ "You cannot pass in both default (%r) and "
+ "leave_stdout=True" % default)
+ default = sys.stdout
+ if default:
+ self._defaultfunc = self._writedefault
+ elif factory:
+ self._defaultfunc = self._writefactory
+ elif paramwriter:
+ self._defaultfunc = self._writeparam
+ else:
+ self._defaultfunc = self._writeerror
+ self._default = default
+ self._factory = factory
+ self._paramwriter = paramwriter
+ self._catchers = {}
+
+ def write(self, v, currentThread=threading.currentThread):
+ name = currentThread().getName()
+ catchers = self._catchers
+ if not catchers.has_key(name):
+ self._defaultfunc(name, v)
+ else:
+ catcher = catchers[name]
+ catcher.write(v)
+
+ def seek(self, *args):
+ # Weird, but Google App Engine is seeking on stdout
+ name = threading.currentThread().getName()
+ catchers = self._catchers
+ if not name in catchers:
+ self._default.seek(*args)
+ else:
+ catchers[name].seek(*args)
+
+ def read(self, *args):
+ name = threading.currentThread().getName()
+ catchers = self._catchers
+ if not name in catchers:
+ self._default.read(*args)
+ else:
+ catchers[name].read(*args)
+
+
+ def _writedefault(self, name, v):
+ self._default.write(v)
+
+ def _writefactory(self, name, v):
+ self._factory(name).write(v)
+
+ def _writeparam(self, name, v):
+ self._paramwriter(name, v)
+
+ def _writeerror(self, name, v):
+ assert False, (
+ "There is no PrintCatcher output stream for the thread %r"
+ % name)
+
+ def register(self, catcher, name=None,
+ currentThread=threading.currentThread):
+ if name is None:
+ name = currentThread().getName()
+ self._catchers[name] = catcher
+
+ def deregister(self, name=None,
+ currentThread=threading.currentThread):
+ if name is None:
+ name = currentThread().getName()
+ assert self._catchers.has_key(name), (
+ "There is no PrintCatcher catcher for the thread %r" % name)
+ del self._catchers[name]
+
+_printcatcher = None
+_oldstdout = None
+
+def install(**kw):
+ global _printcatcher, _oldstdout, register, deregister
+ if (not _printcatcher or sys.stdout is not _printcatcher):
+ _oldstdout = sys.stdout
+ _printcatcher = sys.stdout = PrintCatcher(**kw)
+ register = _printcatcher.register
+ deregister = _printcatcher.deregister
+
+def uninstall():
+ global _printcatcher, _oldstdout, register, deregister
+ if _printcatcher:
+ sys.stdout = _oldstdout
+ _printcatcher = _oldstdout = None
+ register = not_installed_error
+ deregister = not_installed_error
+
+def not_installed_error(*args, **kw):
+ assert False, (
+ "threadedprint has not yet been installed (call "
+ "threadedprint.install())")
+
+register = deregister = not_installed_error
+
+class StdinCatcher(filemixin.FileMixin):
+
+ def __init__(self, default=None, factory=None, paramwriter=None):
+ assert len(filter(lambda x: x is not None,
+ [default, factory, paramwriter])) <= 1, (
+ "You can only provide one of default, factory, or paramwriter")
+ if default:
+ self._defaultfunc = self._readdefault
+ elif factory:
+ self._defaultfunc = self._readfactory
+ elif paramwriter:
+ self._defaultfunc = self._readparam
+ else:
+ self._defaultfunc = self._readerror
+ self._default = default
+ self._factory = factory
+ self._paramwriter = paramwriter
+ self._catchers = {}
+
+ def read(self, size=None, currentThread=threading.currentThread):
+ name = currentThread().getName()
+ catchers = self._catchers
+ if not catchers.has_key(name):
+ return self._defaultfunc(name, size)
+ else:
+ catcher = catchers[name]
+ return catcher.read(size)
+
+ def _readdefault(self, name, size):
+ self._default.read(size)
+
+ def _readfactory(self, name, size):
+ self._factory(name).read(size)
+
+ def _readparam(self, name, size):
+ self._paramreader(name, size)
+
+ def _readerror(self, name, size):
+ assert False, (
+ "There is no StdinCatcher output stream for the thread %r"
+ % name)
+
+ def register(self, catcher, name=None,
+ currentThread=threading.currentThread):
+ if name is None:
+ name = currentThread().getName()
+ self._catchers[name] = catcher
+
+ def deregister(self, catcher, name=None,
+ currentThread=threading.currentThread):
+ if name is None:
+ name = currentThread().getName()
+ assert self._catchers.has_key(name), (
+ "There is no StdinCatcher catcher for the thread %r" % name)
+ del self._catchers[name]
+
+_stdincatcher = None
+_oldstdin = None
+
+def install_stdin(**kw):
+ global _stdincatcher, _oldstdin, register_stdin, deregister_stdin
+ if not _stdincatcher:
+ _oldstdin = sys.stdin
+ _stdincatcher = sys.stdin = StdinCatcher(**kw)
+ register_stdin = _stdincatcher.register
+ deregister_stdin = _stdincatcher.deregister
+
+def uninstall():
+ global _stdincatcher, _oldstin, register_stdin, deregister_stdin
+ if _stdincatcher:
+ sys.stdin = _oldstdin
+ _stdincatcher = _oldstdin = None
+ register_stdin = deregister_stdin = not_installed_error_stdin
+
+def not_installed_error_stdin(*args, **kw):
+ assert False, (
+ "threadedprint has not yet been installed for stdin (call "
+ "threadedprint.install_stdin())")
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadinglocal.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadinglocal.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/util/threadinglocal.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,43 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Implementation of thread-local storage, for Python versions that don't
+have thread local storage natively.
+"""
+
+try:
+ import threading
+except ImportError:
+ # No threads, so "thread local" means process-global
+ class local(object):
+ pass
+else:
+ try:
+ local = threading.local
+ except AttributeError:
+ # Added in 2.4, but now we'll have to define it ourselves
+ import thread
+ class local(object):
+
+ def __init__(self):
+ self.__dict__['__objs'] = {}
+
+ def __getattr__(self, attr, g=thread.get_ident):
+ try:
+ return self.__dict__['__objs'][g()][attr]
+ except KeyError:
+ raise AttributeError(
+ "No variable %s defined for the thread %s"
+ % (attr, g()))
+
+ def __setattr__(self, attr, value, g=thread.get_ident):
+ self.__dict__['__objs'].setdefault(g(), {})[attr] = value
+
+ def __delattr__(self, attr, g=thread.get_ident):
+ try:
+ del self.__dict__['__objs'][g()][attr]
+ except KeyError:
+ raise AttributeError(
+ "No variable %s defined for thread %s"
+ % (attr, g()))
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgilib.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgilib.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgilib.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,597 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+"""
+A module of many disparate routines.
+"""
+
+# functions which moved to paste.request and paste.response
+# Deprecated around 15 Dec 2005
+from paste.request import get_cookies, parse_querystring, parse_formvars
+from paste.request import construct_url, path_info_split, path_info_pop
+from paste.response import HeaderDict, has_header, header_value, remove_header
+from paste.response import error_body_response, error_response, error_response_app
+
+from traceback import print_exception
+import urllib
+from cStringIO import StringIO
+import sys
+from urlparse import urlsplit
+import warnings
+
+__all__ = ['add_close', 'add_start_close', 'capture_output', 'catch_errors',
+ 'catch_errors_app', 'chained_app_iters', 'construct_url',
+ 'dump_environ', 'encode_unicode_app_iter', 'error_body_response',
+ 'error_response', 'get_cookies', 'has_header', 'header_value',
+ 'interactive', 'intercept_output', 'path_info_pop',
+ 'path_info_split', 'raw_interactive', 'send_file']
+
+class add_close(object):
+ """
+ An an iterable that iterates over app_iter, then calls
+ close_func.
+ """
+
+ def __init__(self, app_iterable, close_func):
+ self.app_iterable = app_iterable
+ self.app_iter = iter(app_iterable)
+ self.close_func = close_func
+ self._closed = False
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ return self.app_iter.next()
+
+ def close(self):
+ self._closed = True
+ if hasattr(self.app_iterable, 'close'):
+ self.app_iterable.close()
+ self.close_func()
+
+ def __del__(self):
+ if not self._closed:
+ # We can't raise an error or anything at this stage
+ print >> sys.stderr, (
+ "Error: app_iter.close() was not called when finishing "
+ "WSGI request. finalization function %s not called"
+ % self.close_func)
+
+class add_start_close(object):
+ """
+ An an iterable that iterates over app_iter, calls start_func
+ before the first item is returned, then calls close_func at the
+ end.
+ """
+
+ def __init__(self, app_iterable, start_func, close_func=None):
+ self.app_iterable = app_iterable
+ self.app_iter = iter(app_iterable)
+ self.first = True
+ self.start_func = start_func
+ self.close_func = close_func
+ self._closed = False
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.first:
+ self.start_func()
+ self.first = False
+ return self.app_iter.next()
+
+ def close(self):
+ self._closed = True
+ if hasattr(self.app_iterable, 'close'):
+ self.app_iterable.close()
+ if self.close_func is not None:
+ self.close_func()
+
+ def __del__(self):
+ if not self._closed:
+ # We can't raise an error or anything at this stage
+ print >> sys.stderr, (
+ "Error: app_iter.close() was not called when finishing "
+ "WSGI request. finalization function %s not called"
+ % self.close_func)
+
+class chained_app_iters(object):
+
+ """
+ Chains several app_iters together, also delegating .close() to each
+ of them.
+ """
+
+ def __init__(self, *chained):
+ self.app_iters = chained
+ self.chained = [iter(item) for item in chained]
+ self._closed = False
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if len(self.chained) == 1:
+ return self.chained[0].next()
+ else:
+ try:
+ return self.chained[0].next()
+ except StopIteration:
+ self.chained.pop(0)
+ return self.next()
+
+ def close(self):
+ self._closed = True
+ got_exc = None
+ for app_iter in self.app_iters:
+ try:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ except:
+ got_exc = sys.exc_info()
+ if got_exc:
+ raise got_exc[0], got_exc[1], got_exc[2]
+
+ def __del__(self):
+ if not self._closed:
+ # We can't raise an error or anything at this stage
+ print >> sys.stderr, (
+ "Error: app_iter.close() was not called when finishing "
+ "WSGI request. finalization function %s not called"
+ % self.close_func)
+
+class encode_unicode_app_iter(object):
+ """
+ Encodes an app_iterable's unicode responses as strings
+ """
+
+ def __init__(self, app_iterable, encoding=sys.getdefaultencoding(),
+ errors='strict'):
+ self.app_iterable = app_iterable
+ self.app_iter = iter(app_iterable)
+ self.encoding = encoding
+ self.errors = errors
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ content = self.app_iter.next()
+ if isinstance(content, unicode):
+ content = content.encode(self.encoding, self.errors)
+ return content
+
+ def close(self):
+ if hasattr(self.app_iterable, 'close'):
+ self.app_iterable.close()
+
+def catch_errors(application, environ, start_response, error_callback,
+ ok_callback=None):
+ """
+ Runs the application, and returns the application iterator (which should be
+ passed upstream). If an error occurs then error_callback will be called with
+ exc_info as its sole argument. If no errors occur and ok_callback is given,
+ then it will be called with no arguments.
+ """
+ try:
+ app_iter = application(environ, start_response)
+ except:
+ error_callback(sys.exc_info())
+ raise
+ if type(app_iter) in (list, tuple):
+ # These won't produce exceptions
+ if ok_callback:
+ ok_callback()
+ return app_iter
+ else:
+ return _wrap_app_iter(app_iter, error_callback, ok_callback)
+
+class _wrap_app_iter(object):
+
+ def __init__(self, app_iterable, error_callback, ok_callback):
+ self.app_iterable = app_iterable
+ self.app_iter = iter(app_iterable)
+ self.error_callback = error_callback
+ self.ok_callback = ok_callback
+ if hasattr(self.app_iterable, 'close'):
+ self.close = self.app_iterable.close
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ try:
+ return self.app_iter.next()
+ except StopIteration:
+ if self.ok_callback:
+ self.ok_callback()
+ raise
+ except:
+ self.error_callback(sys.exc_info())
+ raise
+
+def catch_errors_app(application, environ, start_response, error_callback_app,
+ ok_callback=None, catch=Exception):
+ """
+ Like ``catch_errors``, except error_callback_app should be a
+ callable that will receive *three* arguments -- ``environ``,
+ ``start_response``, and ``exc_info``. It should call
+ ``start_response`` (*with* the exc_info argument!) and return an
+ iterator.
+ """
+ try:
+ app_iter = application(environ, start_response)
+ except catch:
+ return error_callback_app(environ, start_response, sys.exc_info())
+ if type(app_iter) in (list, tuple):
+ # These won't produce exceptions
+ if ok_callback is not None:
+ ok_callback()
+ return app_iter
+ else:
+ return _wrap_app_iter_app(
+ environ, start_response, app_iter,
+ error_callback_app, ok_callback, catch=catch)
+
+class _wrap_app_iter_app(object):
+
+ def __init__(self, environ, start_response, app_iterable,
+ error_callback_app, ok_callback, catch=Exception):
+ self.environ = environ
+ self.start_response = start_response
+ self.app_iterable = app_iterable
+ self.app_iter = iter(app_iterable)
+ self.error_callback_app = error_callback_app
+ self.ok_callback = ok_callback
+ self.catch = catch
+ if hasattr(self.app_iterable, 'close'):
+ self.close = self.app_iterable.close
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ try:
+ return self.app_iter.next()
+ except StopIteration:
+ if self.ok_callback:
+ self.ok_callback()
+ raise
+ except self.catch:
+ if hasattr(self.app_iterable, 'close'):
+ try:
+ self.app_iterable.close()
+ except:
+ # @@: Print to wsgi.errors?
+ pass
+ new_app_iterable = self.error_callback_app(
+ self.environ, self.start_response, sys.exc_info())
+ app_iter = iter(new_app_iterable)
+ if hasattr(new_app_iterable, 'close'):
+ self.close = new_app_iterable.close
+ self.next = app_iter.next
+ return self.next()
+
+def raw_interactive(application, path='', raise_on_wsgi_error=False,
+ **environ):
+ """
+ Runs the application in a fake environment.
+ """
+ assert "path_info" not in environ, "argument list changed"
+ if raise_on_wsgi_error:
+ errors = ErrorRaiser()
+ else:
+ errors = StringIO()
+ basic_environ = {
+ # mandatory CGI variables
+ 'REQUEST_METHOD': 'GET', # always mandatory
+ 'SCRIPT_NAME': '', # may be empty if app is at the root
+ 'PATH_INFO': '', # may be empty if at root of app
+ 'SERVER_NAME': 'localhost', # always mandatory
+ 'SERVER_PORT': '80', # always mandatory
+ 'SERVER_PROTOCOL': 'HTTP/1.0',
+ # mandatory wsgi variables
+ 'wsgi.version': (1, 0),
+ 'wsgi.url_scheme': 'http',
+ 'wsgi.input': StringIO(''),
+ 'wsgi.errors': errors,
+ 'wsgi.multithread': False,
+ 'wsgi.multiprocess': False,
+ 'wsgi.run_once': False,
+ }
+ if path:
+ (_, _, path_info, query, fragment) = urlsplit(str(path))
+ path_info = urllib.unquote(path_info)
+ # urlsplit returns unicode so coerce it back to str
+ path_info, query = str(path_info), str(query)
+ basic_environ['PATH_INFO'] = path_info
+ if query:
+ basic_environ['QUERY_STRING'] = query
+ for name, value in environ.items():
+ name = name.replace('__', '.')
+ basic_environ[name] = value
+ if ('SERVER_NAME' in basic_environ
+ and 'HTTP_HOST' not in basic_environ):
+ basic_environ['HTTP_HOST'] = basic_environ['SERVER_NAME']
+ istream = basic_environ['wsgi.input']
+ if isinstance(istream, str):
+ basic_environ['wsgi.input'] = StringIO(istream)
+ basic_environ['CONTENT_LENGTH'] = len(istream)
+ data = {}
+ output = []
+ headers_set = []
+ headers_sent = []
+ def start_response(status, headers, exc_info=None):
+ if exc_info:
+ try:
+ if headers_sent:
+ # Re-raise original exception only if headers sent
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ # avoid dangling circular reference
+ exc_info = None
+ elif headers_set:
+ # You cannot set the headers more than once, unless the
+ # exc_info is provided.
+ raise AssertionError("Headers already set and no exc_info!")
+ headers_set.append(True)
+ data['status'] = status
+ data['headers'] = headers
+ return output.append
+ app_iter = application(basic_environ, start_response)
+ try:
+ try:
+ for s in app_iter:
+ if not isinstance(s, str):
+ raise ValueError(
+ "The app_iter response can only contain str (not "
+ "unicode); got: %r" % s)
+ headers_sent.append(True)
+ if not headers_set:
+ raise AssertionError("Content sent w/o headers!")
+ output.append(s)
+ except TypeError, e:
+ # Typically "iteration over non-sequence", so we want
+ # to give better debugging information...
+ e.args = ((e.args[0] + ' iterable: %r' % app_iter),) + e.args[1:]
+ raise
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ return (data['status'], data['headers'], ''.join(output),
+ errors.getvalue())
+
+class ErrorRaiser(object):
+
+ def flush(self):
+ pass
+
+ def write(self, value):
+ if not value:
+ return
+ raise AssertionError(
+ "No errors should be written (got: %r)" % value)
+
+ def writelines(self, seq):
+ raise AssertionError(
+ "No errors should be written (got lines: %s)" % list(seq))
+
+ def getvalue(self):
+ return ''
+
+def interactive(*args, **kw):
+ """
+ Runs the application interatively, wrapping `raw_interactive` but
+ returning the output in a formatted way.
+ """
+ status, headers, content, errors = raw_interactive(*args, **kw)
+ full = StringIO()
+ if errors:
+ full.write('Errors:\n')
+ full.write(errors.strip())
+ full.write('\n----------end errors\n')
+ full.write(status + '\n')
+ for name, value in headers:
+ full.write('%s: %s\n' % (name, value))
+ full.write('\n')
+ full.write(content)
+ return full.getvalue()
+interactive.proxy = 'raw_interactive'
+
+def dump_environ(environ, start_response):
+ """
+ Application which simply dumps the current environment
+ variables out as a plain text response.
+ """
+ output = []
+ keys = environ.keys()
+ keys.sort()
+ for k in keys:
+ v = str(environ[k]).replace("\n","\n ")
+ output.append("%s: %s\n" % (k, v))
+ output.append("\n")
+ content_length = environ.get("CONTENT_LENGTH", '')
+ if content_length:
+ output.append(environ['wsgi.input'].read(int(content_length)))
+ output.append("\n")
+ output = "".join(output)
+ headers = [('Content-Type', 'text/plain'),
+ ('Content-Length', str(len(output)))]
+ start_response("200 OK", headers)
+ return [output]
+
+def send_file(filename):
+ warnings.warn(
+ "wsgilib.send_file has been moved to paste.fileapp.FileApp",
+ DeprecationWarning, 2)
+ from paste import fileapp
+ return fileapp.FileApp(filename)
+
+def capture_output(environ, start_response, application):
+ """
+ Runs application with environ and start_response, and captures
+ status, headers, and body.
+
+ Sends status and header, but *not* body. Returns (status,
+ headers, body). Typically this is used like:
+
+ .. code-block:: python
+
+ def dehtmlifying_middleware(application):
+ def replacement_app(environ, start_response):
+ status, headers, body = capture_output(
+ environ, start_response, application)
+ content_type = header_value(headers, 'content-type')
+ if (not content_type
+ or not content_type.startswith('text/html')):
+ return [body]
+ body = re.sub(r'<.*?>', '', body)
+ return [body]
+ return replacement_app
+
+ """
+ warnings.warn(
+ 'wsgilib.capture_output has been deprecated in favor '
+ 'of wsgilib.intercept_output',
+ DeprecationWarning, 2)
+ data = []
+ output = StringIO()
+ def replacement_start_response(status, headers, exc_info=None):
+ if data:
+ data[:] = []
+ data.append(status)
+ data.append(headers)
+ start_response(status, headers, exc_info)
+ return output.write
+ app_iter = application(environ, replacement_start_response)
+ try:
+ for item in app_iter:
+ output.write(item)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ if not data:
+ data.append(None)
+ if len(data) < 2:
+ data.append(None)
+ data.append(output.getvalue())
+ return data
+
+def intercept_output(environ, application, conditional=None,
+ start_response=None):
+ """
+ Runs application with environ and captures status, headers, and
+ body. None are sent on; you must send them on yourself (unlike
+ ``capture_output``)
+
+ Typically this is used like:
+
+ .. code-block:: python
+
+ def dehtmlifying_middleware(application):
+ def replacement_app(environ, start_response):
+ status, headers, body = intercept_output(
+ environ, application)
+ start_response(status, headers)
+ content_type = header_value(headers, 'content-type')
+ if (not content_type
+ or not content_type.startswith('text/html')):
+ return [body]
+ body = re.sub(r'<.*?>', '', body)
+ return [body]
+ return replacement_app
+
+ A third optional argument ``conditional`` should be a function
+ that takes ``conditional(status, headers)`` and returns False if
+ the request should not be intercepted. In that case
+ ``start_response`` will be called and ``(None, None, app_iter)``
+ will be returned. You must detect that in your code and return
+ the app_iter, like:
+
+ .. code-block:: python
+
+ def dehtmlifying_middleware(application):
+ def replacement_app(environ, start_response):
+ status, headers, body = intercept_output(
+ environ, application,
+ lambda s, h: header_value(headers, 'content-type').startswith('text/html'),
+ start_response)
+ if status is None:
+ return body
+ start_response(status, headers)
+ body = re.sub(r'<.*?>', '', body)
+ return [body]
+ return replacement_app
+ """
+ if conditional is not None and start_response is None:
+ raise TypeError(
+ "If you provide conditional you must also provide "
+ "start_response")
+ data = []
+ output = StringIO()
+ def replacement_start_response(status, headers, exc_info=None):
+ if conditional is not None and not conditional(status, headers):
+ data.append(None)
+ return start_response(status, headers, exc_info)
+ if data:
+ data[:] = []
+ data.append(status)
+ data.append(headers)
+ return output.write
+ app_iter = application(environ, replacement_start_response)
+ if data[0] is None:
+ return (None, None, app_iter)
+ try:
+ for item in app_iter:
+ output.write(item)
+ finally:
+ if hasattr(app_iter, 'close'):
+ app_iter.close()
+ if not data:
+ data.append(None)
+ if len(data) < 2:
+ data.append(None)
+ data.append(output.getvalue())
+ return data
+
+## Deprecation warning wrapper:
+
+class ResponseHeaderDict(HeaderDict):
+
+ def __init__(self, *args, **kw):
+ warnings.warn(
+ "The class wsgilib.ResponseHeaderDict has been moved "
+ "to paste.response.HeaderDict",
+ DeprecationWarning, 2)
+ HeaderDict.__init__(self, *args, **kw)
+
+def _warn_deprecated(new_func):
+ new_name = new_func.func_name
+ new_path = new_func.func_globals['__name__'] + '.' + new_name
+ def replacement(*args, **kw):
+ warnings.warn(
+ "The function wsgilib.%s has been moved to %s"
+ % (new_name, new_path),
+ DeprecationWarning, 2)
+ return new_func(*args, **kw)
+ try:
+ replacement.func_name = new_func.func_name
+ except:
+ pass
+ return replacement
+
+# Put warnings wrapper in place for all public functions that
+# were imported from elsewhere:
+
+for _name in __all__:
+ _func = globals()[_name]
+ if (hasattr(_func, 'func_globals')
+ and _func.func_globals['__name__'] != __name__):
+ globals()[_name] = _warn_deprecated(_func)
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgiwrappers.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgiwrappers.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/wsgiwrappers.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,581 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""WSGI Wrappers for a Request and Response
+
+The WSGIRequest and WSGIResponse objects are light wrappers to make it easier
+to deal with an incoming request and sending a response.
+"""
+import re
+import warnings
+from pprint import pformat
+from Cookie import SimpleCookie
+from paste.request import EnvironHeaders, get_cookie_dict, \
+ parse_dict_querystring, parse_formvars
+from paste.util.multidict import MultiDict, UnicodeMultiDict
+from paste.registry import StackedObjectProxy
+from paste.response import HeaderDict
+from paste.wsgilib import encode_unicode_app_iter
+from paste.httpheaders import ACCEPT_LANGUAGE
+from paste.util.mimeparse import desired_matches
+
+__all__ = ['WSGIRequest', 'WSGIResponse']
+
+_CHARSET_RE = re.compile(r';\s*charset=([^;]*)', re.I)
+
+class DeprecatedSettings(StackedObjectProxy):
+ def _push_object(self, obj):
+ warnings.warn('paste.wsgiwrappers.settings is deprecated: Please use '
+ 'paste.wsgiwrappers.WSGIRequest.defaults instead',
+ DeprecationWarning, 3)
+ WSGIResponse.defaults._push_object(obj)
+ StackedObjectProxy._push_object(self, obj)
+
+# settings is deprecated: use WSGIResponse.defaults instead
+settings = DeprecatedSettings(default=dict())
+
+class environ_getter(object):
+ """For delegating an attribute to a key in self.environ."""
+ # @@: Also __set__? Should setting be allowed?
+ def __init__(self, key, default='', default_factory=None):
+ self.key = key
+ self.default = default
+ self.default_factory = default_factory
+ def __get__(self, obj, type=None):
+ if type is None:
+ return self
+ if self.key not in obj.environ:
+ if self.default_factory:
+ val = obj.environ[self.key] = self.default_factory()
+ return val
+ else:
+ return self.default
+ return obj.environ[self.key]
+
+ def __repr__(self):
+ return '<Proxy for WSGI environ %r key>' % self.key
+
+class WSGIRequest(object):
+ """WSGI Request API Object
+
+ This object represents a WSGI request with a more friendly interface.
+ This does not expose every detail of the WSGI environment, and attempts
+ to express nothing beyond what is available in the environment
+ dictionary.
+
+ The only state maintained in this object is the desired ``charset``,
+ its associated ``errors`` handler, and the ``decode_param_names``
+ option.
+
+ The incoming parameter values will be automatically coerced to unicode
+ objects of the ``charset`` encoding when ``charset`` is set. The
+ incoming parameter names are not decoded to unicode unless the
+ ``decode_param_names`` option is enabled.
+
+ When unicode is expected, ``charset`` will overridden by the the
+ value of the ``Content-Type`` header's charset parameter if one was
+ specified by the client.
+
+ The class variable ``defaults`` specifies default values for
+ ``charset``, ``errors``, and ``langauge``. These can be overridden for the
+ current request via the registry.
+
+ The ``language`` default value is considered the fallback during i18n
+ translations to ensure in odd cases that mixed languages don't occur should
+ the ``language`` file contain the string but not another language in the
+ accepted languages list. The ``language`` value only applies when getting
+ a list of accepted languages from the HTTP Accept header.
+
+ This behavior is duplicated from Aquarium, and may seem strange but is
+ very useful. Normally, everything in the code is in "en-us". However,
+ the "en-us" translation catalog is usually empty. If the user requests
+ ``["en-us", "zh-cn"]`` and a translation isn't found for a string in
+ "en-us", you don't want gettext to fallback to "zh-cn". You want it to
+ just use the string itself. Hence, if a string isn't found in the
+ ``language`` catalog, the string in the source code will be used.
+
+ *All* other state is kept in the environment dictionary; this is
+ essential for interoperability.
+
+ You are free to subclass this object.
+
+ """
+ defaults = StackedObjectProxy(default=dict(charset=None, errors='replace',
+ decode_param_names=False,
+ language='en-us'))
+ def __init__(self, environ):
+ self.environ = environ
+ # This isn't "state" really, since the object is derivative:
+ self.headers = EnvironHeaders(environ)
+
+ defaults = self.defaults._current_obj()
+ self.charset = defaults.get('charset')
+ if self.charset:
+ # There's a charset: params will be coerced to unicode. In that
+ # case, attempt to use the charset specified by the browser
+ browser_charset = self.determine_browser_charset()
+ if browser_charset:
+ self.charset = browser_charset
+ self.errors = defaults.get('errors', 'strict')
+ self.decode_param_names = defaults.get('decode_param_names', False)
+ self._languages = None
+
+ body = environ_getter('wsgi.input')
+ scheme = environ_getter('wsgi.url_scheme')
+ method = environ_getter('REQUEST_METHOD')
+ script_name = environ_getter('SCRIPT_NAME')
+ path_info = environ_getter('PATH_INFO')
+
+ def urlvars(self):
+ """
+ Return any variables matched in the URL (e.g.,
+ ``wsgiorg.routing_args``).
+ """
+ if 'paste.urlvars' in self.environ:
+ return self.environ['paste.urlvars']
+ elif 'wsgiorg.routing_args' in self.environ:
+ return self.environ['wsgiorg.routing_args'][1]
+ else:
+ return {}
+ urlvars = property(urlvars, doc=urlvars.__doc__)
+
+ def is_xhr(self):
+ """Returns a boolean if X-Requested-With is present and a XMLHttpRequest"""
+ return self.environ.get('HTTP_X_REQUESTED_WITH', '') == 'XMLHttpRequest'
+ is_xhr = property(is_xhr, doc=is_xhr.__doc__)
+
+ def host(self):
+ """Host name provided in HTTP_HOST, with fall-back to SERVER_NAME"""
+ return self.environ.get('HTTP_HOST', self.environ.get('SERVER_NAME'))
+ host = property(host, doc=host.__doc__)
+
+ def languages(self):
+ """Return a list of preferred languages, most preferred first.
+
+ The list may be empty.
+ """
+ if self._languages is not None:
+ return self._languages
+ acceptLanguage = self.environ.get('HTTP_ACCEPT_LANGUAGE')
+ langs = ACCEPT_LANGUAGE.parse(self.environ)
+ fallback = self.defaults.get('language', 'en-us')
+ if not fallback:
+ return langs
+ if fallback not in langs:
+ langs.append(fallback)
+ index = langs.index(fallback)
+ langs[index+1:] = []
+ self._languages = langs
+ return self._languages
+ languages = property(languages, doc=languages.__doc__)
+
+ def _GET(self):
+ return parse_dict_querystring(self.environ)
+
+ def GET(self):
+ """
+ Dictionary-like object representing the QUERY_STRING
+ parameters. Always present, if possibly empty.
+
+ If the same key is present in the query string multiple times, a
+ list of its values can be retrieved from the ``MultiDict`` via
+ the ``getall`` method.
+
+ Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
+ ``charset`` is set.
+ """
+ params = self._GET()
+ if self.charset:
+ params = UnicodeMultiDict(params, encoding=self.charset,
+ errors=self.errors,
+ decode_keys=self.decode_param_names)
+ return params
+ GET = property(GET, doc=GET.__doc__)
+
+ def _POST(self):
+ return parse_formvars(self.environ, include_get_vars=False)
+
+ def POST(self):
+ """Dictionary-like object representing the POST body.
+
+ Most values are encoded strings, or unicode strings when
+ ``charset`` is set. There may also be FieldStorage objects
+ representing file uploads. If this is not a POST request, or the
+ body is not encoded fields (e.g., an XMLRPC request) then this
+ will be empty.
+
+ This will consume wsgi.input when first accessed if applicable,
+ but the raw version will be put in
+ environ['paste.parsed_formvars'].
+
+ Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
+ ``charset`` is set.
+ """
+ params = self._POST()
+ if self.charset:
+ params = UnicodeMultiDict(params, encoding=self.charset,
+ errors=self.errors,
+ decode_keys=self.decode_param_names)
+ return params
+ POST = property(POST, doc=POST.__doc__)
+
+ def params(self):
+ """Dictionary-like object of keys from POST, GET, URL dicts
+
+ Return a key value from the parameters, they are checked in the
+ following order: POST, GET, URL
+
+ Additional methods supported:
+
+ ``getlist(key)``
+ Returns a list of all the values by that key, collected from
+ POST, GET, URL dicts
+
+ Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
+ ``charset`` is set.
+ """
+ params = MultiDict()
+ params.update(self._POST())
+ params.update(self._GET())
+ if self.charset:
+ params = UnicodeMultiDict(params, encoding=self.charset,
+ errors=self.errors,
+ decode_keys=self.decode_param_names)
+ return params
+ params = property(params, doc=params.__doc__)
+
+ def cookies(self):
+ """Dictionary of cookies keyed by cookie name.
+
+ Just a plain dictionary, may be empty but not None.
+
+ """
+ return get_cookie_dict(self.environ)
+ cookies = property(cookies, doc=cookies.__doc__)
+
+ def determine_browser_charset(self):
+ """
+ Determine the encoding as specified by the browser via the
+ Content-Type's charset parameter, if one is set
+ """
+ charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', ''))
+ if charset_match:
+ return charset_match.group(1)
+
+ def match_accept(self, mimetypes):
+ """Return a list of specified mime-types that the browser's HTTP Accept
+ header allows in the order provided."""
+ return desired_matches(mimetypes,
+ self.environ.get('HTTP_ACCEPT', '*/*'))
+
+ def __repr__(self):
+ """Show important attributes of the WSGIRequest"""
+ pf = pformat
+ msg = '<%s.%s object at 0x%x method=%s,' % \
+ (self.__class__.__module__, self.__class__.__name__,
+ id(self), pf(self.method))
+ msg += '\nscheme=%s, host=%s, script_name=%s, path_info=%s,' % \
+ (pf(self.scheme), pf(self.host), pf(self.script_name),
+ pf(self.path_info))
+ msg += '\nlanguages=%s,' % pf(self.languages)
+ if self.charset:
+ msg += ' charset=%s, errors=%s,' % (pf(self.charset),
+ pf(self.errors))
+ msg += '\nGET=%s,' % pf(self.GET)
+ msg += '\nPOST=%s,' % pf(self.POST)
+ msg += '\ncookies=%s>' % pf(self.cookies)
+ return msg
+
+class WSGIResponse(object):
+ """A basic HTTP response with content, headers, and out-bound cookies
+
+ The class variable ``defaults`` specifies default values for
+ ``content_type``, ``charset`` and ``errors``. These can be overridden
+ for the current request via the registry.
+
+ """
+ defaults = StackedObjectProxy(
+ default=dict(content_type='text/html', charset='utf-8',
+ errors='strict', headers={'Cache-Control':'no-cache'})
+ )
+ def __init__(self, content='', mimetype=None, code=200):
+ self._iter = None
+ self._is_str_iter = True
+
+ self.content = content
+ self.headers = HeaderDict()
+ self.cookies = SimpleCookie()
+ self.status_code = code
+
+ defaults = self.defaults._current_obj()
+ if not mimetype:
+ mimetype = defaults.get('content_type', 'text/html')
+ charset = defaults.get('charset')
+ if charset:
+ mimetype = '%s; charset=%s' % (mimetype, charset)
+ self.headers.update(defaults.get('headers', {}))
+ self.headers['Content-Type'] = mimetype
+ self.errors = defaults.get('errors', 'strict')
+
+ def __str__(self):
+ """Returns a rendition of the full HTTP message, including headers.
+
+ When the content is an iterator, the actual content is replaced with the
+ output of str(iterator) (to avoid exhausting the iterator).
+ """
+ if self._is_str_iter:
+ content = ''.join(self.get_content())
+ else:
+ content = str(self.content)
+ return '\n'.join(['%s: %s' % (key, value)
+ for key, value in self.headers.headeritems()]) \
+ + '\n\n' + content
+
+ def __call__(self, environ, start_response):
+ """Convenience call to return output and set status information
+
+ Conforms to the WSGI interface for calling purposes only.
+
+ Example usage:
+
+ .. code-block:: python
+
+ def wsgi_app(environ, start_response):
+ response = WSGIResponse()
+ response.write("Hello world")
+ response.headers['Content-Type'] = 'latin1'
+ return response(environ, start_response)
+
+ """
+ status_text = STATUS_CODE_TEXT[self.status_code]
+ status = '%s %s' % (self.status_code, status_text)
+ response_headers = self.headers.headeritems()
+ for c in self.cookies.values():
+ response_headers.append(('Set-Cookie', c.output(header='')))
+ start_response(status, response_headers)
+ is_file = isinstance(self.content, file)
+ if 'wsgi.file_wrapper' in environ and is_file:
+ return environ['wsgi.file_wrapper'](self.content)
+ elif is_file:
+ return iter(lambda: self.content.read(), '')
+ return self.get_content()
+
+ def determine_charset(self):
+ """
+ Determine the encoding as specified by the Content-Type's charset
+ parameter, if one is set
+ """
+ charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', ''))
+ if charset_match:
+ return charset_match.group(1)
+
+ def has_header(self, header):
+ """
+ Case-insensitive check for a header
+ """
+ warnings.warn('WSGIResponse.has_header is deprecated, use '
+ 'WSGIResponse.headers.has_key instead', DeprecationWarning,
+ 2)
+ return self.headers.has_key(header)
+
+ def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
+ domain=None, secure=None, httponly=None):
+ """
+ Define a cookie to be sent via the outgoing HTTP headers
+ """
+ self.cookies[key] = value
+ for var_name, var_value in [
+ ('max_age', max_age), ('path', path), ('domain', domain),
+ ('secure', secure), ('expires', expires), ('httponly', httponly)]:
+ if var_value is not None and var_value is not False:
+ self.cookies[key][var_name.replace('_', '-')] = var_value
+
+ def delete_cookie(self, key, path='/', domain=None):
+ """
+ Notify the browser the specified cookie has expired and should be
+ deleted (via the outgoing HTTP headers)
+ """
+ self.cookies[key] = ''
+ if path is not None:
+ self.cookies[key]['path'] = path
+ if domain is not None:
+ self.cookies[key]['domain'] = domain
+ self.cookies[key]['expires'] = 0
+ self.cookies[key]['max-age'] = 0
+
+ def _set_content(self, content):
+ if hasattr(content, '__iter__'):
+ self._iter = content
+ if isinstance(content, list):
+ self._is_str_iter = True
+ else:
+ self._is_str_iter = False
+ else:
+ self._iter = [content]
+ self._is_str_iter = True
+ content = property(lambda self: self._iter, _set_content,
+ doc='Get/set the specified content, where content can '
+ 'be: a string, a list of strings, a generator function '
+ 'that yields strings, or an iterable object that '
+ 'produces strings.')
+
+ def get_content(self):
+ """
+ Returns the content as an iterable of strings, encoding each element of
+ the iterator from a Unicode object if necessary.
+ """
+ charset = self.determine_charset()
+ if charset:
+ return encode_unicode_app_iter(self.content, charset, self.errors)
+ else:
+ return self.content
+
+ def wsgi_response(self):
+ """
+ Return this WSGIResponse as a tuple of WSGI formatted data, including:
+ (status, headers, iterable)
+ """
+ status_text = STATUS_CODE_TEXT[self.status_code]
+ status = '%s %s' % (self.status_code, status_text)
+ response_headers = self.headers.headeritems()
+ for c in self.cookies.values():
+ response_headers.append(('Set-Cookie', c.output(header='')))
+ return status, response_headers, self.get_content()
+
+ # The remaining methods partially implement the file-like object interface.
+ # See http://docs.python.org/lib/bltin-file-objects.html
+ def write(self, content):
+ if not self._is_str_iter:
+ raise IOError, "This %s instance's content is not writable: (content " \
+ 'is an iterator)' % self.__class__.__name__
+ self.content.append(content)
+
+ def flush(self):
+ pass
+
+ def tell(self):
+ if not self._is_str_iter:
+ raise IOError, 'This %s instance cannot tell its position: (content ' \
+ 'is an iterator)' % self.__class__.__name__
+ return sum([len(chunk) for chunk in self._iter])
+
+ ########################################
+ ## Content-type and charset
+
+ def charset__get(self):
+ """
+ Get/set the charset (in the Content-Type)
+ """
+ header = self.headers.get('content-type')
+ if not header:
+ return None
+ match = _CHARSET_RE.search(header)
+ if match:
+ return match.group(1)
+ return None
+
+ def charset__set(self, charset):
+ if charset is None:
+ del self.charset
+ return
+ try:
+ header = self.headers.pop('content-type')
+ except KeyError:
+ raise AttributeError(
+ "You cannot set the charset when no content-type is defined")
+ match = _CHARSET_RE.search(header)
+ if match:
+ header = header[:match.start()] + header[match.end():]
+ header += '; charset=%s' % charset
+ self.headers['content-type'] = header
+
+ def charset__del(self):
+ try:
+ header = self.headers.pop('content-type')
+ except KeyError:
+ # Don't need to remove anything
+ return
+ match = _CHARSET_RE.search(header)
+ if match:
+ header = header[:match.start()] + header[match.end():]
+ self.headers['content-type'] = header
+
+ charset = property(charset__get, charset__set, charset__del, doc=charset__get.__doc__)
+
+ def content_type__get(self):
+ """
+ Get/set the Content-Type header (or None), *without* the
+ charset or any parameters.
+
+ If you include parameters (or ``;`` at all) when setting the
+ content_type, any existing parameters will be deleted;
+ otherwise they will be preserved.
+ """
+ header = self.headers.get('content-type')
+ if not header:
+ return None
+ return header.split(';', 1)[0]
+
+ def content_type__set(self, value):
+ if ';' not in value:
+ header = self.headers.get('content-type', '')
+ if ';' in header:
+ params = header.split(';', 1)[1]
+ value += ';' + params
+ self.headers['content-type'] = value
+
+ def content_type__del(self):
+ try:
+ del self.headers['content-type']
+ except KeyError:
+ pass
+
+ content_type = property(content_type__get, content_type__set,
+ content_type__del, doc=content_type__get.__doc__)
+
+## @@ I'd love to remove this, but paste.httpexceptions.get_exception
+## doesn't seem to work...
+# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+STATUS_CODE_TEXT = {
+ 100: 'CONTINUE',
+ 101: 'SWITCHING PROTOCOLS',
+ 200: 'OK',
+ 201: 'CREATED',
+ 202: 'ACCEPTED',
+ 203: 'NON-AUTHORITATIVE INFORMATION',
+ 204: 'NO CONTENT',
+ 205: 'RESET CONTENT',
+ 206: 'PARTIAL CONTENT',
+ 226: 'IM USED',
+ 300: 'MULTIPLE CHOICES',
+ 301: 'MOVED PERMANENTLY',
+ 302: 'FOUND',
+ 303: 'SEE OTHER',
+ 304: 'NOT MODIFIED',
+ 305: 'USE PROXY',
+ 306: 'RESERVED',
+ 307: 'TEMPORARY REDIRECT',
+ 400: 'BAD REQUEST',
+ 401: 'UNAUTHORIZED',
+ 402: 'PAYMENT REQUIRED',
+ 403: 'FORBIDDEN',
+ 404: 'NOT FOUND',
+ 405: 'METHOD NOT ALLOWED',
+ 406: 'NOT ACCEPTABLE',
+ 407: 'PROXY AUTHENTICATION REQUIRED',
+ 408: 'REQUEST TIMEOUT',
+ 409: 'CONFLICT',
+ 410: 'GONE',
+ 411: 'LENGTH REQUIRED',
+ 412: 'PRECONDITION FAILED',
+ 413: 'REQUEST ENTITY TOO LARGE',
+ 414: 'REQUEST-URI TOO LONG',
+ 415: 'UNSUPPORTED MEDIA TYPE',
+ 416: 'REQUESTED RANGE NOT SATISFIABLE',
+ 417: 'EXPECTATION FAILED',
+ 500: 'INTERNAL SERVER ERROR',
+ 501: 'NOT IMPLEMENTED',
+ 502: 'BAD GATEWAY',
+ 503: 'SERVICE UNAVAILABLE',
+ 504: 'GATEWAY TIMEOUT',
+ 505: 'HTTP VERSION NOT SUPPORTED',
+}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+Metadata-Version: 1.0
+Name: PasteDeploy
+Version: 1.3.4
+Summary: Load, configure, and compose WSGI applications and servers
+Home-page: http://pythonpaste.org/deploy/
+Author: Ian Bicking
+Author-email: ianb at colorstudy.com
+License: MIT
+Description: This tool provides code to load WSGI applications and servers from
+ URIs; these URIs can refer to Python Eggs for INI-style configuration
+ files. `Paste Script <http://pythonpaste.org/script>`_ provides
+ commands to serve applications based on this configuration file.
+
+ The latest version is available in a `Mercurial repository
+ <http://bitbucket.org/ianb/pastedeploy>`_ (or a `tarball
+ <http://bitbucket.org/ianb/pastedeploy/get/tip.gz#egg=PasteDeploy-dev>`_).
+
+ For the latest changes see the `news file
+ <http://pythonpaste.org/deploy/news.html>`_.
+
+Keywords: web wsgi application server
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
+Classifier: Framework :: Paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+MANIFEST.in
+setup.cfg
+setup.py
+PasteDeploy.egg-info/PKG-INFO
+PasteDeploy.egg-info/SOURCES.txt
+PasteDeploy.egg-info/dependency_links.txt
+PasteDeploy.egg-info/entry_points.txt
+PasteDeploy.egg-info/namespace_packages.txt
+PasteDeploy.egg-info/not-zip-safe
+PasteDeploy.egg-info/requires.txt
+PasteDeploy.egg-info/top_level.txt
+docs/index.txt
+docs/license.txt
+docs/news.txt
+paste/__init__.py
+paste/deploy/__init__.py
+paste/deploy/config.py
+paste/deploy/converters.py
+paste/deploy/epdesc.py
+paste/deploy/interfaces.py
+paste/deploy/loadwsgi.py
+paste/deploy/paster_templates.py
+paste/deploy/util/__init__.py
+paste/deploy/util/fixtypeerror.py
+paste/deploy/util/threadinglocal.py
+tests/__init__.py
+tests/finddata.py
+tests/fixture.py
+tests/test_basic_app.py
+tests/test_config.py
+tests/test_config_middleware.py
+tests/test_filter.py
+tests/test_load_package.py
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/entry_points.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/entry_points.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/entry_points.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+
+ [paste.filter_app_factory]
+ config = paste.deploy.config:make_config_filter [Config]
+ prefix = paste.deploy.config:make_prefix_middleware
+
+ [paste.paster_create_template]
+ paste_deploy=paste.deploy.paster_templates:PasteDeploy
+
+ [paste.entry_point_description]
+ paste.app_factory = paste.deploy.epdesc:AppFactoryDescription
+ paste.composit_factory = paste.deploy.epdesc:CompositeFactoryDescription
+ paste.composite_factory = paste.deploy.epdesc:CompositeFactoryDescription
+ paste.filter_app_factory = paste.deploy.epdesc:FilterAppFactoryDescription
+ paste.filter_factory = paste.deploy.epdesc:FilterFactoryDescription
+ paste.server_factory = paste.deploy.epdesc:ServerFactoryDescription
+ paste.server_runner = paste.deploy.epdesc:ServerRunnerDescription
+
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/namespace_packages.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/namespace_packages.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/namespace_packages.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/requires.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/requires.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/requires.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+
+
+[Paste]
+Paste
+
+[Config]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+tests
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ # don't prevent use of paste if pkg_resources isn't installed
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
+
+try:
+ import modulefinder
+except ImportError:
+ pass
+else:
+ for p in __path__:
+ modulefinder.AddPackagePath(__name__, p)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+from loadwsgi import *
+try:
+ from config import CONFIG
+except ImportError:
+ # @@: Or should we require Paste? Or should we put threadlocal
+ # into this package too?
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/config.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/config.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/config.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,298 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""Paste Configuration Middleware and Objects"""
+import threading
+import re
+# Loaded lazily
+wsgilib = None
+local = None
+
+__all__ = ['DispatchingConfig', 'CONFIG', 'ConfigMiddleware', 'PrefixMiddleware']
+
+def local_dict():
+ global config_local, local
+ try:
+ return config_local.wsgi_dict
+ except NameError:
+ from paste.deploy.util.threadinglocal import local
+ config_local = local()
+ config_local.wsgi_dict = result = {}
+ return result
+ except AttributeError:
+ config_local.wsgi_dict = result = {}
+ return result
+
+class DispatchingConfig(object):
+
+ """
+ This is a configuration object that can be used globally,
+ imported, have references held onto. The configuration may differ
+ by thread (or may not).
+
+ Specific configurations are registered (and deregistered) either
+ for the process or for threads.
+ """
+
+ # @@: What should happen when someone tries to add this
+ # configuration to itself? Probably the conf should become
+ # resolved, and get rid of this delegation wrapper
+
+ _constructor_lock = threading.Lock()
+
+ def __init__(self):
+ self._constructor_lock.acquire()
+ try:
+ self.dispatching_id = 0
+ while 1:
+ self._local_key = 'paste.processconfig_%i' % self.dispatching_id
+ if not local_dict().has_key(self._local_key):
+ break
+ self.dispatching_id += 1
+ finally:
+ self._constructor_lock.release()
+ self._process_configs = []
+
+ def push_thread_config(self, conf):
+ """
+ Make ``conf`` the active configuration for this thread.
+ Thread-local configuration always overrides process-wide
+ configuration.
+
+ This should be used like::
+
+ conf = make_conf()
+ dispatching_config.push_thread_config(conf)
+ try:
+ ... do stuff ...
+ finally:
+ dispatching_config.pop_thread_config(conf)
+ """
+ local_dict().setdefault(self._local_key, []).append(conf)
+
+ def pop_thread_config(self, conf=None):
+ """
+ Remove a thread-local configuration. If ``conf`` is given,
+ it is checked against the popped configuration and an error
+ is emitted if they don't match.
+ """
+ self._pop_from(local_dict()[self._local_key], conf)
+
+ def _pop_from(self, lst, conf):
+ popped = lst.pop()
+ if conf is not None and popped is not conf:
+ raise AssertionError(
+ "The config popped (%s) is not the same as the config "
+ "expected (%s)"
+ % (popped, conf))
+
+ def push_process_config(self, conf):
+ """
+ Like push_thread_config, but applies the configuration to
+ the entire process.
+ """
+ self._process_configs.append(conf)
+
+ def pop_process_config(self, conf=None):
+ self._pop_from(self._process_configs, conf)
+
+ def __getattr__(self, attr):
+ conf = self.current_conf()
+ if conf is None:
+ raise AttributeError(
+ "No configuration has been registered for this process "
+ "or thread")
+ return getattr(conf, attr)
+
+ def current_conf(self):
+ thread_configs = local_dict().get(self._local_key)
+ if thread_configs:
+ return thread_configs[-1]
+ elif self._process_configs:
+ return self._process_configs[-1]
+ else:
+ return None
+
+ def __getitem__(self, key):
+ # I thought __getattr__ would catch this, but apparently not
+ conf = self.current_conf()
+ if conf is None:
+ raise TypeError(
+ "No configuration has been registered for this process "
+ "or thread")
+ return conf[key]
+
+ def __contains__(self, key):
+ # I thought __getattr__ would catch this, but apparently not
+ return self.has_key(key)
+
+ def __setitem__(self, key, value):
+ # I thought __getattr__ would catch this, but apparently not
+ conf = self.current_conf()
+ conf[key] = value
+
+CONFIG = DispatchingConfig()
+
+class ConfigMiddleware(object):
+
+ """
+ A WSGI middleware that adds a ``paste.config`` key to the request
+ environment, as well as registering the configuration temporarily
+ (for the length of the request) with ``paste.CONFIG``.
+ """
+
+ def __init__(self, application, config):
+ """
+ This delegates all requests to `application`, adding a *copy*
+ of the configuration `config`.
+ """
+ self.application = application
+ self.config = config
+
+ def __call__(self, environ, start_response):
+ global wsgilib
+ if wsgilib is None:
+ import pkg_resources
+ pkg_resources.require('Paste')
+ from paste import wsgilib
+ popped_config = None
+ if 'paste.config' in environ:
+ popped_config = environ['paste.config']
+ conf = environ['paste.config'] = self.config.copy()
+ app_iter = None
+ CONFIG.push_thread_config(conf)
+ try:
+ app_iter = self.application(environ, start_response)
+ finally:
+ if app_iter is None:
+ # An error occurred...
+ CONFIG.pop_thread_config(conf)
+ if popped_config is not None:
+ environ['paste.config'] = popped_config
+ if type(app_iter) in (list, tuple):
+ # Because it is a concrete iterator (not a generator) we
+ # know the configuration for this thread is no longer
+ # needed:
+ CONFIG.pop_thread_config(conf)
+ if popped_config is not None:
+ environ['paste.config'] = popped_config
+ return app_iter
+ else:
+ def close_config():
+ CONFIG.pop_thread_config(conf)
+ new_app_iter = wsgilib.add_close(app_iter, close_config)
+ return new_app_iter
+
+def make_config_filter(app, global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return ConfigMiddleware(app, conf)
+
+make_config_middleware = ConfigMiddleware.__doc__
+
+class PrefixMiddleware(object):
+ """Translate a given prefix into a SCRIPT_NAME for the filtered
+ application.
+
+ PrefixMiddleware provides a way to manually override the root prefix
+ (SCRIPT_NAME) of your application for certain, rare situations.
+
+ When running an application under a prefix (such as '/james') in
+ FastCGI/apache, the SCRIPT_NAME environment variable is automatically
+ set to to the appropriate value: '/james'. Pylons' URL generating
+ functions, such as url_for, always take the SCRIPT_NAME value into account.
+
+ One situation where PrefixMiddleware is required is when an application
+ is accessed via a reverse proxy with a prefix. The application is accessed
+ through the reverse proxy via the the URL prefix '/james', whereas the
+ reverse proxy forwards those requests to the application at the prefix '/'.
+
+ The reverse proxy, being an entirely separate web server, has no way of
+ specifying the SCRIPT_NAME variable; it must be manually set by a
+ PrefixMiddleware instance. Without setting SCRIPT_NAME, url_for will
+ generate URLs such as: '/purchase_orders/1', when it should be
+ generating: '/james/purchase_orders/1'.
+
+ To filter your application through a PrefixMiddleware instance, add the
+ following to the '[app:main]' section of your .ini file:
+
+ .. code-block:: ini
+
+ filter-with = proxy-prefix
+
+ [filter:proxy-prefix]
+ use = egg:PasteDeploy#prefix
+ prefix = /james
+
+ The name ``proxy-prefix`` simply acts as an identifier of the filter
+ section; feel free to rename it.
+
+ Also, unless disabled, the ``X-Forwarded-Server`` header will be
+ translated to the ``Host`` header, for cases when that header is
+ lost in the proxying. Also ``X-Forwarded-Host``,
+ ``X-Forwarded-Scheme``, and ``X-Forwarded-Proto`` are translated.
+
+ If ``force_port`` is set, SERVER_PORT and HTTP_HOST will be
+ rewritten with the given port. You can use a number, string (like
+ '80') or the empty string (whatever is the default port for the
+ scheme). This is useful in situations where there is port
+ forwarding going on, and the server believes itself to be on a
+ different port than what the outside world sees.
+
+ You can also use ``scheme`` to explicitly set the scheme (like
+ ``scheme = https``).
+ """
+ def __init__(self, app, global_conf=None, prefix='/',
+ translate_forwarded_server=True,
+ force_port=None, scheme=None):
+ self.app = app
+ self.prefix = prefix.rstrip('/')
+ self.translate_forwarded_server = translate_forwarded_server
+ self.regprefix = re.compile("^%s(.*)$" % self.prefix)
+ self.force_port = force_port
+ self.scheme = scheme
+
+ def __call__(self, environ, start_response):
+ url = environ['PATH_INFO']
+ url = re.sub(self.regprefix, r'\1', url)
+ if not url: url = '/'
+ environ['PATH_INFO'] = url
+ environ['SCRIPT_NAME'] = self.prefix
+ if self.translate_forwarded_server:
+ if 'HTTP_X_FORWARDED_SERVER' in environ:
+ environ['SERVER_NAME'] = environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_SERVER').split(',')[0]
+ if 'HTTP_X_FORWARDED_HOST' in environ:
+ environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_HOST').split(',')[0]
+ if 'HTTP_X_FORWARDED_FOR' in environ:
+ environ['REMOTE_ADDR'] = environ.pop('HTTP_X_FORWARDED_FOR')
+ if 'HTTP_X_FORWARDED_SCHEME' in environ:
+ environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_SCHEME')
+ elif 'HTTP_X_FORWARDED_PROTO' in environ:
+ environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_PROTO')
+ if self.force_port is not None:
+ host = environ.get('HTTP_HOST', '').split(':', 1)[0]
+ if self.force_port:
+ host = '%s:%s' % (host, self.force_port)
+ environ['SERVER_PORT'] = str(self.force_port)
+ else:
+ if environ['wsgi.url_scheme'] == 'http':
+ port = '80'
+ else:
+ port = '443'
+ environ['SERVER_PORT'] = port
+ environ['HTTP_HOST'] = host
+ if self.scheme is not None:
+ environ['wsgi.url_scheme'] = self.scheme
+ return self.app(environ, start_response)
+
+def make_prefix_middleware(
+ app, global_conf, prefix='/',
+ translate_forwarded_server=True,
+ force_port=None, scheme=None):
+ from paste.deploy.converters import asbool
+ translate_forwarded_server = asbool(translate_forwarded_server)
+ return PrefixMiddleware(
+ app, prefix=prefix,
+ translate_forwarded_server=translate_forwarded_server,
+ force_port=force_port, scheme=scheme)
+
+make_prefix_middleware.__doc__ = PrefixMiddleware.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/converters.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/converters.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/converters.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+def asbool(obj):
+ if isinstance(obj, (str, unicode)):
+ obj = obj.strip().lower()
+ if obj in ['true', 'yes', 'on', 'y', 't', '1']:
+ return True
+ elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
+ return False
+ else:
+ raise ValueError(
+ "String is not true/false: %r" % obj)
+ return bool(obj)
+
+def asint(obj):
+ try:
+ return int(obj)
+ except (TypeError, ValueError), e:
+ raise ValueError(
+ "Bad integer value: %r" % obj)
+
+def aslist(obj, sep=None, strip=True):
+ if isinstance(obj, (str, unicode)):
+ lst = obj.split(sep)
+ if strip:
+ lst = [v.strip() for v in lst]
+ return lst
+ elif isinstance(obj, (list, tuple)):
+ return obj
+ elif obj is None:
+ return []
+ else:
+ return [obj]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/epdesc.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/epdesc.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/epdesc.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,37 @@
+class AppFactoryDescription(object):
+ description = """
+ This gives a factory/function that can create WSGI apps
+ """
+
+class CompositeFactoryDescription(object):
+ description = """
+ This gives a factory/function that can create WSGI apps, and has
+ access to the application creator so that it can in turn fetch
+ apps based on name.
+ """
+
+class FilterAppFactoryDescription(object):
+ description = """
+ This gives a factory/function that wraps a WSGI application to
+ create another WSGI application (typically applying middleware)
+ """
+
+class FilterFactoryDescription(object):
+ description = """
+ This gives a factory/function that return a function that can wrap
+ a WSGI application and returns another WSGI application.
+ paste.filter_app_factory is the same thing with less layers.
+ """
+
+class ServerFactoryDescription(object):
+ description = """
+ This gives a factory/function that creates a server, that can be
+ called with a WSGI application to run indefinitely.
+ paste.server_runner is the same thing with less layers.
+ """
+
+class ServerRunnerDescription(object):
+ description = """
+ This gives a factory/function that, given a WSGI application and
+ configuration, will serve the application indefinitely.
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/interfaces.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/interfaces.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/interfaces.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,202 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+############################################################
+## Functions
+############################################################
+
+def loadapp(uri, name=None, relative_to=None, global_conf=None):
+ """
+ Provided by ``paste.deploy.loadapp``.
+
+ Load the specified URI as a WSGI application (returning IWSGIApp).
+ The ``name`` can be in the URI (typically as ``#name``). If it is
+ and ``name`` is given, the keyword argument overrides the URI.
+
+ If the URI contains a relative filename, then ``relative_to`` is
+ used (if ``relative_to`` is not provided, then it is an error).
+
+ ``global_conf`` is used to load the configuration (additions
+ override the values). ``global_conf`` is copied before modifying.
+ """
+
+def loadfilter(uri, name=None, relative_to=None, global_conf=None):
+ """
+ Provided by ``paste.deploy.loadfilter``.
+
+ Like ``loadapp()``, except returns in IFilter object.
+ """
+
+def loadserver(uri, name=None, relative_to=None, global_conf=None):
+ """
+ Provided by ``paste.deploy.loadserver``.
+
+ Like ``loadapp()``, except returns in IServer object.
+ """
+
+############################################################
+## Factories
+############################################################
+
+class IPasteAppFactory(object):
+
+ """
+ This is the spec for the ``paste.app_factory``
+ protocol/entry_point.
+ """
+
+ def __call__(global_conf, **local_conf):
+ """
+ Returns a WSGI application (IWSGIAPP) given the global
+ configuration and the local configuration passed in as keyword
+ arguments.
+
+ All keys are strings, but values in local_conf may not be
+ valid Python identifiers (if you use ``**kw`` you can still
+ capture these values).
+ """
+
+class IPasteCompositFactory(object):
+
+ """
+ This is the spec for the ``paste.composit_factory``
+ protocol/entry_point.
+
+ This also produces WSGI applications, like ``paste.app_factory``,
+ but is given more access to the context in which it is loaded.
+ """
+
+ def __call__(loader, global_conf, **local_conf):
+ """
+ Like IPasteAppFactory this returns a WSGI application
+ (IWSGIApp). The ``loader`` value conforms to the ``ILoader``
+ interface, and can be used to load (contextually) more
+ applications.
+ """
+
+class IPasteFilterFactory(object):
+
+ """
+ This is the spec for the ``paste.filter_factory``
+ protocol/entry_point.
+ """
+
+ def __call__(global_conf, **local_conf):
+ """
+ Returns a IFilter object.
+ """
+
+class IPasteFilterAppFactory(object):
+
+ """
+ This is the spec for the ``paste.filter_app_factory``
+ protocol/entry_point.
+ """
+
+ def __call__(wsgi_app, global_conf, **local_conf):
+ """
+ Returns a WSGI application that wraps ``wsgi_app``.
+
+ Note that paste.deploy creates a wrapper for these
+ objects that implement the IFilter interface.
+ """
+
+class IPasteServerFactory(object):
+
+ """
+ This is the spec for the ``paste.server_factory``
+ protocol/entry_point.
+ """
+
+ def __call__(global_conf, **local_conf):
+ """
+ Returns a IServer object.
+ """
+
+class IPasteServerRunner(object):
+
+ """
+ This is the spec for the ``paste.server_runner``
+ protocol/entry_point.
+ """
+
+ def __call__(wsgi_app, global_conf, **local_conf):
+ """
+ Serves the given WSGI application. May serve once, many
+ times, forever; nothing about how the server works is
+ specified here.
+
+ Note that paste.deploy creates a wrapper for these
+ objects that implement the IServer interface.
+ """
+
+class ILoader(object):
+
+ """
+ This is an object passed into ``IPasteCompositFactory``. It is
+ currently implemented in ``paste.deploy.loadwsgi`` by
+ ``ConfigLoader`` and ``EggLoader``.
+ """
+
+ def get_app(name_or_uri, global_conf=None):
+ """
+ Return an IWSGIApp object. If the loader supports named
+ applications, then you can use a simple name; otherwise
+ you must use a full URI.
+
+ Any global configuration you pass in will be added; you should
+ generally pass through the global configuration you received.
+ """
+
+ def get_filter(name_or_uri, global_conf=None):
+ """
+ Return an IFilter object, like ``get_app``.
+ """
+
+ def get_server(name_or_uri, global_conf=None):
+ """
+ Return an IServer object, like ``get_app``.
+ """
+
+############################################################
+## Objects
+############################################################
+
+class IWSGIApp(object):
+
+ """
+ This is an application that conforms to `PEP 333
+ <http://www.python.org/peps/pep-0333.html>`_: Python Web Server
+ Gateway Interface v1.0
+ """
+
+ def __call__(environ, start_response):
+ """
+ Calls ``start_response(status_code, header_list)`` and returns
+ an iterator for the body of the response.
+ """
+
+class IFilter(object):
+
+ """
+ A filter is a simple case of middleware, where an object
+ wraps a single WSGI application (IWSGIApp).
+ """
+
+ def __call__(wsgi_app):
+ """
+ Returns an IWSGIApp object, typically one that wraps the
+ ``wsgi_app`` passed in.
+ """
+
+class IServer(object):
+
+ """
+ A simple server interface.
+ """
+
+ def __call__(wsgi_app):
+ """
+ Serves the given WSGI application. May serve once, many
+ times, forever; nothing about how the server works is
+ specified here.
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/loadwsgi.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/loadwsgi.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/loadwsgi.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,631 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import re
+import urllib
+from ConfigParser import ConfigParser
+import pkg_resources
+from paste.deploy.util.fixtypeerror import fix_call
+
+__all__ = ['loadapp', 'loadserver', 'loadfilter', 'appconfig']
+
+############################################################
+## Utility functions
+############################################################
+
+def import_string(s):
+ return pkg_resources.EntryPoint.parse("x="+s).load(False)
+
+def _aslist(obj):
+ """
+ Turn object into a list; lists and tuples are left as-is, None
+ becomes [], and everything else turns into a one-element list.
+ """
+ if obj is None:
+ return []
+ elif isinstance(obj, (list, tuple)):
+ return obj
+ else:
+ return [obj]
+
+def _flatten(lst):
+ """
+ Flatten a nested list.
+ """
+ if not isinstance(lst, (list, tuple)):
+ return [lst]
+ result = []
+ for item in lst:
+ result.extend(_flatten(item))
+ return result
+
+class NicerConfigParser(ConfigParser):
+
+ def __init__(self, filename, *args, **kw):
+ ConfigParser.__init__(self, *args, **kw)
+ self.filename = filename
+
+ def defaults(self):
+ """Return the defaults, with their values interpolated (with the
+ defaults dict itself)
+
+ Mainly to support defaults using values such as %(here)s
+ """
+ defaults = ConfigParser.defaults(self).copy()
+ for key, val in defaults.iteritems():
+ defaults[key] = self._interpolate('DEFAULT', key, val, defaults)
+ return defaults
+
+ def _interpolate(self, section, option, rawval, vars):
+ try:
+ return ConfigParser._interpolate(
+ self, section, option, rawval, vars)
+ except Exception, e:
+ args = list(e.args)
+ args[0] = 'Error in file %s, [%s] %s=%r: %s' % (
+ self.filename, section, option, rawval, e)
+ e.args = tuple(args)
+ raise
+
+############################################################
+## Object types
+############################################################
+
+class _ObjectType(object):
+
+ name = None
+ egg_protocols = None
+ config_prefixes = None
+
+ def __init__(self):
+ # Normalize these variables:
+ self.egg_protocols = map(_aslist, _aslist(self.egg_protocols))
+ self.config_prefixes = map(_aslist, _aslist(self.config_prefixes))
+
+ def __repr__(self):
+ return '<%s protocols=%r prefixes=%r>' % (
+ self.name, self.egg_protocols, self.config_prefixes)
+
+ def invoke(self, context):
+ assert context.protocol in _flatten(self.egg_protocols)
+ return fix_call(context.object,
+ context.global_conf, **context.local_conf)
+
+class _App(_ObjectType):
+
+ name = 'application'
+ egg_protocols = ['paste.app_factory', 'paste.composite_factory',
+ 'paste.composit_factory']
+ config_prefixes = [['app', 'application'], ['composite', 'composit'],
+ 'pipeline', 'filter-app']
+
+ def invoke(self, context):
+ if context.protocol in ('paste.composit_factory',
+ 'paste.composite_factory'):
+ return fix_call(context.object,
+ context.loader, context.global_conf,
+ **context.local_conf)
+ elif context.protocol == 'paste.app_factory':
+ return fix_call(context.object, context.global_conf, **context.local_conf)
+ else:
+ assert 0, "Protocol %r unknown" % context.protocol
+
+APP = _App()
+
+class _Filter(_ObjectType):
+ name = 'filter'
+ egg_protocols = [['paste.filter_factory', 'paste.filter_app_factory']]
+ config_prefixes = ['filter']
+
+ def invoke(self, context):
+ if context.protocol == 'paste.filter_factory':
+ return fix_call(context.object,
+ context.global_conf, **context.local_conf)
+ elif context.protocol == 'paste.filter_app_factory':
+ def filter_wrapper(wsgi_app):
+ # This should be an object, so it has a nicer __repr__
+ return fix_call(context.object,
+ wsgi_app, context.global_conf,
+ **context.local_conf)
+ return filter_wrapper
+ else:
+ assert 0, "Protocol %r unknown" % context.protocol
+
+FILTER = _Filter()
+
+class _Server(_ObjectType):
+ name = 'server'
+ egg_protocols = [['paste.server_factory', 'paste.server_runner']]
+ config_prefixes = ['server']
+
+ def invoke(self, context):
+ if context.protocol == 'paste.server_factory':
+ return fix_call(context.object,
+ context.global_conf, **context.local_conf)
+ elif context.protocol == 'paste.server_runner':
+ def server_wrapper(wsgi_app):
+ # This should be an object, so it has a nicer __repr__
+ return fix_call(context.object,
+ wsgi_app, context.global_conf,
+ **context.local_conf)
+ return server_wrapper
+ else:
+ assert 0, "Protocol %r unknown" % context.protocol
+
+SERVER = _Server()
+
+# Virtual type: (@@: There's clearly something crufty here;
+# this probably could be more elegant)
+class _PipeLine(_ObjectType):
+ name = 'pipeline'
+
+ def invoke(self, context):
+ app = context.app_context.create()
+ filters = [c.create() for c in context.filter_contexts]
+ filters.reverse()
+ for filter in filters:
+ app = filter(app)
+ return app
+
+PIPELINE = _PipeLine()
+
+class _FilterApp(_ObjectType):
+ name = 'filter_app'
+
+ def invoke(self, context):
+ next_app = context.next_context.create()
+ filter = context.filter_context.create()
+ return filter(next_app)
+
+FILTER_APP = _FilterApp()
+
+class _FilterWith(_App):
+ name = 'filtered_with'
+
+ def invoke(self, context):
+ filter = context.filter_context.create()
+ filtered = context.next_context.create()
+ if context.next_context.object_type is APP:
+ return filter(filtered)
+ else:
+ # filtering a filter
+ def composed(app):
+ return filter(filtered(app))
+ return composed
+
+FILTER_WITH = _FilterWith()
+
+############################################################
+## Loaders
+############################################################
+
+def loadapp(uri, name=None, **kw):
+ return loadobj(APP, uri, name=name, **kw)
+
+def loadfilter(uri, name=None, **kw):
+ return loadobj(FILTER, uri, name=name, **kw)
+
+def loadserver(uri, name=None, **kw):
+ return loadobj(SERVER, uri, name=name, **kw)
+
+def appconfig(uri, name=None, relative_to=None, global_conf=None):
+ context = loadcontext(APP, uri, name=name,
+ relative_to=relative_to,
+ global_conf=global_conf)
+ return context.config()
+
+_loaders = {}
+
+def loadobj(object_type, uri, name=None, relative_to=None,
+ global_conf=None):
+ context = loadcontext(
+ object_type, uri, name=name, relative_to=relative_to,
+ global_conf=global_conf)
+ return context.create()
+
+def loadcontext(object_type, uri, name=None, relative_to=None,
+ global_conf=None):
+ if '#' in uri:
+ if name is None:
+ uri, name = uri.split('#', 1)
+ else:
+ # @@: Ignore fragment or error?
+ uri = uri.split('#', 1)[0]
+ if name is None:
+ name = 'main'
+ if ':' not in uri:
+ raise LookupError("URI has no scheme: %r" % uri)
+ scheme, path = uri.split(':', 1)
+ scheme = scheme.lower()
+ if scheme not in _loaders:
+ raise LookupError(
+ "URI scheme not known: %r (from %s)"
+ % (scheme, ', '.join(_loaders.keys())))
+ return _loaders[scheme](
+ object_type,
+ uri, path, name=name, relative_to=relative_to,
+ global_conf=global_conf)
+
+def _loadconfig(object_type, uri, path, name, relative_to,
+ global_conf):
+ isabs = os.path.isabs(path)
+ # De-Windowsify the paths:
+ path = path.replace('\\', '/')
+ if not isabs:
+ if not relative_to:
+ raise ValueError(
+ "Cannot resolve relative uri %r; no relative_to keyword "
+ "argument given" % uri)
+ relative_to = relative_to.replace('\\', '/')
+ if relative_to.endswith('/'):
+ path = relative_to + path
+ else:
+ path = relative_to + '/' + path
+ if path.startswith('///'):
+ path = path[2:]
+ path = urllib.unquote(path)
+ loader = ConfigLoader(path)
+ if global_conf:
+ loader.update_defaults(global_conf, overwrite=False)
+ return loader.get_context(object_type, name, global_conf)
+
+_loaders['config'] = _loadconfig
+
+def _loadegg(object_type, uri, spec, name, relative_to,
+ global_conf):
+ loader = EggLoader(spec)
+ return loader.get_context(object_type, name, global_conf)
+
+_loaders['egg'] = _loadegg
+
+############################################################
+## Loaders
+############################################################
+
+class _Loader(object):
+
+ def get_app(self, name=None, global_conf=None):
+ return self.app_context(
+ name=name, global_conf=global_conf).create()
+
+ def get_filter(self, name=None, global_conf=None):
+ return self.filter_context(
+ name=name, global_conf=global_conf).create()
+
+ def get_server(self, name=None, global_conf=None):
+ return self.server_context(
+ name=name, global_conf=global_conf).create()
+
+ def app_context(self, name=None, global_conf=None):
+ return self.get_context(
+ APP, name=name, global_conf=global_conf)
+
+ def filter_context(self, name=None, global_conf=None):
+ return self.get_context(
+ FILTER, name=name, global_conf=global_conf)
+
+ def server_context(self, name=None, global_conf=None):
+ return self.get_context(
+ SERVER, name=name, global_conf=global_conf)
+
+ _absolute_re = re.compile(r'^[a-zA-Z]+:')
+ def absolute_name(self, name):
+ """
+ Returns true if the name includes a scheme
+ """
+ if name is None:
+ return False
+ return self._absolute_re.search(name)
+
+class ConfigLoader(_Loader):
+
+ def __init__(self, filename):
+ self.filename = filename = filename.strip()
+ self.parser = NicerConfigParser(self.filename)
+ # Don't lower-case keys:
+ self.parser.optionxform = str
+ # Stupid ConfigParser ignores files that aren't found, so
+ # we have to add an extra check:
+ if not os.path.exists(filename):
+ if filename.strip() != filename:
+ raise IOError(
+ "File %r not found; trailing whitespace: "
+ "did you try to use a # on the same line as a filename? "
+ "(comments must be on their own line)" % filename)
+ raise IOError(
+ "File %r not found" % filename)
+ self.parser.read(filename)
+ self.parser._defaults.setdefault(
+ 'here', os.path.dirname(os.path.abspath(filename)))
+ self.parser._defaults.setdefault(
+ '__file__', os.path.abspath(filename))
+
+ def update_defaults(self, new_defaults, overwrite=True):
+ for key, value in new_defaults.items():
+ if not overwrite and key in self.parser._defaults:
+ continue
+ self.parser._defaults[key] = value
+
+ def get_context(self, object_type, name=None, global_conf=None):
+ if self.absolute_name(name):
+ return loadcontext(object_type, name,
+ relative_to=os.path.dirname(self.filename),
+ global_conf=global_conf)
+ section = self.find_config_section(
+ object_type, name=name)
+ if global_conf is None:
+ global_conf = {}
+ else:
+ global_conf = global_conf.copy()
+ defaults = self.parser.defaults()
+ global_conf.update(defaults)
+ local_conf = {}
+ global_additions = {}
+ get_from_globals = {}
+ for option in self.parser.options(section):
+ if option.startswith('set '):
+ name = option[4:].strip()
+ global_additions[name] = global_conf[name] = (
+ self.parser.get(section, option))
+ elif option.startswith('get '):
+ name = option[4:].strip()
+ get_from_globals[name] = self.parser.get(section, option)
+ else:
+ if option in defaults:
+ # @@: It's a global option (?), so skip it
+ continue
+ local_conf[option] = self.parser.get(section, option)
+ for local_var, glob_var in get_from_globals.items():
+ local_conf[local_var] = global_conf[glob_var]
+ if object_type in (APP, FILTER) and 'filter-with' in local_conf:
+ filter_with = local_conf.pop('filter-with')
+ else:
+ filter_with = None
+ if 'require' in local_conf:
+ for spec in local_conf['require'].split():
+ pkg_resources.require(spec)
+ del local_conf['require']
+ if section.startswith('filter-app:'):
+ context = self._filter_app_context(
+ object_type, section, name=name,
+ global_conf=global_conf, local_conf=local_conf,
+ global_additions=global_additions)
+ elif section.startswith('pipeline:'):
+ context = self._pipeline_app_context(
+ object_type, section, name=name,
+ global_conf=global_conf, local_conf=local_conf,
+ global_additions=global_additions)
+ elif 'use' in local_conf:
+ context = self._context_from_use(
+ object_type, local_conf, global_conf, global_additions,
+ section)
+ else:
+ context = self._context_from_explicit(
+ object_type, local_conf, global_conf, global_additions,
+ section)
+ if filter_with is not None:
+ filter_with_context = LoaderContext(
+ obj=None,
+ object_type=FILTER_WITH,
+ protocol=None,
+ global_conf=global_conf, local_conf=local_conf,
+ loader=self)
+ filter_with_context.filter_context = self.filter_context(
+ name=filter_with, global_conf=global_conf)
+ filter_with_context.next_context = context
+ return filter_with_context
+ return context
+
+ def _context_from_use(self, object_type, local_conf, global_conf,
+ global_additions, section):
+ use = local_conf.pop('use')
+ context = self.get_context(
+ object_type, name=use, global_conf=global_conf)
+ context.global_conf.update(global_additions)
+ context.local_conf.update(local_conf)
+ if '__file__' in global_conf:
+ # use sections shouldn't overwrite the original __file__
+ context.global_conf['__file__'] = global_conf['__file__']
+ # @@: Should loader be overwritten?
+ context.loader = self
+ return context
+
+ def _context_from_explicit(self, object_type, local_conf, global_conf,
+ global_addition, section):
+ possible = []
+ for protocol_options in object_type.egg_protocols:
+ for protocol in protocol_options:
+ if protocol in local_conf:
+ possible.append((protocol, local_conf[protocol]))
+ break
+ if len(possible) > 1:
+ raise LookupError(
+ "Multiple protocols given in section %r: %s"
+ % (section, possible))
+ if not possible:
+ raise LookupError(
+ "No loader given in section %r" % section)
+ found_protocol, found_expr = possible[0]
+ del local_conf[found_protocol]
+ value = import_string(found_expr)
+ context = LoaderContext(
+ value, object_type, found_protocol,
+ global_conf, local_conf, self)
+ return context
+
+ def _filter_app_context(self, object_type, section, name,
+ global_conf, local_conf, global_additions):
+ if 'next' not in local_conf:
+ raise LookupError(
+ "The [%s] section in %s is missing a 'next' setting"
+ % (section, self.filename))
+ next_name = local_conf.pop('next')
+ context = LoaderContext(None, FILTER_APP, None, global_conf,
+ local_conf, self)
+ context.next_context = self.get_context(
+ APP, next_name, global_conf)
+ if 'use' in local_conf:
+ context.filter_context = self._context_from_use(
+ FILTER, local_conf, global_conf, global_additions,
+ section)
+ else:
+ context.filter_context = self._context_from_explicit(
+ FILTER, local_conf, global_conf, global_additions,
+ section)
+ return context
+
+ def _pipeline_app_context(self, object_type, section, name,
+ global_conf, local_conf, global_additions):
+ if 'pipeline' not in local_conf:
+ raise LookupError(
+ "The [%s] section in %s is missing a 'pipeline' setting"
+ % (section, self.filename))
+ pipeline = local_conf.pop('pipeline').split()
+ if local_conf:
+ raise LookupError(
+ "The [%s] pipeline section in %s has extra "
+ "(disallowed) settings: %s"
+ % (', '.join(local_conf.keys())))
+ context = LoaderContext(None, PIPELINE, None, global_conf,
+ local_conf, self)
+ context.app_context = self.get_context(
+ APP, pipeline[-1], global_conf)
+ context.filter_contexts = [
+ self.get_context(FILTER, name, global_conf)
+ for name in pipeline[:-1]]
+ return context
+
+ def find_config_section(self, object_type, name=None):
+ """
+ Return the section name with the given name prefix (following the
+ same pattern as ``protocol_desc`` in ``config``. It must have the
+ given name, or for ``'main'`` an empty name is allowed. The
+ prefix must be followed by a ``:``.
+
+ Case is *not* ignored.
+ """
+ possible = []
+ for name_options in object_type.config_prefixes:
+ for name_prefix in name_options:
+ found = self._find_sections(
+ self.parser.sections(), name_prefix, name)
+ if found:
+ possible.extend(found)
+ break
+ if not possible:
+ raise LookupError(
+ "No section %r (prefixed by %s) found in config %s"
+ % (name,
+ ' or '.join(map(repr, _flatten(object_type.config_prefixes))),
+ self.filename))
+ if len(possible) > 1:
+ raise LookupError(
+ "Ambiguous section names %r for section %r (prefixed by %s) "
+ "found in config %s"
+ % (possible, name,
+ ' or '.join(map(repr, _flatten(object_type.config_prefixes))),
+ self.filename))
+ return possible[0]
+
+ def _find_sections(self, sections, name_prefix, name):
+ found = []
+ if name is None:
+ if name_prefix in sections:
+ found.append(name_prefix)
+ name = 'main'
+ for section in sections:
+ if section.startswith(name_prefix+':'):
+ if section[len(name_prefix)+1:].strip() == name:
+ found.append(section)
+ return found
+
+
+class EggLoader(_Loader):
+
+ def __init__(self, spec):
+ self.spec = spec
+
+ def get_context(self, object_type, name=None, global_conf=None):
+ if self.absolute_name(name):
+ return loadcontext(object_type, name,
+ global_conf=global_conf)
+ entry_point, protocol, ep_name = self.find_egg_entry_point(
+ object_type, name=name)
+ return LoaderContext(
+ entry_point,
+ object_type,
+ protocol,
+ global_conf or {}, {},
+ self,
+ distribution=pkg_resources.get_distribution(self.spec),
+ entry_point_name=ep_name)
+
+ def find_egg_entry_point(self, object_type, name=None):
+ """
+ Returns the (entry_point, protocol) for the with the given
+ ``name``.
+ """
+ if name is None:
+ name = 'main'
+ possible = []
+ for protocol_options in object_type.egg_protocols:
+ for protocol in protocol_options:
+ pkg_resources.require(self.spec)
+ entry = pkg_resources.get_entry_info(
+ self.spec,
+ protocol,
+ name)
+ if entry is not None:
+ possible.append((entry.load(), protocol, entry.name))
+ break
+ if not possible:
+ # Better exception
+ dist = pkg_resources.get_distribution(self.spec)
+ raise LookupError(
+ "Entry point %r not found in egg %r (dir: %s; protocols: %s; "
+ "entry_points: %s)"
+ % (name, self.spec,
+ dist.location,
+ ', '.join(_flatten(object_type.egg_protocols)),
+ ', '.join(_flatten([
+ (pkg_resources.get_entry_info(self.spec, prot, name) or {}).keys()
+ for prot in protocol_options] or '(no entry points)'))))
+ if len(possible) > 1:
+ raise LookupError(
+ "Ambiguous entry points for %r in egg %r (protocols: %s)"
+ % (name, self.spec, ', '.join(_flatten(protocol_options))))
+ return possible[0]
+
+class LoaderContext(object):
+
+ def __init__(self, obj, object_type, protocol,
+ global_conf, local_conf, loader,
+ distribution=None, entry_point_name=None):
+ self.object = obj
+ self.object_type = object_type
+ self.protocol = protocol
+ #assert protocol in _flatten(object_type.egg_protocols), (
+ # "Bad protocol %r; should be one of %s"
+ # % (protocol, ', '.join(map(repr, _flatten(object_type.egg_protocols)))))
+ self.global_conf = global_conf
+ self.local_conf = local_conf
+ self.loader = loader
+ self.distribution = distribution
+ self.entry_point_name = entry_point_name
+
+ def create(self):
+ return self.object_type.invoke(self)
+
+ def config(self):
+ conf = AttrDict(self.global_conf)
+ conf.update(self.local_conf)
+ conf.local_conf = self.local_conf
+ conf.global_conf = self.global_conf
+ conf.context = self
+ return conf
+
+class AttrDict(dict):
+ """
+ A dictionary that can be assigned to.
+ """
+ pass
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/paster_templates.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/paster_templates.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/paster_templates.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+from paste.script.templates import Template
+
+class PasteDeploy(Template):
+
+ _template_dir = 'paster_templates/paste_deploy'
+ summary = "A web application deployed through paste.deploy"
+
+ egg_plugins = ['PasteDeploy']
+
+ required_templates = ['PasteScript#basic_package']
+
+ def post(self, command, output_dir, vars):
+ for prereq in ['PasteDeploy']:
+ command.insert_into_file(
+ os.path.join(output_dir, 'setup.py'),
+ 'Extra requirements',
+ '%r,\n' % prereq,
+ indent=True)
+ command.insert_into_file(
+ os.path.join(output_dir, 'setup.py'),
+ 'Entry points',
+ (' [paste.app_factory]\n'
+ ' main = %(package)s.wsgiapp:make_app\n') % vars,
+ indent=False)
+ if command.verbose:
+ print '*'*72
+ print '* Run "paster serve docs/devel_config.ini" to run the sample application'
+ print '* on http://localhost:8080'
+ print '*'*72
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/fixtypeerror.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/fixtypeerror.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/fixtypeerror.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,61 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Fixes the vague error message that you get when calling a function
+with the wrong arguments.
+"""
+import inspect
+import sys
+
+def fix_type_error(exc_info, callable, varargs, kwargs):
+ """
+ Given an exception, this will test if the exception was due to a
+ signature error, and annotate the error with better information if
+ so.
+
+ Usage::
+
+ try:
+ val = callable(*args, **kw)
+ except TypeError:
+ exc_info = fix_type_error(None, callable, args, kw)
+ raise exc_info[0], exc_info[1], exc_info[2]
+ """
+ if exc_info is None:
+ exc_info = sys.exc_info()
+ if (exc_info[0] != TypeError
+ or str(exc_info[1]).find('arguments') == -1
+ or getattr(exc_info[1], '_type_error_fixed', False)):
+ return exc_info
+ exc_info[1]._type_error_fixed = True
+ import inspect
+ argspec = inspect.formatargspec(*inspect.getargspec(callable))
+ args = ', '.join(map(_short_repr, varargs))
+ if kwargs and args:
+ args += ', '
+ if kwargs:
+ kwargs = kwargs.items()
+ kwargs.sort()
+ args += ', '.join(['%s=...' % n for n, v in kwargs])
+ gotspec = '(%s)' % args
+ msg = '%s; got %s, wanted %s' % (exc_info[1], gotspec, argspec)
+ exc_info[1].args = (msg,)
+ return exc_info
+
+def _short_repr(v):
+ v = repr(v)
+ if len(v) > 12:
+ v = v[:8]+'...'+v[-4:]
+ return v
+
+def fix_call(callable, *args, **kw):
+ """
+ Call ``callable(*args, **kw)`` fixing any type errors that come
+ out.
+ """
+ try:
+ val = callable(*args, **kw)
+ except TypeError:
+ exc_info = fix_type_error(None, callable, args, kw)
+ raise exc_info[0], exc_info[1], exc_info[2]
+ return val
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/threadinglocal.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/threadinglocal.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/paste/deploy/util/threadinglocal.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,39 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+try:
+ import threading
+except ImportError:
+ # No threads, so "thread local" means process-global
+ class local(object):
+ pass
+else:
+ try:
+ local = threading.local
+ except AttributeError:
+ # Added in 2.4, but now we'll have to define it ourselves
+ import thread
+ class local(object):
+
+ def __init__(self):
+ self.__dict__['__objs'] = {}
+
+ def __getattr__(self, attr, g=thread.get_ident):
+ try:
+ return self.__dict__['__objs'][g()][attr]
+ except KeyError:
+ raise AttributeError(
+ "No variable %s defined for the thread %s"
+ % (attr, g()))
+
+ def __setattr__(self, attr, value, g=thread.get_ident):
+ self.__dict__['__objs'].setdefault(g(), {})[attr] = value
+
+ def __delattr__(self, attr, g=thread.get_ident):
+ try:
+ del self.__dict__['__objs'][g()][attr]
+ except KeyError:
+ raise AttributeError(
+ "No variable %s defined for thread %s"
+ % (attr, g()))
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+import os
+import sys
+
+here = os.path.dirname(__file__)
+base = os.path.dirname(here)
+sys.path.insert(0, base)
+
+# We can only import this after we adjust the paths
+import pkg_resources
+
+# Make absolutely sure we're testing *this* package, not
+# some other installed package
+pkg_resources.require('PasteDeploy')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/finddata.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/finddata.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/finddata.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,99 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# Note: you may want to copy this into your setup.py file verbatim, as
+# you can't import this from another package, when you don't know if
+# that package is installed yet.
+
+import os
+import sys
+from fnmatch import fnmatchcase
+from distutils.util import convert_path
+
+# Provided as an attribute, so you can append to these instead
+# of replicating them:
+standard_exclude = ('*.py', '*.pyc', '*$py.class', '*~', '.*', '*.bak')
+standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
+ './dist', 'EGG-INFO', '*.egg-info')
+
+def find_package_data(
+ where='.', package='',
+ exclude=standard_exclude,
+ exclude_directories=standard_exclude_directories,
+ only_in_packages=True,
+ show_ignored=False):
+ """
+ Return a dictionary suitable for use in ``package_data``
+ in a distutils ``setup.py`` file.
+
+ The dictionary looks like::
+
+ {'package': [files]}
+
+ Where ``files`` is a list of all the files in that package that
+ don't match anything in ``exclude``.
+
+ If ``only_in_packages`` is true, then top-level directories that
+ are not packages won't be included (but directories under packages
+ will).
+
+ Directories matching any pattern in ``exclude_directories`` will
+ be ignored; by default directories with leading ``.``, ``CVS``,
+ and ``_darcs`` will be ignored.
+
+ If ``show_ignored`` is true, then all the files that aren't
+ included in package data are shown on stderr (for debugging
+ purposes).
+
+ Note patterns use wildcards, or can be exact paths (including
+ leading ``./``), and all searching is case-insensitive.
+ """
+
+ out = {}
+ stack = [(convert_path(where), '', package, only_in_packages)]
+ while stack:
+ where, prefix, package, only_in_packages = stack.pop(0)
+ for name in os.listdir(where):
+ fn = os.path.join(where, name)
+ if os.path.isdir(fn):
+ bad_name = False
+ for pattern in exclude_directories:
+ if (fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "Directory %s ignored by pattern %s"
+ % (fn, pattern))
+ break
+ if bad_name:
+ continue
+ if (os.path.isfile(os.path.join(fn, '__init__.py'))
+ and not prefix):
+ if not package:
+ new_package = name
+ else:
+ new_package = package + '.' + name
+ stack.append((fn, '', new_package, False))
+ else:
+ stack.append((fn, prefix + name + '/', package, only_in_packages))
+ elif package or not only_in_packages:
+ # is a file
+ bad_name = False
+ for pattern in exclude:
+ if (fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "File %s ignored by pattern %s"
+ % (fn, pattern))
+ break
+ if bad_name:
+ continue
+ out.setdefault(package, []).append(prefix+name)
+ return out
+
+if __name__ == '__main__':
+ import pprint
+ pprint.pprint(
+ find_package_data(show_ignored=True))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/fixture.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/fixture.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/fixture.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+import os
+import sys
+import shutil
+
+test_dir = os.path.dirname(__file__)
+egg_info_dir = os.path.join(test_dir, 'fake_packages', 'FakeApp.egg',
+ 'EGG-INFO')
+info_dir = os.path.join(test_dir, 'fake_packages', 'FakeApp.egg',
+ 'FakeApp.egg-info')
+if not os.path.exists(egg_info_dir):
+ try:
+ os.symlink(info_dir, egg_info_dir)
+ except:
+ shutil.copytree(info_dir, egg_info_dir)
+
+sys.path.append(os.path.dirname(egg_info_dir))
+
+from pkg_resources import *
+working_set.add_entry(os.path.dirname(egg_info_dir))
+require('FakeApp')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_basic_app.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_basic_app.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_basic_app.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,34 @@
+from paste.deploy import loadapp, loadfilter, appconfig
+from fixture import *
+import fakeapp.apps
+
+here = os.path.dirname(__file__)
+
+def test_main():
+ app = loadapp('config:sample_configs/basic_app.ini',
+ relative_to=here)
+ assert app is fakeapp.apps.basic_app
+ app = loadapp('config:sample_configs/basic_app.ini#main',
+ relative_to=here)
+ assert app is fakeapp.apps.basic_app
+ app = loadapp('config:sample_configs/basic_app.ini',
+ relative_to=here, name='main')
+ assert app is fakeapp.apps.basic_app
+ app = loadapp('config:sample_configs/basic_app.ini#ignored',
+ relative_to=here, name='main')
+ assert app is fakeapp.apps.basic_app
+
+def test_other():
+ app = loadapp('config:sample_configs/basic_app.ini#other',
+ relative_to=here)
+ assert app is fakeapp.apps.basic_app2
+
+
+def test_composit():
+ app = loadapp('config:sample_configs/basic_app.ini#remote_addr',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.RemoteAddrDispatch)
+ assert app.map['127.0.0.1'] is fakeapp.apps.basic_app
+ assert app.map['0.0.0.0'] is fakeapp.apps.basic_app2
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,116 @@
+import os
+from paste.deploy import loadapp, loadfilter, appconfig
+from fixture import *
+import fakeapp.configapps as fc
+from pprint import pprint
+
+ini_file = 'config:sample_configs/test_config.ini'
+here = os.path.dirname(__file__)
+config_path = os.path.join(here, 'sample_configs')
+config_filename = os.path.join(config_path, 'test_config.ini')
+
+def test_config_egg():
+ app = loadapp('egg:FakeApp#configed')
+ assert isinstance(app, fc.SimpleApp)
+
+def test_config1():
+ app = loadapp(ini_file, relative_to=here, name='test1')
+ assert app.local_conf == {
+ 'setting1': 'foo', 'setting2': 'bar'}
+ assert app.global_conf == {
+ 'def1': 'a', 'def2': 'b',
+ 'here': config_path,
+ '__file__': config_filename}
+
+def test_config2():
+ app = loadapp(ini_file, relative_to=here, name='test2')
+ assert app.local_conf == {
+ 'local conf': 'something'}
+ assert app.global_conf == {
+ 'def1': 'test2',
+ 'def2': 'b',
+ 'another': 'TEST',
+ 'here': config_path,
+ '__file__': config_filename}
+ # Run this to make sure the global-conf-modified test2
+ # didn't mess up the general global conf
+ test_config1()
+
+def test_config3():
+ app = loadapp(ini_file, relative_to=here, name='test3')
+ assert isinstance(app, fc.SimpleApp)
+ assert app.local_conf == {
+ 'local conf': 'something',
+ 'another': 'something more\nacross several\nlines'}
+ assert app.global_conf == {
+ 'def1': 'test3',
+ 'def2': 'b',
+ 'another': 'TEST',
+ 'here': config_path,
+ '__file__': config_filename}
+ test_config2()
+
+def test_foreign_config():
+ app = loadapp(ini_file, relative_to=here, name='test_foreign_config')
+ assert isinstance(app, fc.SimpleApp)
+ assert app.local_conf == {
+ 'another': 'FOO',
+ 'bob': 'your uncle'}
+ pprint(app.global_conf)
+ assert app.global_conf == {
+ 'def1': 'a',
+ 'def2': 'from include',
+ 'def3': 'c',
+ 'glob': 'override',
+ 'here': config_path,
+ '__file__': os.path.join(config_path, 'test_config.ini')}
+
+def test_config_get():
+ app = loadapp(ini_file, relative_to=here, name='test_get')
+ assert isinstance(app, fc.SimpleApp)
+ assert app.local_conf == {
+ 'def1': 'a',
+ 'foo': 'TEST'}
+ assert app.global_conf == {
+ 'def1': 'a',
+ 'def2': 'TEST',
+ 'here': config_path,
+ '__file__': config_filename}
+
+def test_appconfig():
+ conf = appconfig(ini_file, relative_to=here, name='test_get')
+ assert conf == {
+ 'def1': 'a',
+ 'def2': 'TEST',
+ 'here': config_path,
+ '__file__': config_filename,
+ 'foo': 'TEST'}
+ assert conf.local_conf == {
+ 'def1': 'a',
+ 'foo': 'TEST'}
+ assert conf.global_conf == {
+ 'def1': 'a',
+ 'def2': 'TEST',
+ 'here': config_path,
+ '__file__': config_filename,}
+
+def test_appconfig_filter_with():
+ conf = appconfig('config:test_filter_with.ini', relative_to=config_path)
+ assert conf['example'] == 'test'
+
+def test_global_conf():
+ conf = appconfig(ini_file, relative_to=here, name='test_global_conf', global_conf={'def2': 'TEST DEF 2', 'inherit': 'bazbar'})
+ pprint(conf)
+ assert conf == {
+ 'def1': 'a',
+ # Note that this gets overwritten:
+ 'def2': 'b',
+ 'here': config_path,
+ 'inherit': 'bazbar',
+ '__file__': config_filename,
+ 'test_interp': 'this:bazbar',
+ }
+ assert conf.local_conf == {
+ 'test_interp': 'this:bazbar',
+ }
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config_middleware.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config_middleware.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_config_middleware.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+from nose.tools import assert_raises
+from paste.deploy.config import ConfigMiddleware
+from paste.fixture import TestApp
+
+class Bug(Exception): pass
+
+def app_with_exception(environ, start_response):
+ def cont():
+ yield "something"
+ raise Bug
+ start_response('200 OK', [('Content-type', 'text/html')])
+ return cont()
+
+def test_error():
+ wrapped = ConfigMiddleware(app_with_exception, {'test': 1})
+ test_app = TestApp(wrapped)
+ assert_raises(Bug, test_app.get, '/')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_filter.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_filter.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_filter.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,46 @@
+from paste.deploy import loadapp, loadfilter
+from fixture import *
+import fakeapp.apps
+
+here = os.path.dirname(__file__)
+
+def test_filter_app():
+ app = loadapp('config:sample_configs/test_filter.ini#filt',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app
+ assert app.method_to_call == 'lower'
+
+def test_pipeline():
+ app = loadapp('config:sample_configs/test_filter.ini#piped',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app
+ assert app.method_to_call == 'upper'
+
+def test_filter_app2():
+ app = loadapp('config:sample_configs/test_filter.ini#filt2',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app
+ assert app.method_to_call == 'lower'
+
+def test_pipeline2():
+ app = loadapp('config:sample_configs/test_filter.ini#piped2',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app
+ assert app.method_to_call == 'upper'
+
+def test_filter_app_inverted():
+ app = loadapp('config:sample_configs/test_filter.ini#inv',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app
+
+def test_filter_with_filter_with():
+ app = loadapp('config:sample_configs/test_filter_with.ini',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert isinstance(app.app, fakeapp.apps.CapFilter)
+ assert app.app.app is fakeapp.apps.basic_app
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_load_package.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_load_package.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteDeploy-1.3.4-py2.6.egg/tests/test_load_package.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+import sys, os
+import pkg_resources
+import site
+from pprint import pprint
+
+def test_load_package():
+ print 'Path:'
+ pprint(sys.path)
+ print pkg_resources.require('FakeApp')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,43 @@
+Metadata-Version: 1.0
+Name: PasteScript
+Version: 1.7.3
+Summary: A pluggable command-line frontend, including commands to setup package file layouts
+Home-page: http://pythonpaste.org/script/
+Author: Ian Bicking
+Author-email: ianb at colorstudy.com
+License: MIT
+Description: This is a pluggable command-line tool.
+
+ It includes some built-in features;
+
+ * Create file layouts for packages. For instance, ``paste create
+ --template=basic_package MyPackage`` will create a `setuptools
+ <http://peak.telecommunity.com/DevCenter/setuptools>`_-ready
+ file layout.
+
+ * Serving up web applications, with configuration based on
+ `paste.deploy <http://pythonpaste.org/deploy/paste-deploy.html>`_.
+
+ The latest version is available in a `Subversion repository
+ <http://svn.pythonpaste.org/Paste/Script/trunk#egg=PasteScript-dev>`_.
+
+ For the latest changes see the `news file
+ <http://pythonpaste.org/script/news.html>`_.
+
+ Changes in 1.7.3
+ ----------------
+
+ * CherryPy wsgiserver updated to 3.1.1, fixes a regression in Python
+ 2.5 plus a couple other small fixes.
+
+
+Keywords: web wsgi setuptools framework command-line setup
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Framework :: Paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,86 @@
+ez_setup.py
+regen-docs
+setup.cfg
+setup.py
+PasteScript.egg-info/PKG-INFO
+PasteScript.egg-info/SOURCES.txt
+PasteScript.egg-info/dependency_links.txt
+PasteScript.egg-info/entry_points.txt
+PasteScript.egg-info/namespace_packages.txt
+PasteScript.egg-info/not-zip-safe
+PasteScript.egg-info/requires.txt
+PasteScript.egg-info/top_level.txt
+docs/conf.py
+docs/developer.txt
+docs/example_app.ini
+docs/example_cgi_app.ini
+docs/index.txt
+docs/license.txt
+docs/news.txt
+docs/_static/paste.css
+docs/_templates/layout.html
+docs/modules/checkperms.txt
+docs/modules/command.txt
+docs/modules/copydir.txt
+docs/modules/filemaker.txt
+docs/modules/templates.txt
+docs/modules/testapp.txt
+docs/modules/util.secret.txt
+paste/__init__.py
+paste/script/__init__.py
+paste/script/appinstall.py
+paste/script/bool_optparse.py
+paste/script/cgi_server.py
+paste/script/checkperms.py
+paste/script/cherrypy_server.py
+paste/script/command.py
+paste/script/copydir.py
+paste/script/create_distro.py
+paste/script/default_sysconfig.py
+paste/script/entrypoints.py
+paste/script/epdesc.py
+paste/script/exe.py
+paste/script/filemaker.py
+paste/script/flup_server.py
+paste/script/grep.py
+paste/script/help.py
+paste/script/interfaces.py
+paste/script/pluginlib.py
+paste/script/request.py
+paste/script/serve.py
+paste/script/templates.py
+paste/script/testapp.py
+paste/script/twisted_web2_server.py
+paste/script/wsgiutils_server.py
+paste/script/paster-templates/basic_package/setup.cfg
+paste/script/paster-templates/basic_package/setup.py_tmpl
+paste/script/paster-templates/basic_package/+package+/__init__.py
+paste/script/paster-templates/basic_package/docs/license.txt_tmpl
+paste/script/util/__init__.py
+paste/script/util/logging_config.py
+paste/script/util/secret.py
+paste/script/util/string24.py
+paste/script/util/subprocess24.py
+paste/script/util/uuid.py
+paste/script/wsgiserver/__init__.py
+scripts/paster
+tests/conftest.py
+tests/test_egg_finder.py
+tests/test_logging_config.py
+tests/test_plugin_adder.py
+tests/test_template_introspect.py
+tests/appsetup/test_make_project.py
+tests/appsetup/testfiles/admin_index.py
+tests/appsetup/testfiles/conftest.py
+tests/appsetup/testfiles/iscape.txt
+tests/appsetup/testfiles/test_forbidden.py
+tests/fake_packages/FakePlugin.egg/setup.py
+tests/fake_packages/FakePlugin.egg/FakePlugin.egg-info/PKG-INFO
+tests/fake_packages/FakePlugin.egg/FakePlugin.egg-info/entry_points.txt
+tests/fake_packages/FakePlugin.egg/FakePlugin.egg-info/paster_plugins.txt
+tests/fake_packages/FakePlugin.egg/FakePlugin.egg-info/top_level.txt
+tests/fake_packages/FakePlugin.egg/fakeplugin/__init__.py
+tests/sample_templates/test1.txt
+tests/sample_templates/test2.py_tmpl
+tests/sample_templates/test3.ini_tmpl
+tests/sample_templates/test4.html_tmpl
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/entry_points.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/entry_points.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/entry_points.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,59 @@
+
+ [paste.global_paster_command]
+ help=paste.script.help:HelpCommand
+ create=paste.script.create_distro:CreateDistroCommand [Templating]
+ serve=paste.script.serve:ServeCommand [Config]
+ request=paste.script.request:RequestCommand [Config]
+ post=paste.script.request:RequestCommand [Config]
+ exe=paste.script.exe:ExeCommand
+ points=paste.script.entrypoints:EntryPointCommand
+ make-config=paste.script.appinstall:MakeConfigCommand
+ setup-app=paste.script.appinstall:SetupCommand
+
+ [paste.paster_command]
+ grep = paste.script.grep:GrepCommand
+
+ [paste.paster_create_template]
+ basic_package=paste.script.templates:BasicPackage
+
+ [paste.server_runner]
+ wsgiutils=paste.script.wsgiutils_server:run_server [WSGIUtils]
+ flup_ajp_thread=paste.script.flup_server:run_ajp_thread [Flup]
+ flup_ajp_fork=paste.script.flup_server:run_ajp_fork [Flup]
+ flup_fcgi_thread=paste.script.flup_server:run_fcgi_thread [Flup]
+ flup_fcgi_fork=paste.script.flup_server:run_fcgi_fork [Flup]
+ flup_scgi_thread=paste.script.flup_server:run_scgi_thread [Flup]
+ flup_scgi_fork=paste.script.flup_server:run_scgi_fork [Flup]
+ cgi=paste.script.cgi_server:paste_run_cgi
+ cherrypy=paste.script.cherrypy_server:cpwsgi_server
+ twisted=paste.script.twisted_web2_server:run_twisted
+
+ [paste.app_factory]
+ test=paste.script.testapp:make_test_application
+
+ [paste.entry_point_description]
+ paste.entry_point_description = paste.script.epdesc:MetaEntryPointDescription
+ paste.paster_create_template = paste.script.epdesc:CreateTemplateDescription
+ paste.paster_command = paste.script.epdesc:PasterCommandDescription
+ paste.global_paster_command = paste.script.epdesc:GlobalPasterCommandDescription
+ paste.app_install = paste.script.epdesc:AppInstallDescription
+
+ # These aren't part of Paste Script particularly, but
+ # we'll document them here
+ console_scripts = paste.script.epdesc:ConsoleScriptsDescription
+ # @@: Need non-console scripts...
+ distutils.commands = paste.script.epdesc:DistutilsCommandsDescription
+ distutils.setup_keywords = paste.script.epdesc:SetupKeywordsDescription
+ egg_info.writers = paste.script.epdesc:EggInfoWriters
+ # @@: Not sure what this does:
+ #setuptools.file_finders = paste.script.epdesc:SetuptoolsFileFinders
+
+ [console_scripts]
+ paster=paste.script.command:run
+
+ [distutils.setup_keywords]
+ paster_plugins = setuptools.dist:assert_string_list
+
+ [egg_info.writers]
+ paster_plugins.txt = setuptools.command.egg_info:write_arg
+
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/namespace_packages.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/namespace_packages.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/namespace_packages.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/requires.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/requires.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/requires.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+Paste>=1.3
+PasteDeploy
+
+[Templating]
+
+
+[Config]
+PasteDeploy
+
+[WSGIUtils]
+WSGIUtils
+
+[Flup]
+Flup
+
+[Cheetah]
+Cheetah
+
+[Paste]
+PasteDeploy
+Cheetah
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/scripts/paster
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/scripts/paster (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/scripts/paster 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+#!/work/develop/repository/svn.zope.org/zopeorg.buildout/branches/beta.zope.org/bin/python
+import os
+import sys
+
+try:
+ here = __file__
+except NameError:
+ # Python 2.2
+ here = sys.argv[0]
+
+relative_paste = os.path.join(
+ os.path.dirname(os.path.dirname(os.path.abspath(here))), 'paste')
+
+if os.path.exists(relative_paste):
+ sys.path.insert(0, os.path.dirname(relative_paste))
+
+from paste.script import command
+command.run()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+paste
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ # don't prevent use of paste if pkg_resources isn't installed
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
+
+try:
+ import modulefinder
+except ImportError:
+ pass
+else:
+ for p in __path__:
+ modulefinder.AddPackagePath(__name__, p)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/appinstall.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/appinstall.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/appinstall.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,613 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Provides the two commands for preparing an application:
+``prepare-app`` and ``setup-app``
+"""
+
+import os
+import sys
+if sys.version_info < (2, 4):
+ from paste.script.util import string24 as string
+else:
+ import string
+import new
+from cStringIO import StringIO
+from paste.script.command import Command, BadCommand, run as run_command
+import paste.script.templates
+from paste.script import copydir
+import pkg_resources
+Cheetah = None
+from ConfigParser import ConfigParser
+from paste.util import import_string
+from paste.deploy import appconfig
+from paste.script.util import uuid
+from paste.script.util import secret
+
+class AbstractInstallCommand(Command):
+
+ default_interactive = 1
+
+ default_sysconfigs = [
+ (False, '/etc/paste/sysconfig.py'),
+ (False, '/usr/local/etc/paste/sysconfig.py'),
+ (True, 'paste.script.default_sysconfig'),
+ ]
+ if os.environ.get('HOME'):
+ default_sysconfigs.insert(
+ 0, (False, os.path.join(os.environ['HOME'], '.paste', 'config',
+ 'sysconfig.py')))
+ if os.environ.get('PASTE_SYSCONFIG'):
+ default_sysconfigs.insert(
+ 0, (False, os.environ['PASTE_SYSCONFIG']))
+
+ def run(self, args):
+ # This is overridden so we can parse sys-config before we pass
+ # it to optparse
+ self.sysconfigs = self.default_sysconfigs
+ new_args = []
+ while args:
+ if args[0].startswith('--no-default-sysconfig'):
+ self.sysconfigs = []
+ args.pop(0)
+ continue
+ if args[0].startswith('--sysconfig='):
+ self.sysconfigs.insert(
+ 0, (True, args.pop(0)[len('--sysconfig='):]))
+ continue
+ if args[0] == '--sysconfig':
+ args.pop(0)
+ if not args:
+ raise BadCommand, (
+ "You gave --sysconfig as the last argument without "
+ "a value")
+ self.sysconfigs.insert(0, (True, args.pop(0)))
+ continue
+ new_args.append(args.pop(0))
+ self.load_sysconfigs()
+ return super(AbstractInstallCommand, self).run(new_args)
+
+ #@classmethod
+ def standard_parser(cls, **kw):
+ parser = super(AbstractInstallCommand, cls).standard_parser(**kw)
+ parser.add_option('--sysconfig',
+ action="append",
+ dest="sysconfigs",
+ help="System configuration file")
+ parser.add_option('--no-default-sysconfig',
+ action='store_true',
+ dest='no_default_sysconfig',
+ help="Don't load the default sysconfig files")
+ parser.add_option(
+ '--easy-install',
+ action='append',
+ dest='easy_install_op',
+ metavar='OP',
+ help='An option to add if invoking easy_install (like --easy-install=exclude-scripts)')
+ parser.add_option(
+ '--no-install',
+ action='store_true',
+ dest='no_install',
+ help="Don't try to install the package (it must already be installed)")
+ parser.add_option(
+ '-f', '--find-links',
+ action='append',
+ dest='easy_install_find_links',
+ metavar='URL',
+ help='Passed through to easy_install')
+
+ return parser
+
+ standard_parser = classmethod(standard_parser)
+
+ ########################################
+ ## Sysconfig Handling
+ ########################################
+
+ def load_sysconfigs(self):
+ configs = self.sysconfigs[:]
+ configs.reverse()
+ self.sysconfig_modules = []
+ for index, (explicit, name) in enumerate(configs):
+ # @@: At some point I'd like to give the specialized
+ # modules some access to the values in earlier modules,
+ # e.g., to specialize those values or functions. That's
+ # why these modules are loaded backwards.
+ if name.endswith('.py'):
+ if not os.path.exists(name):
+ if explicit:
+ raise BadCommand, (
+ "sysconfig file %s does not exist"
+ % name)
+ else:
+ continue
+ globs = {}
+ execfile(name, globs)
+ mod = new.module('__sysconfig_%i__' % index)
+ for name, value in globs.items():
+ setattr(mod, name, value)
+ mod.__file__ = name
+ else:
+ try:
+ mod = import_string.simple_import(name)
+ except ImportError, e:
+ if explicit:
+ raise
+ else:
+ continue
+ mod.paste_command = self
+ self.sysconfig_modules.insert(0, mod)
+ # @@: I'd really prefer to clone the parser here somehow,
+ # not to modify it in place
+ parser = self.parser
+ self.call_sysconfig_functions('add_custom_options', parser)
+
+ def get_sysconfig_option(self, name, default=None):
+ """
+ Return the value of the given option in the first sysconfig
+ module in which it is found, or ``default`` (None) if not
+ found in any.
+ """
+ for mod in self.sysconfig_modules:
+ if hasattr(mod, name):
+ return getattr(mod, name)
+ return default
+
+ def get_sysconfig_options(self, name):
+ """
+ Return the option value for the given name in all the
+ sysconfig modules in which is is found (``[]`` if none).
+ """
+ return [getattr(mod, name) for mod in self.sysconfig_modules
+ if hasattr(mod, name)]
+
+ def call_sysconfig_function(self, name, *args, **kw):
+ """
+ Call the specified function in the first sysconfig module it
+ is defined in. ``NameError`` if no function is found.
+ """
+ val = self.get_sysconfig_option(name)
+ if val is None:
+ raise NameError, (
+ "Method %s not found in any sysconfig module" % name)
+ return val(*args, **kw)
+
+ def call_sysconfig_functions(self, name, *args, **kw):
+ """
+ Call all the named functions in the sysconfig modules,
+ returning a list of the return values.
+ """
+ return [method(*args, **kw) for method in
+ self.get_sysconfig_options(name)]
+
+ def sysconfig_install_vars(self, installer):
+ """
+ Return the folded results of calling the
+ ``install_variables()`` functions.
+ """
+ result = {}
+ all_vars = self.call_sysconfig_functions(
+ 'install_variables', installer)
+ all_vars.reverse()
+ for vardict in all_vars:
+ result.update(vardict)
+ return result
+
+ ########################################
+ ## Distributions
+ ########################################
+
+ def get_distribution(self, req):
+ """
+ This gets a distribution object, and installs the distribution
+ if required.
+ """
+ try:
+ dist = pkg_resources.get_distribution(req)
+ if self.verbose:
+ print 'Distribution already installed:'
+ print ' ', dist, 'from', dist.location
+ return dist
+ except pkg_resources.DistributionNotFound:
+ if self.options.no_install:
+ print "Because --no-install was given, we won't try to install the package %s" % req
+ raise
+ options = ['-v', '-m']
+ for op in self.options.easy_install_op or []:
+ if not op.startswith('-'):
+ op = '--'+op
+ options.append(op)
+ for op in self.options.easy_install_find_links or []:
+ options.append('--find-links=%s' % op)
+ if self.simulate:
+ raise BadCommand(
+ "Must install %s, but in simulation mode" % req)
+ print "Must install %s" % req
+ from setuptools.command import easy_install
+ from setuptools import setup
+ setup(script_args=['-q', 'easy_install']
+ + options + [req])
+ return pkg_resources.get_distribution(req)
+
+ def get_installer(self, distro, ep_group, ep_name):
+ installer_class = distro.load_entry_point(
+ 'paste.app_install', ep_name)
+ installer = installer_class(
+ distro, ep_group, ep_name)
+ return installer
+
+
+class MakeConfigCommand(AbstractInstallCommand):
+
+ default_verbosity = 1
+ max_args = None
+ min_args = 1
+ summary = "Install a package and create a fresh config file/directory"
+ usage = "PACKAGE_NAME [CONFIG_FILE] [VAR=VALUE]"
+
+ description = """\
+ Note: this is an experimental command, and it will probably change
+ in several ways by the next release.
+
+ make-config is part of a two-phase installation process (the
+ second phase is setup-app). make-config installs the package
+ (using easy_install) and asks it to create a bare configuration
+ file or directory (possibly filling in defaults from the extra
+ variables you give).
+ """
+
+ parser = AbstractInstallCommand.standard_parser(
+ simulate=True, quiet=True, no_interactive=True)
+ parser.add_option('--info',
+ action="store_true",
+ dest="show_info",
+ help="Show information on the package (after installing it), but do not write a config.")
+ parser.add_option('--name',
+ action='store',
+ dest='ep_name',
+ help='The name of the application contained in the distribution (default "main")')
+ parser.add_option('--entry-group',
+ action='store',
+ dest='ep_group',
+ default='paste.app_factory',
+ help='The entry point group to install (i.e., the kind of application; default paste.app_factory')
+ parser.add_option('--edit',
+ action='store_true',
+ dest='edit',
+ help='Edit the configuration file after generating it (using $EDITOR)')
+ parser.add_option('--setup',
+ action='store_true',
+ dest='run_setup',
+ help='Run setup-app immediately after generating (and possibly editing) the configuration file')
+
+ def command(self):
+ self.requirement = self.args[0]
+ if '#' in self.requirement:
+ if self.options.ep_name is not None:
+ raise BadCommand(
+ "You may not give both --name and a requirement with "
+ "#name")
+ self.requirement, self.options.ep_name = self.requirement.split('#', 1)
+ if not self.options.ep_name:
+ self.options.ep_name = 'main'
+ self.distro = self.get_distribution(self.requirement)
+ self.installer = self.get_installer(
+ self.distro, self.options.ep_group, self.options.ep_name)
+ if self.options.show_info:
+ if len(self.args) > 1:
+ raise BadCommand(
+ "With --info you can only give one argument")
+ return self.show_info()
+ if len(self.args) < 2:
+ # See if sysconfig can give us a default filename
+ options = filter(None, self.call_sysconfig_functions(
+ 'default_config_filename', self.installer))
+ if not options:
+ raise BadCommand(
+ "You must give a configuration filename")
+ self.config_file = options[0]
+ else:
+ self.config_file = self.args[1]
+ self.check_config_file()
+ self.project_name = self.distro.project_name
+ self.vars = self.sysconfig_install_vars(self.installer)
+ self.vars.update(self.parse_vars(self.args[2:]))
+ self.vars['project_name'] = self.project_name
+ self.vars['requirement'] = self.requirement
+ self.vars['ep_name'] = self.options.ep_name
+ self.vars['ep_group'] = self.options.ep_group
+ self.vars.setdefault('app_name', self.project_name.lower())
+ self.vars.setdefault('app_instance_uuid', uuid.uuid4())
+ self.vars.setdefault('app_instance_secret', secret.secret_string())
+ if self.verbose > 1:
+ print_vars = self.vars.items()
+ print_vars.sort()
+ print 'Variables for installation:'
+ for name, value in print_vars:
+ print ' %s: %r' % (name, value)
+ self.installer.write_config(self, self.config_file, self.vars)
+ edit_success = True
+ if self.options.edit:
+ edit_success = self.run_editor()
+ setup_configs = self.installer.editable_config_files(self.config_file)
+ # @@: We'll just assume the first file in the list is the one
+ # that works with setup-app...
+ setup_config = setup_configs[0]
+ if self.options.run_setup:
+ if not edit_success:
+ print 'Config-file editing was not successful.'
+ if self.ask('Run setup-app anyway?', default=False):
+ self.run_setup(setup_config)
+ else:
+ self.run_setup(setup_config)
+ else:
+ filenames = self.installer.editable_config_files(self.config_file)
+ assert not isinstance(filenames, basestring), (
+ "editable_config_files returned a string, not a list")
+ if not filenames and filenames is not None:
+ print 'No config files need editing'
+ else:
+ print 'Now you should edit the config files'
+ if filenames:
+ for fn in filenames:
+ print ' %s' % fn
+
+ def show_info(self):
+ text = self.installer.description(None)
+ print text
+
+ def check_config_file(self):
+ if self.installer.expect_config_directory is None:
+ return
+ fn = self.config_file
+ if self.installer.expect_config_directory:
+ if os.path.splitext(fn)[1]:
+ raise BadCommand(
+ "The CONFIG_FILE argument %r looks like a filename, "
+ "and a directory name is expected" % fn)
+ else:
+ if fn.endswith('/') or not os.path.splitext(fn):
+ raise BadCommand(
+ "The CONFIG_FILE argument %r looks like a directory "
+ "name and a filename is expected" % fn)
+
+ def run_setup(self, filename):
+ run_command(['setup-app', filename])
+
+ def run_editor(self):
+ filenames = self.installer.editable_config_files(self.config_file)
+ if filenames is None:
+ print 'Warning: the config file is not known (--edit ignored)'
+ return False
+ if not filenames:
+ print 'Warning: no config files need editing (--edit ignored)'
+ return True
+ if len(filenames) > 1:
+ print 'Warning: there is more than one editable config file (--edit ignored)'
+ return False
+ if not os.environ.get('EDITOR'):
+ print 'Error: you must set $EDITOR if using --edit'
+ return False
+ if self.verbose:
+ print '%s %s' % (os.environ['EDITOR'], filenames[0])
+ retval = os.system('$EDITOR %s' % filenames[0])
+ if retval:
+ print 'Warning: editor %s returned with error code %i' % (
+ os.environ['EDITOR'], retval)
+ return False
+ return True
+
+class SetupCommand(AbstractInstallCommand):
+
+ default_verbosity = 1
+ max_args = 1
+ min_args = 1
+ summary = "Setup an application, given a config file"
+ usage = "CONFIG_FILE"
+
+ description = """\
+ Note: this is an experimental command, and it will probably change
+ in several ways by the next release.
+
+ Setup an application according to its configuration file. This is
+ the second part of a two-phase web application installation
+ process (the first phase is prepare-app). The setup process may
+ consist of things like creating directories and setting up
+ databases.
+ """
+
+ parser = AbstractInstallCommand.standard_parser(
+ simulate=True, quiet=True, interactive=True)
+ parser.add_option('--name',
+ action='store',
+ dest='section_name',
+ default=None,
+ help='The name of the section to set up (default: app:main)')
+
+ def command(self):
+ config_spec = self.args[0]
+ section = self.options.section_name
+ if section is None:
+ if '#' in config_spec:
+ config_spec, section = config_spec.split('#', 1)
+ else:
+ section = 'main'
+ if not ':' in section:
+ plain_section = section
+ section = 'app:'+section
+ else:
+ plain_section = section.split(':', 1)[0]
+ if not config_spec.startswith('config:'):
+ config_spec = 'config:' + config_spec
+ if plain_section != 'main':
+ config_spec += '#' + plain_section
+ config_file = config_spec[len('config:'):].split('#', 1)[0]
+ config_file = os.path.join(os.getcwd(), config_file)
+ self.logging_file_config(config_file)
+ conf = appconfig(config_spec, relative_to=os.getcwd())
+ ep_name = conf.context.entry_point_name
+ ep_group = conf.context.protocol
+ dist = conf.context.distribution
+ if dist is None:
+ raise BadCommand(
+ "The section %r is not the application (probably a filter). You should add #section_name, where section_name is the section that configures your application" % plain_section)
+ installer = self.get_installer(dist, ep_group, ep_name)
+ installer.setup_config(
+ self, config_file, section, self.sysconfig_install_vars(installer))
+ self.call_sysconfig_functions(
+ 'post_setup_hook', installer, config_file)
+
+
+class Installer(object):
+
+ """
+ Abstract base class for installers, and also a generic
+ installer that will run off config files in the .egg-info
+ directory of a distribution.
+
+ Packages that simply refer to this installer can provide a file
+ ``*.egg-info/paste_deploy_config.ini_tmpl`` that will be
+ interpreted by Cheetah. They can also provide ``websetup``
+ modules with a ``setup_app(command, conf, vars)`` (or the
+ now-deprecated ``setup_config(command, filename, section, vars)``)
+ function, that will be called.
+
+ In the future other functions or configuration files may be
+ called.
+ """
+
+ # If this is true, then try to detect filename-looking config_file
+ # values, and reject them. Conversely, if false try to detect
+ # directory-looking values and reject them. None means don't
+ # check.
+ expect_config_directory = False
+
+ # Set this to give a default config filename when none is
+ # specified:
+ default_config_filename = None
+
+ # Set this to true to use Cheetah to fill your templates, or false
+ # to not do so:
+ use_cheetah = True
+
+ def __init__(self, dist, ep_group, ep_name):
+ self.dist = dist
+ self.ep_group = ep_group
+ self.ep_name = ep_name
+
+ def description(self, config):
+ return 'An application'
+
+ def write_config(self, command, filename, vars):
+ """
+ Writes the content to the filename (directory or single file).
+ You should use the ``command`` object, which respects things
+ like simulation and interactive. ``vars`` is a dictionary
+ of user-provided variables.
+ """
+ command.ensure_file(filename, self.config_content(command, vars))
+
+ def editable_config_files(self, filename):
+ """
+ Return a list of filenames; this is primarily used when the
+ filename is treated as a directory and several configuration
+ files are created. The default implementation returns the
+ file itself. Return None if you don't know what files should
+ be edited on installation.
+ """
+ if not self.expect_config_directory:
+ return [filename]
+ else:
+ return None
+
+ def config_content(self, command, vars):
+ """
+ Called by ``self.write_config``, this returns the text content
+ for the config file, given the provided variables.
+
+ The default implementation reads
+ ``Package.egg-info/paste_deploy_config.ini_tmpl`` and fills it
+ with the variables.
+ """
+ global Cheetah
+ meta_name = 'paste_deploy_config.ini_tmpl'
+ if not self.dist.has_metadata(meta_name):
+ if command.verbose:
+ print 'No %s found' % meta_name
+ return self.simple_config(vars)
+ return self.template_renderer(
+ self.dist.get_metadata(meta_name), vars, filename=meta_name)
+
+ def template_renderer(self, content, vars, filename=None):
+ """
+ Subclasses may override this to provide different template
+ substitution (e.g., use a different template engine).
+ """
+ if self.use_cheetah:
+ import Cheetah.Template
+ tmpl = Cheetah.Template.Template(content,
+ searchList=[vars])
+ return copydir.careful_sub(
+ tmpl, vars, filename)
+ else:
+ tmpl = string.Template(content)
+ return tmpl.substitute(vars)
+
+ def simple_config(self, vars):
+ """
+ Return a very simple configuration file for this application.
+ """
+ if self.ep_name != 'main':
+ ep_name = '#'+self.ep_name
+ else:
+ ep_name = ''
+ return ('[app:main]\n'
+ 'use = egg:%s%s\n'
+ % (self.dist.project_name, ep_name))
+
+ def setup_config(self, command, filename, section, vars):
+ """
+ Called to setup an application, given its configuration
+ file/directory.
+
+ The default implementation calls
+ ``package.websetup.setup_config(command, filename, section,
+ vars)`` or ``package.websetup.setup_app(command, config,
+ vars)``
+
+ With ``setup_app`` the ``config`` object is a dictionary with
+ the extra attributes ``global_conf``, ``local_conf`` and
+ ``filename``
+ """
+ modules = [
+ line.strip()
+ for line in self.dist.get_metadata_lines('top_level.txt')
+ if line.strip() and not line.strip().startswith('#')]
+ if not modules:
+ print 'No modules are listed in top_level.txt'
+ print 'Try running python setup.py egg_info to regenerate that file'
+ for mod_name in modules:
+ mod_name = mod_name + '.websetup'
+ mod = import_string.try_import_module(mod_name)
+ if mod is None:
+ continue
+ if command.verbose:
+ print 'Running setup_config() from %s' % mod_name
+ if hasattr(mod, 'setup_app'):
+ self._call_setup_app(
+ mod.setup_app, command, filename, section, vars)
+ elif hasattr(mod, 'setup_config'):
+ mod.setup_config(command, filename, section, vars)
+ else:
+ print 'No setup_app() or setup_config() function in %s (%s)' % (
+ mod.__name__, mod.__file__)
+
+ def _call_setup_app(self, func, command, filename, section, vars):
+ filename = os.path.abspath(filename)
+ if ':' in section:
+ section = section.split(':', 1)[1]
+ conf = 'config:%s#%s' % (filename, section)
+ conf = appconfig(conf)
+ conf.filename = filename
+ func(command, conf, vars)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/bool_optparse.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/bool_optparse.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/bool_optparse.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,60 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+A subclass of ``optparse.OptionParser`` that allows boolean long
+options (like ``--verbose``) to also take arguments (like
+``--verbose=true``). Arguments *must* use ``=``.
+"""
+
+import optparse
+try:
+ _ = optparse._
+except AttributeError:
+ from gettext import gettext as _
+
+class BoolOptionParser(optparse.OptionParser):
+
+ def _process_long_opt(self, rargs, values):
+ arg = rargs.pop(0)
+
+ # Value explicitly attached to arg? Pretend it's the next
+ # argument.
+ if "=" in arg:
+ (opt, next_arg) = arg.split("=", 1)
+ rargs.insert(0, next_arg)
+ had_explicit_value = True
+ else:
+ opt = arg
+ had_explicit_value = False
+
+ opt = self._match_long_opt(opt)
+ option = self._long_opt[opt]
+ if option.takes_value():
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error(_("%s option requires an argument") % opt)
+ else:
+ self.error(_("%s option requires %d arguments")
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ elif had_explicit_value:
+ value = rargs[0].lower().strip()
+ del rargs[0:1]
+ if value in ('true', 'yes', 'on', '1', 'y', 't'):
+ value = None
+ elif value in ('false', 'no', 'off', '0', 'n', 'f'):
+ # Don't process
+ return
+ else:
+ self.error(_('%s option takes a boolean value only (true/false)') % opt)
+
+ else:
+ value = None
+
+ option.process(opt, value, values, self)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cgi_server.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cgi_server.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cgi_server.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,71 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import sys
+
+## FIXME: this should be deprecated in favor of wsgiref
+
+def paste_run_cgi(wsgi_app, global_conf):
+ run_with_cgi(wsgi_app)
+
+stdout = sys.__stdout__
+
+# Taken from the WSGI spec:
+
+def run_with_cgi(application):
+
+ environ = dict(os.environ.items())
+ environ['wsgi.input'] = sys.stdin
+ environ['wsgi.errors'] = sys.stderr
+ environ['wsgi.version'] = (1,0)
+ environ['wsgi.multithread'] = False
+ environ['wsgi.multiprocess'] = True
+ environ['wsgi.run_once'] = True
+
+ if environ.get('HTTPS','off') in ('on','1'):
+ environ['wsgi.url_scheme'] = 'https'
+ else:
+ environ['wsgi.url_scheme'] = 'http'
+
+ headers_set = []
+ headers_sent = []
+
+ def write(data):
+ if not headers_set:
+ raise AssertionError("write() before start_response()")
+
+ elif not headers_sent:
+ # Before the first output, send the stored headers
+ status, response_headers = headers_sent[:] = headers_set
+ stdout.write('Status: %s\r\n' % status)
+ for header in response_headers:
+ stdout.write('%s: %s\r\n' % header)
+ stdout.write('\r\n')
+
+ stdout.write(data)
+ stdout.flush()
+
+ def start_response(status,response_headers,exc_info=None):
+ if exc_info:
+ try:
+ if headers_sent:
+ # Re-raise original exception if headers sent
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ exc_info = None # avoid dangling circular ref
+ elif headers_set:
+ raise AssertionError("Headers already set!")
+
+ headers_set[:] = [status,response_headers]
+ return write
+
+ result = application(environ, start_response)
+ try:
+ for data in result:
+ if data: # don't send headers until body appears
+ write(data)
+ if not headers_sent:
+ write('') # send headers now if body was empty
+ finally:
+ if hasattr(result,'close'):
+ result.close()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/checkperms.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/checkperms.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/checkperms.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,441 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+This is a module to check the filesystem for the presence and
+permissions of certain files. It can also be used to correct the
+permissions (but not existance) of those files.
+
+Currently only supports Posix systems (with Posixy permissions).
+Permission stuff can probably be stubbed out later.
+"""
+import os
+
+def read_perm_spec(spec):
+ """
+ Reads a spec like 'rw-r--r--' into a octal number suitable for
+ chmod. That is characters in groups of three -- first group is
+ user, second for group, third for other (all other people). The
+ characters are r (read), w (write), and x (executable), though the
+ executable can also be s (sticky). Files in sticky directories
+ get the directories permission setting.
+
+ Examples::
+
+ >>> print oct(read_perm_spec('rw-r--r--'))
+ 0644
+ >>> print oct(read_perm_spec('rw-rwsr--'))
+ 02664
+ >>> print oct(read_perm_spec('r-xr--r--'))
+ 0544
+ >>> print oct(read_perm_spec('r--------'))
+ 0400
+ """
+ total_mask = 0
+ # suid/sgid modes give this mask in user, group, other mode:
+ set_bits = (04000, 02000, 0)
+ pieces = (spec[0:3], spec[3:6], spec[6:9])
+ for i, (mode, set_bit) in enumerate(zip(pieces, set_bits)):
+ mask = 0
+ read, write, exe = list(mode)
+ if read == 'r':
+ mask = mask | 4
+ elif read != '-':
+ raise ValueError, (
+ "Character %r unexpected (should be '-' or 'r')"
+ % read)
+ if write == 'w':
+ mask = mask | 2
+ elif write != '-':
+ raise ValueError, (
+ "Character %r unexpected (should be '-' or 'w')"
+ % write)
+ if exe == 'x':
+ mask = mask | 1
+ elif exe not in ('s', '-'):
+ raise ValueError, (
+ "Character %r unexpected (should be '-', 'x', or 's')"
+ % exe)
+ if exe == 's' and i == 2:
+ raise ValueError, (
+ "The 'other' executable setting cannot be suid/sgid ('s')")
+ mask = mask << ((2-i)*3)
+ if exe == 's':
+ mask = mask | set_bit
+ total_mask = total_mask | mask
+ return total_mask
+
+modes = [
+ (04000, 'setuid bit',
+ 'setuid bit: make contents owned by directory owner'),
+ (02000, 'setgid bit',
+ 'setgid bit: make contents inherit permissions from directory'),
+ (01000, 'sticky bit',
+ 'sticky bit: append-only directory'),
+ (00400, 'read by owner', 'read by owner'),
+ (00200, 'write by owner', 'write by owner'),
+ (00100, 'execute by owner', 'owner can search directory'),
+ (00040, 'allow read by group members',
+ 'allow read by group members',),
+ (00020, 'allow write by group members',
+ 'allow write by group members'),
+ (00010, 'execute by group members',
+ 'group members can search directory'),
+ (00004, 'read by others', 'read by others'),
+ (00002, 'write by others', 'write by others'),
+ (00001, 'execution by others', 'others can search directory'),
+ ]
+
+exe_bits = [0100, 0010, 0001]
+exe_mask = 0111
+full_mask = 07777
+
+def mode_diff(filename, mode, **kw):
+ """
+ Returns the differences calculated using ``calc_mode_diff``
+ """
+ cur_mode = os.stat(filename).st_mode
+ return calc_mode_diff(cur_mode, mode, **kw)
+
+def calc_mode_diff(cur_mode, mode, keep_exe=True,
+ not_set='not set: ',
+ set='set: '):
+ """
+ Gives the difference between the actual mode of the file and the
+ given mode. If ``keep_exe`` is true, then if the mode doesn't
+ include any executable information the executable information will
+ simply be ignored. High bits are also always ignored (except
+ suid/sgid and sticky bit).
+
+ Returns a list of differences (empty list if no differences)
+ """
+ for exe_bit in exe_bits:
+ if mode & exe_bit:
+ keep_exe = False
+ diffs = []
+ isdir = os.path.isdir(filename)
+ for bit, file_desc, dir_desc in modes:
+ if keep_exe and bit in exe_bits:
+ continue
+ if isdir:
+ desc = dir_desc
+ else:
+ desc = file_desc
+ if (mode & bit) and not (cur_mode & bit):
+ diffs.append(not_set + desc)
+ if not (mode & bit) and (cur_mode & bit):
+ diffs.append(set + desc)
+ return diffs
+
+def calc_set_mode(cur_mode, mode, keep_exe=True):
+ """
+ Calculates the new mode given the current node ``cur_mode`` and
+ the mode spec ``mode`` and if ``keep_exe`` is true then also keep
+ the executable bits in ``cur_mode`` if ``mode`` has no executable
+ bits in it. Return the new mode.
+
+ Examples::
+
+ >>> print oct(calc_set_mode(0775, 0644))
+ 0755
+ >>> print oct(calc_set_mode(0775, 0744))
+ 0744
+ >>> print oct(calc_set_mode(010600, 0644))
+ 010644
+ >>> print oct(calc_set_mode(0775, 0644, False))
+ 0644
+ """
+ for exe_bit in exe_bits:
+ if mode & exe_bit:
+ keep_exe = False
+ # This zeros-out full_mask parts of the current mode:
+ keep_parts = (cur_mode | full_mask) ^ full_mask
+ if keep_exe:
+ keep_parts = keep_parts | (cur_mode & exe_mask)
+ new_mode = keep_parts | mode
+ return new_mode
+
+def set_mode(filename, mode, **kw):
+ """
+ Sets the mode on ``filename`` using ``calc_set_mode``
+ """
+ cur_mode = os.stat(filename).st_mode
+ new_mode = calc_set_mode(cur_mode, mode, **kw)
+ os.chmod(filename, new_mode)
+
+def calc_ownership_spec(spec):
+ """
+ Calculates what a string spec means, returning (uid, username,
+ gid, groupname), where there can be None values meaning no
+ preference.
+
+ The spec is a string like ``owner:group``. It may use numbers
+ instead of user/group names. It may leave out ``:group``. It may
+ use '-' to mean any-user/any-group.
+
+ """
+ import grp
+ import pwd
+ user = group = None
+ uid = gid = None
+ if ':' in spec:
+ user_spec, group_spec = spec.split(':', 1)
+ else:
+ user_spec, group_spec = spec, '-'
+ if user_spec == '-':
+ user_spec = '0'
+ if group_spec == '-':
+ group_spec = '0'
+ try:
+ uid = int(user_spec)
+ except ValueError:
+ uid = pwd.getpwnam(user_spec)
+ user = user_spec
+ else:
+ if not uid:
+ uid = user = None
+ else:
+ user = pwd.getpwuid(uid).pw_name
+ try:
+ gid = int(group_spec)
+ except ValueError:
+ gid = grp.getgrnam(group_spec)
+ group = group_spec
+ else:
+ if not gid:
+ gid = group = None
+ else:
+ group = grp.getgrgid(gid).gr_name
+ return (uid, user, gid, group)
+
+def ownership_diff(filename, spec):
+ """
+ Return a list of differences between the ownership of ``filename``
+ and the spec given.
+ """
+ import grp
+ import pwd
+ diffs = []
+ uid, user, gid, group = calc_ownership_spec(spec)
+ st = os.stat(filename)
+ if uid and uid != st.st_uid:
+ diffs.append('owned by %s (should be %s)' %
+ (pwd.getpwuid(st.st_uid).pw_name, user))
+ if gid and gid != st.st_gid:
+ diffs.append('group %s (should be %s)' %
+ (grp.getgrgid(st.st_gid).gr_name, group))
+ return diffs
+
+def set_ownership(filename, spec):
+ """
+ Set the ownership of ``filename`` given the spec.
+ """
+ uid, user, gid, group = calc_ownership_spec(spec)
+ st = os.stat(filename)
+ if not uid:
+ uid = st.st_uid
+ if not gid:
+ gid = st.st_gid
+ os.chmod(filename, uid, gid)
+
+class PermissionSpec(object):
+ """
+ Represents a set of specifications for permissions.
+
+ Typically reads from a file that looks like this::
+
+ rwxrwxrwx user:group filename
+
+ If the filename ends in /, then it expected to be a directory, and
+ the directory is made executable automatically, and the contents
+ of the directory are given the same permission (recursively). By
+ default the executable bit on files is left as-is, unless the
+ permissions specifically say it should be on in some way.
+
+ You can use 'nomodify filename' for permissions to say that any
+ permission is okay, and permissions should not be changed.
+
+ Use 'noexist filename' to say that a specific file should not
+ exist.
+
+ Use 'symlink filename symlinked_to' to assert a symlink destination
+
+ The entire file is read, and most specific rules are used for each
+ file (i.e., a rule for a subdirectory overrides the rule for a
+ superdirectory). Order does not matter.
+ """
+
+ def __init__(self):
+ self.paths = {}
+
+ def parsefile(self, filename):
+ f = open(filename)
+ lines = f.readlines()
+ f.close()
+ self.parselines(lines, filename=filename)
+
+ commands = {}
+
+ def parselines(self, lines, filename=None):
+ for lineindex, line in enumerate(lines):
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ parts = line.split()
+ command = parts[0]
+ if command in self.commands:
+ cmd = self.commands[command](*parts[1:])
+ else:
+ cmd = self.commands['*'](*parts)
+ self.paths[cmd.path] = cmd
+
+ def check(self):
+ action = _Check(self)
+ self.traverse(action)
+
+ def fix(self):
+ action = _Fixer(self)
+ self.traverse(action)
+
+ def traverse(self, action):
+ paths = self.paths_sorted()
+ checked = {}
+ for path, checker in list(paths)[::-1]:
+ self.check_tree(action, path, paths, checked)
+ for path, checker in paths:
+ if path not in checked:
+ action.noexists(path, checker)
+
+ def traverse_tree(self, action, path, paths, checked):
+ if path in checked:
+ return
+ self.traverse_path(action, path, paths, checked)
+ if os.path.isdir(path):
+ for fn in os.listdir(path):
+ fn = os.path.join(path, fn)
+ self.traverse_tree(action, fn, paths, checked)
+
+ def traverse_path(self, action, path, paths, checked):
+ checked[path] = None
+ for check_path, checker in paths:
+ if path.startswith(check_path):
+ action.check(check_path, checker)
+ if not checker.inherit:
+ break
+
+ def paths_sorted(self):
+ paths = self.paths.items()
+ paths.sort(lambda a, b: -cmp(len(a[0]), len(b[0])))
+
+class _Rule(object):
+ class __metaclass__(type):
+ def __new__(meta, class_name, bases, d):
+ cls = type.__new__(meta, class_name, bases, d)
+ PermissionSpec.commands[cls.__name__] = cls
+ return cls
+
+ inherit = False
+ def noexists(self):
+ return ['Path %s does not exist' % path]
+
+class _NoModify(_Rule):
+
+ name = 'nomodify'
+
+ def __init__(self, path):
+ self.path = path
+
+ def fix(self, path):
+ pass
+
+class _NoExist(_Rule):
+
+ name = 'noexist'
+
+ def __init__(self, path):
+ self.path = path
+
+ def check(self, path):
+ return ['Path %s should not exist' % path]
+
+ def noexists(self, path):
+ return []
+
+ def fix(self, path):
+ # @@: Should delete?
+ pass
+
+class _SymLink(_Rule):
+
+ name = 'symlink'
+ inherit = True
+
+ def __init__(self, path, dest):
+ self.path = path
+ self.dest = dest
+
+ def check(self, path):
+ assert path == self.path, (
+ "_Symlink should only be passed specific path %s (not %s)"
+ % (self.path, path))
+ try:
+ link = os.path.readlink(path)
+ except OSError:
+ if e.errno != 22:
+ raise
+ return ['Path %s is not a symlink (should point to %s)'
+ % (path, self.dest)]
+ if link != self.dest:
+ return ['Path %s should symlink to %s, not %s'
+ % (path, self.dest, link)]
+ return []
+
+ def fix(self, path):
+ assert path == self.path, (
+ "_Symlink should only be passed specific path %s (not %s)"
+ % (self.path, path))
+ if not os.path.exists(path):
+ os.symlink(path, self.dest)
+ else:
+ # @@: This should correct the symlink or something:
+ print 'Not symlinking %s' % path
+
+class _Permission(_Rule):
+
+ name = '*'
+
+ def __init__(self, perm, owner, dir):
+ self.perm_spec = read_perm_spec(perm)
+ self.owner = owner
+ self.dir = dir
+
+ def check(self, path):
+ return mode_diff(path, self.perm_spec)
+
+ def fix(self, path):
+ set_mode(path, self.perm_spec)
+
+class _Strategy(object):
+
+ def __init__(self, spec):
+ self.spec = spec
+
+class _Check(_Strategy):
+
+ def noexists(self, path, checker):
+ checker.noexists(path)
+
+ def check(self, path, checker):
+ checker.check(path)
+
+class _Fixer(_Strategy):
+
+ def noexists(self, path, checker):
+ pass
+
+ def check(self, path, checker):
+ checker.fix(path)
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cherrypy_server.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cherrypy_server.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/cherrypy_server.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,101 @@
+"""
+Entry point for CherryPy's WSGI server
+"""
+import paste.script.wsgiserver as wsgiserver
+
+def cpwsgi_server(app, global_conf=None, host='127.0.0.1', port=None,
+ ssl_pem=None, protocol_version=None, numthreads=None,
+ server_name=None, max=None, request_queue_size=None,
+ timeout=None):
+ """
+ Serves the specified WSGI app via CherryPyWSGIServer.
+
+ ``app``
+
+ The WSGI 'application callable'; multiple WSGI applications
+ may be passed as (script_name, callable) pairs.
+
+ ``host``
+
+ This is the ipaddress to bind to (or a hostname if your
+ nameserver is properly configured). This defaults to
+ 127.0.0.1, which is not a public interface.
+
+ ``port``
+
+ The port to run on, defaults to 8080 for HTTP, or 4443 for
+ HTTPS. This can be a string or an integer value.
+
+ ``ssl_pem``
+
+ This an optional SSL certificate file (via OpenSSL) You can
+ generate a self-signed test PEM certificate file as follows:
+
+ $ openssl genrsa 1024 > host.key
+ $ chmod 400 host.key
+ $ openssl req -new -x509 -nodes -sha1 -days 365 \\
+ -key host.key > host.cert
+ $ cat host.cert host.key > host.pem
+ $ chmod 400 host.pem
+
+ ``protocol_version``
+
+ The protocol used by the server, by default ``HTTP/1.1``.
+
+ ``numthreads``
+
+ The number of worker threads to create.
+
+ ``server_name``
+
+ The string to set for WSGI's SERVER_NAME environ entry.
+
+ ``max``
+
+ The maximum number of queued requests. (defaults to -1 = no
+ limit).
+
+ ``request_queue_size``
+
+ The 'backlog' argument to socket.listen(); specifies the
+ maximum number of queued connections.
+
+ ``timeout``
+
+ The timeout in seconds for accepted connections.
+ """
+ is_ssl = False
+ if ssl_pem:
+ port = port or 4443
+ is_ssl = True
+
+ if not port:
+ if ':' in host:
+ host, port = host.split(':', 1)
+ else:
+ port = 8080
+ bind_addr = (host, int(port))
+
+ kwargs = {}
+ for var_name in ('numthreads', 'max', 'request_queue_size', 'timeout'):
+ var = locals()[var_name]
+ if var is not None:
+ kwargs[var_name] = int(var)
+
+ server = wsgiserver.CherryPyWSGIServer(bind_addr, app,
+ server_name=server_name, **kwargs)
+ server.ssl_certificate = server.ssl_private_key = ssl_pem
+ if protocol_version:
+ server.protocol = protocol_version
+
+ try:
+ protocol = is_ssl and 'https' or 'http'
+ if host == '0.0.0.0':
+ print 'serving on 0.0.0.0:%s view at %s://127.0.0.1:%s' % \
+ (port, protocol, port)
+ else:
+ print "serving on %s://%s:%s" % (protocol, host, port)
+ server.start()
+ except (KeyboardInterrupt, SystemExit):
+ server.stop()
+ return server
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/command.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/command.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/command.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,787 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import pkg_resources
+import sys
+import optparse
+import bool_optparse
+import os
+import re
+import textwrap
+import pluginlib
+import ConfigParser
+import getpass
+try:
+ import subprocess
+except ImportError:
+ from paste.script.util import subprocess24 as subprocess
+difflib = None
+
+if sys.version_info >= (2, 6):
+ from logging.config import fileConfig
+else:
+ # Use our custom fileConfig -- 2.5.1's with a custom Formatter class
+ # and less strict whitespace (which were incorporated into 2.6's)
+ from paste.script.util.logging_config import fileConfig
+
+class BadCommand(Exception):
+
+ def __init__(self, message, exit_code=2):
+ self.message = message
+ self.exit_code = exit_code
+ Exception.__init__(self, message)
+
+class NoDefault(object):
+ pass
+
+dist = pkg_resources.get_distribution('PasteScript')
+
+python_version = sys.version.splitlines()[0].strip()
+
+parser = optparse.OptionParser(add_help_option=False,
+ version='%s from %s (python %s)'
+ % (dist, dist.location, python_version),
+ usage='%prog [paster_options] COMMAND [command_options]')
+
+parser.add_option(
+ '--plugin',
+ action='append',
+ dest='plugins',
+ help="Add a plugin to the list of commands (plugins are Egg specs; will also require() the Egg)")
+parser.add_option(
+ '-h', '--help',
+ action='store_true',
+ dest='do_help',
+ help="Show this help message")
+parser.disable_interspersed_args()
+
+# @@: Add an option to run this in another Python interpreter
+
+system_plugins = []
+
+def run(args=None):
+ if (not args and
+ len(sys.argv) >= 2
+ and os.environ.get('_') and sys.argv[0] != os.environ['_']
+ and os.environ['_'] == sys.argv[1]):
+ # probably it's an exe execution
+ args = ['exe', os.environ['_']] + sys.argv[2:]
+ if args is None:
+ args = sys.argv[1:]
+ options, args = parser.parse_args(args)
+ options.base_parser = parser
+ system_plugins.extend(options.plugins or [])
+ commands = get_commands()
+ if options.do_help:
+ args = ['help'] + args
+ if not args:
+ print 'Usage: %s COMMAND' % sys.argv[0]
+ args = ['help']
+ command_name = args[0]
+ if command_name not in commands:
+ command = NotFoundCommand
+ else:
+ command = commands[command_name].load()
+ invoke(command, command_name, options, args[1:])
+
+def parse_exe_file(config):
+ import shlex
+ p = ConfigParser.RawConfigParser()
+ p.read([config])
+ command_name = 'exe'
+ options = []
+ if p.has_option('exe', 'command'):
+ command_name = p.get('exe', 'command')
+ if p.has_option('exe', 'options'):
+ options = shlex.split(p.get('exe', 'options'))
+ if p.has_option('exe', 'sys.path'):
+ paths = shlex.split(p.get('exe', 'sys.path'))
+ paths = [os.path.abspath(os.path.join(os.path.dirname(config), p))
+ for p in paths]
+ for path in paths:
+ pkg_resources.working_set.add_entry(path)
+ sys.path.insert(0, path)
+ args = [command_name, config] + options
+ return args
+
+def get_commands():
+ plugins = system_plugins[:]
+ egg_info_dir = pluginlib.find_egg_info_dir(os.getcwd())
+ if egg_info_dir:
+ plugins.append(os.path.splitext(os.path.basename(egg_info_dir))[0])
+ base_dir = os.path.dirname(egg_info_dir)
+ if base_dir not in sys.path:
+ sys.path.insert(0, base_dir)
+ pkg_resources.working_set.add_entry(base_dir)
+ plugins = pluginlib.resolve_plugins(plugins)
+ commands = pluginlib.load_commands_from_plugins(plugins)
+ commands.update(pluginlib.load_global_commands())
+ return commands
+
+def invoke(command, command_name, options, args):
+ try:
+ runner = command(command_name)
+ exit_code = runner.run(args)
+ except BadCommand, e:
+ print e.message
+ exit_code = e.exit_code
+ sys.exit(exit_code)
+
+
+class Command(object):
+
+ def __init__(self, name):
+ self.command_name = name
+
+ max_args = None
+ max_args_error = 'You must provide no more than %(max_args)s arguments'
+ min_args = None
+ min_args_error = 'You must provide at least %(min_args)s arguments'
+ required_args = None
+ # If this command takes a configuration file, set this to 1 or -1
+ # Then if invoked through #! the config file will be put into the positional
+ # arguments -- at the beginning with 1, at the end with -1
+ takes_config_file = None
+
+ # Grouped in help messages by this:
+ group_name = ''
+
+ required_args = ()
+ description = None
+ usage = ''
+ hidden = False
+ # This is the default verbosity level; --quiet subtracts,
+ # --verbose adds:
+ default_verbosity = 0
+ # This is the default interactive state:
+ default_interactive = 0
+ return_code = 0
+
+ BadCommand = BadCommand
+
+ # Must define:
+ # parser
+ # summary
+ # command()
+
+ def run(self, args):
+ self.parse_args(args)
+
+ # Setup defaults:
+ for name, default in [('verbose', 0),
+ ('quiet', 0),
+ ('interactive', False),
+ ('overwrite', False)]:
+ if not hasattr(self.options, name):
+ setattr(self.options, name, default)
+ if getattr(self.options, 'simulate', False):
+ self.options.verbose = max(self.options.verbose, 1)
+ self.interactive = self.default_interactive
+ if getattr(self.options, 'interactive', False):
+ self.interactive += self.options.interactive
+ if getattr(self.options, 'no_interactive', False):
+ self.interactive = False
+ self.verbose = self.default_verbosity
+ self.verbose += self.options.verbose
+ self.verbose -= self.options.quiet
+ self.simulate = getattr(self.options, 'simulate', False)
+
+ # For #! situations:
+ if (os.environ.get('PASTE_CONFIG_FILE')
+ and self.takes_config_file is not None):
+ take = self.takes_config_file
+ filename = os.environ.get('PASTE_CONFIG_FILE')
+ if take == 1:
+ self.args.insert(0, filename)
+ elif take == -1:
+ self.args.append(filename)
+ else:
+ assert 0, (
+ "Value takes_config_file must be None, 1, or -1 (not %r)"
+ % take)
+
+ if (os.environ.get('PASTE_DEFAULT_QUIET')):
+ self.verbose = 0
+
+ # Validate:
+ if self.min_args is not None and len(self.args) < self.min_args:
+ raise BadCommand(
+ self.min_args_error % {'min_args': self.min_args,
+ 'actual_args': len(self.args)})
+ if self.max_args is not None and len(self.args) > self.max_args:
+ raise BadCommand(
+ self.max_args_error % {'max_args': self.max_args,
+ 'actual_args': len(self.args)})
+ for var_name, option_name in self.required_args:
+ if not getattr(self.options, var_name, None):
+ raise BadCommand(
+ 'You must provide the option %s' % option_name)
+ result = self.command()
+ if result is None:
+ return self.return_code
+ else:
+ return result
+
+ def parse_args(self, args):
+ if self.usage:
+ usage = ' '+self.usage
+ else:
+ usage = ''
+ self.parser.usage = "%%prog [options]%s\n%s" % (
+ usage, self.summary)
+ self.parser.prog = '%s %s' % (sys.argv[0], self.command_name)
+ if self.description:
+ desc = self.description
+ desc = textwrap.dedent(desc)
+ self.parser.description = desc
+ self.options, self.args = self.parser.parse_args(args)
+
+ ########################################
+ ## Utility methods
+ ########################################
+
+ def here(cls):
+ mod = sys.modules[cls.__module__]
+ return os.path.dirname(mod.__file__)
+
+ here = classmethod(here)
+
+ def ask(self, prompt, safe=False, default=True):
+ """
+ Prompt the user. Default can be true, false, ``'careful'`` or
+ ``'none'``. If ``'none'`` then the user must enter y/n. If
+ ``'careful'`` then the user must enter yes/no (long form).
+
+ If the interactive option is over two (``-ii``) then ``safe``
+ will be used as a default. This option should be the
+ do-nothing option.
+ """
+ # @@: Should careful be a separate argument?
+
+ if self.options.interactive >= 2:
+ default = safe
+ if default == 'careful':
+ prompt += ' [yes/no]?'
+ elif default == 'none':
+ prompt += ' [y/n]?'
+ elif default:
+ prompt += ' [Y/n]? '
+ else:
+ prompt += ' [y/N]? '
+ while 1:
+ response = raw_input(prompt).strip().lower()
+ if not response:
+ if default in ('careful', 'none'):
+ print 'Please enter yes or no'
+ continue
+ return default
+ if default == 'careful':
+ if response in ('yes', 'no'):
+ return response == 'yes'
+ print 'Please enter "yes" or "no"'
+ continue
+ if response[0].lower() in ('y', 'n'):
+ return response[0].lower() == 'y'
+ print 'Y or N please'
+
+ def challenge(self, prompt, default=NoDefault, should_echo=True):
+ """
+ Prompt the user for a variable.
+ """
+ if default is not NoDefault:
+ prompt += ' [%r]' % default
+ prompt += ': '
+ while 1:
+ if should_echo:
+ prompt_method = raw_input
+ else:
+ prompt_method = getpass.getpass
+ response = prompt_method(prompt).strip()
+ if not response:
+ if default is not NoDefault:
+ return default
+ else:
+ continue
+ else:
+ return response
+
+ def pad(self, s, length, dir='left'):
+ if len(s) >= length:
+ return s
+ if dir == 'left':
+ return s + ' '*(length-len(s))
+ else:
+ return ' '*(length-len(s)) + s
+
+ def standard_parser(cls, verbose=True,
+ interactive=False,
+ no_interactive=False,
+ simulate=False,
+ quiet=False,
+ overwrite=False):
+ """
+ Create a standard ``OptionParser`` instance.
+
+ Typically used like::
+
+ class MyCommand(Command):
+ parser = Command.standard_parser()
+
+ Subclasses may redefine ``standard_parser``, so use the
+ nearest superclass's class method.
+ """
+ parser = bool_optparse.BoolOptionParser()
+ if verbose:
+ parser.add_option('-v', '--verbose',
+ action='count',
+ dest='verbose',
+ default=0)
+ if quiet:
+ parser.add_option('-q', '--quiet',
+ action='count',
+ dest='quiet',
+ default=0)
+ if no_interactive:
+ parser.add_option('--no-interactive',
+ action="count",
+ dest="no_interactive",
+ default=0)
+ if interactive:
+ parser.add_option('-i', '--interactive',
+ action='count',
+ dest='interactive',
+ default=0)
+ if simulate:
+ parser.add_option('-n', '--simulate',
+ action='store_true',
+ dest='simulate',
+ default=False)
+ if overwrite:
+ parser.add_option('-f', '--overwrite',
+ dest="overwrite",
+ action="store_true",
+ help="Overwrite files (warnings will be emitted for non-matching files otherwise)")
+ return parser
+
+ standard_parser = classmethod(standard_parser)
+
+ def shorten(self, fn, *paths):
+ """
+ Return a shorted form of the filename (relative to the current
+ directory), typically for displaying in messages. If
+ ``*paths`` are present, then use os.path.join to create the
+ full filename before shortening.
+ """
+ if paths:
+ fn = os.path.join(fn, *paths)
+ if fn.startswith(os.getcwd()):
+ return fn[len(os.getcwd()):].lstrip(os.path.sep)
+ else:
+ return fn
+
+ def ensure_dir(self, dir, svn_add=True):
+ """
+ Ensure that the directory exists, creating it if necessary.
+ Respects verbosity and simulation.
+
+ Adds directory to subversion if ``.svn/`` directory exists in
+ parent, and directory was created.
+ """
+ dir = dir.rstrip(os.sep)
+ if not dir:
+ # we either reached the parent-most directory, or we got
+ # a relative directory
+ # @@: Should we make sure we resolve relative directories
+ # first? Though presumably the current directory always
+ # exists.
+ return
+ if not os.path.exists(dir):
+ self.ensure_dir(os.path.dirname(dir))
+ if self.verbose:
+ print 'Creating %s' % self.shorten(dir)
+ if not self.simulate:
+ os.mkdir(dir)
+ if (svn_add and
+ os.path.exists(os.path.join(os.path.dirname(dir), '.svn'))):
+ self.svn_command('add', dir)
+ else:
+ if self.verbose > 1:
+ print "Directory already exists: %s" % self.shorten(dir)
+
+ def ensure_file(self, filename, content, svn_add=True):
+ """
+ Ensure a file named ``filename`` exists with the given
+ content. If ``--interactive`` has been enabled, this will ask
+ the user what to do if a file exists with different content.
+ """
+ global difflib
+ assert content is not None, (
+ "You cannot pass a content of None")
+ self.ensure_dir(os.path.dirname(filename), svn_add=svn_add)
+ if not os.path.exists(filename):
+ if self.verbose:
+ print 'Creating %s' % filename
+ if not self.simulate:
+ f = open(filename, 'wb')
+ f.write(content)
+ f.close()
+ if svn_add and os.path.exists(os.path.join(os.path.dirname(filename), '.svn')):
+ self.svn_command('add', filename,
+ warn_returncode=True)
+ return
+ f = open(filename, 'rb')
+ old_content = f.read()
+ f.close()
+ if content == old_content:
+ if self.verbose > 1:
+ print 'File %s matches expected content' % filename
+ return
+ if not self.options.overwrite:
+ print 'Warning: file %s does not match expected content' % filename
+ if difflib is None:
+ import difflib
+ diff = difflib.context_diff(
+ content.splitlines(),
+ old_content.splitlines(),
+ 'expected ' + filename,
+ filename)
+ print '\n'.join(diff)
+ if self.interactive:
+ while 1:
+ s = raw_input(
+ 'Overwrite file with new content? [y/N] ').strip().lower()
+ if not s:
+ s = 'n'
+ if s.startswith('y'):
+ break
+ if s.startswith('n'):
+ return
+ print 'Unknown response; Y or N please'
+ else:
+ return
+
+ if self.verbose:
+ print 'Overwriting %s with new content' % filename
+ if not self.simulate:
+ f = open(filename, 'wb')
+ f.write(content)
+ f.close()
+
+ def insert_into_file(self, filename, marker_name, text,
+ indent=False):
+ """
+ Inserts ``text`` into the file, right after the given marker.
+ Markers look like: ``-*- <marker_name>[:]? -*-``, and the text
+ will go on the immediately following line.
+
+ Raises ``ValueError`` if the marker is not found.
+
+ If ``indent`` is true, then the text will be indented at the
+ same level as the marker.
+ """
+ if not text.endswith('\n'):
+ raise ValueError(
+ "The text must end with a newline: %r" % text)
+ if not os.path.exists(filename) and self.simulate:
+ # If we are doing a simulation, it's expected that some
+ # files won't exist...
+ if self.verbose:
+ print 'Would (if not simulating) insert text into %s' % (
+ self.shorten(filename))
+ return
+
+ f = open(filename)
+ lines = f.readlines()
+ f.close()
+ regex = re.compile(r'-\*-\s+%s:?\s+-\*-' % re.escape(marker_name),
+ re.I)
+ for i in range(len(lines)):
+ if regex.search(lines[i]):
+ # Found it!
+ if (lines[i:] and len(lines[i:]) > 1 and
+ ''.join(lines[i+1:]).strip().startswith(text.strip())):
+ # Already have it!
+ print 'Warning: line already found in %s (not inserting' % filename
+ print ' %s' % lines[i]
+ return
+
+ if indent:
+ text = text.lstrip()
+ match = re.search(r'^[ \t]*', lines[i])
+ text = match.group(0) + text
+ lines[i+1:i+1] = [text]
+ break
+ else:
+ errstr = (
+ "Marker '-*- %s -*-' not found in %s"
+ % (marker_name, filename))
+ if 1 or self.simulate: # @@: being permissive right now
+ print 'Warning: %s' % errstr
+ else:
+ raise ValueError(errstr)
+ if self.verbose:
+ print 'Updating %s' % self.shorten(filename)
+ if not self.simulate:
+ f = open(filename, 'w')
+ f.write(''.join(lines))
+ f.close()
+
+ def run_command(self, cmd, *args, **kw):
+ """
+ Runs the command, respecting verbosity and simulation.
+ Returns stdout, or None if simulating.
+
+ Keyword arguments:
+
+ cwd:
+ the current working directory to run the command in
+ capture_stderr:
+ if true, then both stdout and stderr will be returned
+ expect_returncode:
+ if true, then don't fail if the return code is not 0
+ force_no_simulate:
+ if true, run the command even if --simulate
+ """
+ cmd = self.quote_first_command_arg(cmd)
+ cwd = popdefault(kw, 'cwd', os.getcwd())
+ capture_stderr = popdefault(kw, 'capture_stderr', False)
+ expect_returncode = popdefault(kw, 'expect_returncode', False)
+ force = popdefault(kw, 'force_no_simulate', False)
+ warn_returncode = popdefault(kw, 'warn_returncode', False)
+ if warn_returncode:
+ expect_returncode = True
+ simulate = self.simulate
+ if force:
+ simulate = False
+ assert not kw, ("Arguments not expected: %s" % kw)
+ if capture_stderr:
+ stderr_pipe = subprocess.STDOUT
+ else:
+ stderr_pipe = subprocess.PIPE
+ try:
+ proc = subprocess.Popen([cmd] + list(args),
+ cwd=cwd,
+ stderr=stderr_pipe,
+ stdout=subprocess.PIPE)
+ except OSError, e:
+ if e.errno != 2:
+ # File not found
+ raise
+ raise OSError(
+ "The expected executable %s was not found (%s)"
+ % (cmd, e))
+ if self.verbose:
+ print 'Running %s %s' % (cmd, ' '.join(args))
+ if simulate:
+ return None
+ stdout, stderr = proc.communicate()
+ if proc.returncode and not expect_returncode:
+ if not self.verbose:
+ print 'Running %s %s' % (cmd, ' '.join(args))
+ print 'Error (exit code: %s)' % proc.returncode
+ if stderr:
+ print stderr
+ raise OSError("Error executing command %s" % cmd)
+ if self.verbose > 2:
+ if stderr:
+ print 'Command error output:'
+ print stderr
+ if stdout:
+ print 'Command output:'
+ print stdout
+ elif proc.returncode and warn_returncode:
+ print 'Warning: command failed (%s %s)' % (cmd, ' '.join(args))
+ print 'Exited with code %s' % proc.returncode
+ return stdout
+
+ def quote_first_command_arg(self, arg):
+ """
+ There's a bug in Windows when running an executable that's
+ located inside a path with a space in it. This method handles
+ that case, or on non-Windows systems or an executable with no
+ spaces, it just leaves well enough alone.
+ """
+ if (sys.platform != 'win32'
+ or ' ' not in arg):
+ # Problem does not apply:
+ return arg
+ try:
+ import win32api
+ except ImportError:
+ raise ValueError(
+ "The executable %r contains a space, and in order to "
+ "handle this issue you must have the win32api module "
+ "installed" % arg)
+ arg = win32api.GetShortPathName(arg)
+ return arg
+
+ _svn_failed = False
+
+ def svn_command(self, *args, **kw):
+ """
+ Run an svn command, but don't raise an exception if it fails.
+ """
+ try:
+ return self.run_command('svn', *args, **kw)
+ except OSError, e:
+ if not self._svn_failed:
+ print 'Unable to run svn command (%s); proceeding anyway' % e
+ self._svn_failed = True
+
+ def write_file(self, filename, content, source=None,
+ binary=True, svn_add=True):
+ """
+ Like ``ensure_file``, but without the interactivity. Mostly
+ deprecated. (I think I forgot it existed)
+ """
+ import warnings
+ warnings.warn(
+ "command.write_file has been replaced with "
+ "command.ensure_file",
+ DeprecationWarning, 2)
+ if os.path.exists(filename):
+ if binary:
+ f = open(filename, 'rb')
+ else:
+ f = open(filename, 'r')
+ old_content = f.read()
+ f.close()
+ if content == old_content:
+ if self.verbose:
+ print 'File %s exists with same content' % (
+ self.shorten(filename))
+ return
+ if (not self.simulate and self.options.interactive):
+ if not self.ask('Overwrite file %s?' % filename):
+ return
+ if self.verbose > 1 and source:
+ print 'Writing %s from %s' % (self.shorten(filename),
+ self.shorten(source))
+ elif self.verbose:
+ print 'Writing %s' % self.shorten(filename)
+ if not self.simulate:
+ already_existed = os.path.exists(filename)
+ if binary:
+ f = open(filename, 'wb')
+ else:
+ f = open(filename, 'w')
+ f.write(content)
+ f.close()
+ if (not already_existed
+ and svn_add
+ and os.path.exists(os.path.join(os.path.dirname(filename), '.svn'))):
+ self.svn_command('add', filename)
+
+ def parse_vars(self, args):
+ """
+ Given variables like ``['a=b', 'c=d']`` turns it into ``{'a':
+ 'b', 'c': 'd'}``
+ """
+ result = {}
+ for arg in args:
+ if '=' not in arg:
+ raise BadCommand(
+ 'Variable assignment %r invalid (no "=")'
+ % arg)
+ name, value = arg.split('=', 1)
+ result[name] = value
+ return result
+
+ def read_vars(self, config, section='pastescript'):
+ """
+ Given a configuration filename, this will return a map of values.
+ """
+ result = {}
+ p = ConfigParser.RawConfigParser()
+ p.read([config])
+ if p.has_section(section):
+ for key, value in p.items(section):
+ if key.endswith('__eval__'):
+ result[key[:-len('__eval__')]] = eval(value)
+ else:
+ result[key] = value
+ return result
+
+ def write_vars(self, config, vars, section='pastescript'):
+ """
+ Given a configuration filename, this will add items in the
+ vars mapping to the configuration file. Will create the
+ configuration file if it doesn't exist.
+ """
+ modified = False
+
+ p = ConfigParser.RawConfigParser()
+ if not os.path.exists(config):
+ f = open(config, 'w')
+ f.write('')
+ f.close()
+ modified = True
+ p.read([config])
+ if not p.has_section(section):
+ p.add_section(section)
+ modified = True
+
+ existing_options = p.options(section)
+ for key, value in vars.items():
+ if (key not in existing_options and
+ '%s__eval__' % key not in existing_options):
+ if not isinstance(value, str):
+ p.set(section, '%s__eval__' % key, repr(value))
+ else:
+ p.set(section, key, value)
+ modified = True
+
+ if modified:
+ p.write(open(config, 'w'))
+
+ def indent_block(self, text, indent=2, initial=None):
+ """
+ Indent the block of text (each line is indented). If you give
+ ``initial``, then that is used in lieue of ``indent`` for the
+ first line.
+ """
+ if initial is None:
+ initial = indent
+ lines = text.splitlines()
+ first = (' '*initial) + lines[0]
+ rest = [(' '*indent)+l for l in lines[1:]]
+ return '\n'.join([first]+rest)
+
+ def logging_file_config(self, config_file):
+ """
+ Setup logging via the logging module's fileConfig function with the
+ specified ``config_file``, if applicable.
+ """
+ parser = ConfigParser.ConfigParser()
+ parser.read([config_file])
+ if parser.has_section('loggers'):
+ fileConfig(config_file)
+
+class NotFoundCommand(Command):
+
+ def run(self, args):
+ #for name, value in os.environ.items():
+ # print '%s: %s' % (name, value)
+ #print sys.argv
+ print ('Command %r not known (you may need to run setup.py egg_info)'
+ % self.command_name)
+ commands = get_commands().items()
+ commands.sort()
+ if not commands:
+ print 'No commands registered.'
+ print 'Have you installed Paste Script?'
+ print '(try running python setup.py develop)'
+ return 2
+ print 'Known commands:'
+ longest = max([len(n) for n, c in commands])
+ for name, command in commands:
+ print ' %s %s' % (self.pad(name, length=longest),
+ command.load().summary)
+ return 2
+
+def popdefault(dict, name, default=None):
+ if name not in dict:
+ return default
+ else:
+ v = dict[name]
+ del dict[name]
+ return v
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/copydir.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/copydir.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/copydir.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,431 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import pkg_resources
+import sys
+if sys.version_info < (2, 4):
+ from paste.script.util import string24 as string
+else:
+ import string
+import cgi
+import urllib
+import re
+Cheetah = None
+try:
+ import subprocess
+except ImportError:
+ from paste.script.util import subprocess24 as subprocess
+import inspect
+
+class SkipTemplate(Exception):
+ """
+ Raised to indicate that the template should not be copied over.
+ Raise this exception during the substitution of your template
+ """
+
+def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
+ use_cheetah=False, sub_vars=True, interactive=False,
+ svn_add=True, overwrite=True, template_renderer=None):
+ """
+ Copies the ``source`` directory to the ``dest`` directory.
+
+ ``vars``: A dictionary of variables to use in any substitutions.
+
+ ``verbosity``: Higher numbers will show more about what is happening.
+
+ ``simulate``: If true, then don't actually *do* anything.
+
+ ``indent``: Indent any messages by this amount.
+
+ ``sub_vars``: If true, variables in ``_tmpl`` files and ``+var+``
+ in filenames will be substituted.
+
+ ``use_cheetah``: If true, then any templates encountered will be
+ substituted with Cheetah. Otherwise ``template_renderer`` or
+ ``string.Template`` will be used for templates.
+
+ ``svn_add``: If true, any files written out in directories with
+ ``.svn/`` directories will be added (via ``svn add``).
+
+ ``overwrite``: If false, then don't every overwrite anything.
+
+ ``interactive``: If you are overwriting a file and interactive is
+ true, then ask before overwriting.
+
+ ``template_renderer``: This is a function for rendering templates
+ (if you don't want to use Cheetah or string.Template). It should
+ have the signature ``template_renderer(content_as_string,
+ vars_as_dict, filename=filename)``.
+ """
+ # This allows you to use a leading +dot+ in filenames which would
+ # otherwise be skipped because leading dots make the file hidden:
+ vars.setdefault('dot', '.')
+ vars.setdefault('plus', '+')
+ use_pkg_resources = isinstance(source, tuple)
+ if use_pkg_resources:
+ names = pkg_resources.resource_listdir(source[0], source[1])
+ else:
+ names = os.listdir(source)
+ names.sort()
+ pad = ' '*(indent*2)
+ if not os.path.exists(dest):
+ if verbosity >= 1:
+ print '%sCreating %s/' % (pad, dest)
+ if not simulate:
+ svn_makedirs(dest, svn_add=svn_add, verbosity=verbosity,
+ pad=pad)
+ elif verbosity >= 2:
+ print '%sDirectory %s exists' % (pad, dest)
+ for name in names:
+ if use_pkg_resources:
+ full = '/'.join([source[1], name])
+ else:
+ full = os.path.join(source, name)
+ reason = should_skip_file(name)
+ if reason:
+ if verbosity >= 2:
+ reason = pad + reason % {'filename': full}
+ print reason
+ continue
+ if sub_vars:
+ dest_full = os.path.join(dest, substitute_filename(name, vars))
+ sub_file = False
+ if dest_full.endswith('_tmpl'):
+ dest_full = dest_full[:-5]
+ sub_file = sub_vars
+ if use_pkg_resources and pkg_resources.resource_isdir(source[0], full):
+ if verbosity:
+ print '%sRecursing into %s' % (pad, os.path.basename(full))
+ copy_dir((source[0], full), dest_full, vars, verbosity, simulate,
+ indent=indent+1, use_cheetah=use_cheetah,
+ sub_vars=sub_vars, interactive=interactive,
+ svn_add=svn_add, template_renderer=template_renderer)
+ continue
+ elif not use_pkg_resources and os.path.isdir(full):
+ if verbosity:
+ print '%sRecursing into %s' % (pad, os.path.basename(full))
+ copy_dir(full, dest_full, vars, verbosity, simulate,
+ indent=indent+1, use_cheetah=use_cheetah,
+ sub_vars=sub_vars, interactive=interactive,
+ svn_add=svn_add, template_renderer=template_renderer)
+ continue
+ elif use_pkg_resources:
+ content = pkg_resources.resource_string(source[0], full)
+ else:
+ f = open(full, 'rb')
+ content = f.read()
+ f.close()
+ if sub_file:
+ try:
+ content = substitute_content(content, vars, filename=full,
+ use_cheetah=use_cheetah,
+ template_renderer=template_renderer)
+ except SkipTemplate:
+ continue
+ if content is None:
+ continue
+ already_exists = os.path.exists(dest_full)
+ if already_exists:
+ f = open(dest_full, 'rb')
+ old_content = f.read()
+ f.close()
+ if old_content == content:
+ if verbosity:
+ print '%s%s already exists (same content)' % (pad, dest_full)
+ continue
+ if interactive:
+ if not query_interactive(
+ full, dest_full, content, old_content,
+ simulate=simulate):
+ continue
+ elif not overwrite:
+ continue
+ if verbosity and use_pkg_resources:
+ print '%sCopying %s to %s' % (pad, full, dest_full)
+ elif verbosity:
+ print '%sCopying %s to %s' % (pad, os.path.basename(full), dest_full)
+ if not simulate:
+ f = open(dest_full, 'wb')
+ f.write(content)
+ f.close()
+ if svn_add and not already_exists:
+ if not os.path.exists(os.path.join(os.path.dirname(os.path.abspath(dest_full)), '.svn')):
+ if verbosity > 1:
+ print '%s.svn/ does not exist; cannot add file' % pad
+ else:
+ cmd = ['svn', 'add', dest_full]
+ if verbosity > 1:
+ print '%sRunning: %s' % (pad, ' '.join(cmd))
+ if not simulate:
+ # @@: Should
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ if verbosity > 1 and stdout:
+ print 'Script output:'
+ print stdout
+ elif svn_add and already_exists and verbosity > 1:
+ print '%sFile already exists (not doing svn add)' % pad
+
+def should_skip_file(name):
+ """
+ Checks if a file should be skipped based on its name.
+
+ If it should be skipped, returns the reason, otherwise returns
+ None.
+ """
+ if name.startswith('.'):
+ return 'Skipping hidden file %(filename)s'
+ if name.endswith('~') or name.endswith('.bak'):
+ return 'Skipping backup file %(filename)s'
+ if name.endswith('.pyc'):
+ return 'Skipping .pyc file %(filename)s'
+ if name.endswith('$py.class'):
+ return 'Skipping $py.class file %(filename)s'
+ if name in ('CVS', '_darcs'):
+ return 'Skipping version control directory %(filename)s'
+ return None
+
+# Overridden on user's request:
+all_answer = None
+
+def query_interactive(src_fn, dest_fn, src_content, dest_content,
+ simulate):
+ global all_answer
+ from difflib import unified_diff, context_diff
+ u_diff = list(unified_diff(
+ dest_content.splitlines(),
+ src_content.splitlines(),
+ dest_fn, src_fn))
+ c_diff = list(context_diff(
+ dest_content.splitlines(),
+ src_content.splitlines(),
+ dest_fn, src_fn))
+ added = len([l for l in u_diff if l.startswith('+')
+ and not l.startswith('+++')])
+ removed = len([l for l in u_diff if l.startswith('-')
+ and not l.startswith('---')])
+ if added > removed:
+ msg = '; %i lines added' % (added-removed)
+ elif removed > added:
+ msg = '; %i lines removed' % (removed-added)
+ else:
+ msg = ''
+ print 'Replace %i bytes with %i bytes (%i/%i lines changed%s)' % (
+ len(dest_content), len(src_content),
+ removed, len(dest_content.splitlines()), msg)
+ prompt = 'Overwrite %s [y/n/d/B/?] ' % dest_fn
+ while 1:
+ if all_answer is None:
+ response = raw_input(prompt).strip().lower()
+ else:
+ response = all_answer
+ if not response or response[0] == 'b':
+ import shutil
+ new_dest_fn = dest_fn + '.bak'
+ n = 0
+ while os.path.exists(new_dest_fn):
+ n += 1
+ new_dest_fn = dest_fn + '.bak' + str(n)
+ print 'Backing up %s to %s' % (dest_fn, new_dest_fn)
+ if not simulate:
+ shutil.copyfile(dest_fn, new_dest_fn)
+ return True
+ elif response.startswith('all '):
+ rest = response[4:].strip()
+ if not rest or rest[0] not in ('y', 'n', 'b'):
+ print query_usage
+ continue
+ response = all_answer = rest[0]
+ if response[0] == 'y':
+ return True
+ elif response[0] == 'n':
+ return False
+ elif response == 'dc':
+ print '\n'.join(c_diff)
+ elif response[0] == 'd':
+ print '\n'.join(u_diff)
+ else:
+ print query_usage
+
+query_usage = """\
+Responses:
+ Y(es): Overwrite the file with the new content.
+ N(o): Do not overwrite the file.
+ D(iff): Show a unified diff of the proposed changes (dc=context diff)
+ B(ackup): Save the current file contents to a .bak file
+ (and overwrite)
+ Type "all Y/N/B" to use Y/N/B for answer to all future questions
+"""
+
+def svn_makedirs(dir, svn_add, verbosity, pad):
+ parent = os.path.dirname(os.path.abspath(dir))
+ if not os.path.exists(parent):
+ svn_makedirs(parent, svn_add, verbosity, pad)
+ os.mkdir(dir)
+ if not svn_add:
+ return
+ if not os.path.exists(os.path.join(parent, '.svn')):
+ if verbosity > 1:
+ print '%s.svn/ does not exist; cannot add directory' % pad
+ return
+ cmd = ['svn', 'add', dir]
+ if verbosity > 1:
+ print '%sRunning: %s' % (pad, ' '.join(cmd))
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ if verbosity > 1 and stdout:
+ print 'Script output:'
+ print stdout
+
+def substitute_filename(fn, vars):
+ for var, value in vars.items():
+ fn = fn.replace('+%s+' % var, str(value))
+ return fn
+
+def substitute_content(content, vars, filename='<string>',
+ use_cheetah=False, template_renderer=None):
+ global Cheetah
+ v = standard_vars.copy()
+ v.update(vars)
+ vars = v
+ if template_renderer is not None:
+ return template_renderer(content, vars, filename=filename)
+ if not use_cheetah:
+ tmpl = LaxTemplate(content)
+ try:
+ return tmpl.substitute(TypeMapper(v))
+ except Exception, e:
+ _add_except(e, ' in file %s' % filename)
+ raise
+ if Cheetah is None:
+ import Cheetah.Template
+ tmpl = Cheetah.Template.Template(source=content,
+ searchList=[vars])
+ return careful_sub(tmpl, vars, filename)
+
+def careful_sub(cheetah_template, vars, filename):
+ """
+ Substitutes the template with the variables, using the
+ .body() method if it exists. It assumes that the variables
+ were also passed in via the searchList.
+ """
+ if not hasattr(cheetah_template, 'body'):
+ return sub_catcher(filename, vars, str, cheetah_template)
+ body = cheetah_template.body
+ args, varargs, varkw, defaults = inspect.getargspec(body)
+ call_vars = {}
+ for arg in args:
+ if arg in vars:
+ call_vars[arg] = vars[arg]
+ return sub_catcher(filename, vars, body, **call_vars)
+
+def sub_catcher(filename, vars, func, *args, **kw):
+ """
+ Run a substitution, returning the value. If an error occurs, show
+ the filename. If the error is a NameError, show the variables.
+ """
+ try:
+ return func(*args, **kw)
+ except SkipTemplate, e:
+ print 'Skipping file %s' % filename
+ if str(e):
+ print str(e)
+ raise
+ except Exception, e:
+ print 'Error in file %s:' % filename
+ if isinstance(e, NameError):
+ items = vars.items()
+ items.sort()
+ for name, value in items:
+ print '%s = %r' % (name, value)
+ raise
+
+def html_quote(s):
+ if s is None:
+ return ''
+ return cgi.escape(str(s), 1)
+
+def url_quote(s):
+ if s is None:
+ return ''
+ return urllib.quote(str(s))
+
+def test(conf, true_cond, false_cond=None):
+ if conf:
+ return true_cond
+ else:
+ return false_cond
+
+def skip_template(condition=True, *args):
+ """
+ Raise SkipTemplate, which causes copydir to skip the template
+ being processed. If you pass in a condition, only raise if that
+ condition is true (allows you to use this with string.Template)
+
+ If you pass any additional arguments, they will be used to
+ instantiate SkipTemplate (generally use like
+ ``skip_template(license=='GPL', 'Skipping file; not using GPL')``)
+ """
+ if condition:
+ raise SkipTemplate(*args)
+
+def _add_except(exc, info):
+ if not hasattr(exc, 'args') or exc.args is None:
+ return
+ args = list(exc.args)
+ if args:
+ args[0] += ' ' + info
+ else:
+ args = [info]
+ exc.args = tuple(args)
+ return
+
+
+standard_vars = {
+ 'nothing': None,
+ 'html_quote': html_quote,
+ 'url_quote': url_quote,
+ 'empty': '""',
+ 'test': test,
+ 'repr': repr,
+ 'str': str,
+ 'bool': bool,
+ 'SkipTemplate': SkipTemplate,
+ 'skip_template': skip_template,
+ }
+
+class TypeMapper(dict):
+
+ def __getitem__(self, item):
+ options = item.split('|')
+ for op in options[:-1]:
+ try:
+ value = eval_with_catch(op, dict(self.items()))
+ break
+ except (NameError, KeyError):
+ pass
+ else:
+ value = eval(options[-1], dict(self.items()))
+ if value is None:
+ return ''
+ else:
+ return str(value)
+
+def eval_with_catch(expr, vars):
+ try:
+ return eval(expr, vars)
+ except Exception, e:
+ _add_except(e, 'in expression %r' % expr)
+ raise
+
+class LaxTemplate(string.Template):
+ # This change of pattern allows for anything in braces, but
+ # only identifiers outside of braces:
+ pattern = r"""
+ \$(?:
+ (?P<escaped>\$) | # Escape sequence of two delimiters
+ (?P<named>[_a-z][_a-z0-9]*) | # delimiter and a Python identifier
+ {(?P<braced>.*?)} | # delimiter and a braced identifier
+ (?P<invalid>) # Other ill-formed delimiter exprs
+ )
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/create_distro.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/create_distro.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/create_distro.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,417 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import re
+import sys
+import os
+import pkg_resources
+from command import Command, BadCommand
+import copydir
+import pluginlib
+import fnmatch
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+class CreateDistroCommand(Command):
+
+ usage = 'PACKAGE_NAME [VAR=VALUE VAR2=VALUE2 ...]'
+ summary = "Create the file layout for a Python distribution"
+ short_description = summary
+
+ description = """\
+ Create a new project. Projects are typically Python packages,
+ ready for distribution. Projects are created from templates, and
+ represent different kinds of projects -- associated with a
+ particular framework for instance.
+ """
+
+ parser = Command.standard_parser(
+ simulate=True, no_interactive=True, quiet=True, overwrite=True)
+ parser.add_option('-t', '--template',
+ dest='templates',
+ metavar='TEMPLATE',
+ action='append',
+ help="Add a template to the create process")
+ parser.add_option('-o', '--output-dir',
+ dest='output_dir',
+ metavar='DIR',
+ default='.',
+ help="Write put the directory into DIR (default current directory)")
+ parser.add_option('--svn-repository',
+ dest='svn_repository',
+ metavar='REPOS',
+ help="Create package at given repository location (this will create the standard trunk/ tags/ branches/ hierarchy)")
+ parser.add_option('--list-templates',
+ dest='list_templates',
+ action='store_true',
+ help="List all templates available")
+ parser.add_option('--list-variables',
+ dest="list_variables",
+ action="store_true",
+ help="List all variables expected by the given template (does not create a package)")
+ parser.add_option('--inspect-files',
+ dest='inspect_files',
+ action='store_true',
+ help="Show where the files in the given (already created) directory came from (useful when using multiple templates)")
+ parser.add_option('--config',
+ action='store',
+ dest='config',
+ help="Template variables file")
+
+ _bad_chars_re = re.compile('[^a-zA-Z0-9_]')
+
+ default_verbosity = 1
+ default_interactive = 1
+
+ def command(self):
+ if self.options.list_templates:
+ return self.list_templates()
+ asked_tmpls = self.options.templates or ['basic_package']
+ templates = []
+ for tmpl_name in asked_tmpls:
+ self.extend_templates(templates, tmpl_name)
+ if self.options.list_variables:
+ return self.list_variables(templates)
+ if self.verbose:
+ print 'Selected and implied templates:'
+ max_tmpl_name = max([len(tmpl_name) for tmpl_name, tmpl in templates])
+ for tmpl_name, tmpl in templates:
+ print ' %s%s %s' % (
+ tmpl_name, ' '*(max_tmpl_name-len(tmpl_name)),
+ tmpl.summary)
+ print
+ if not self.args:
+ if self.interactive:
+ dist_name = self.challenge('Enter project name')
+ else:
+ raise BadCommand('You must provide a PACKAGE_NAME')
+ else:
+ dist_name = self.args[0].lstrip(os.path.sep)
+
+ templates = [tmpl for name, tmpl in templates]
+ output_dir = os.path.join(self.options.output_dir, dist_name)
+
+ pkg_name = self._bad_chars_re.sub('', dist_name.lower())
+ vars = {'project': dist_name,
+ 'package': pkg_name,
+ 'egg': pluginlib.egg_name(dist_name),
+ }
+ vars.update(self.parse_vars(self.args[1:]))
+ if self.options.config and os.path.exists(self.options.config):
+ for key, value in self.read_vars(self.options.config).items():
+ vars.setdefault(key, value)
+
+ if self.verbose: # @@: > 1?
+ self.display_vars(vars)
+
+ if self.options.inspect_files:
+ self.inspect_files(
+ output_dir, templates, vars)
+ return
+ if not os.path.exists(output_dir):
+ # We want to avoid asking questions in copydir if the path
+ # doesn't exist yet
+ copydir.all_answer = 'y'
+
+ if self.options.svn_repository:
+ self.setup_svn_repository(output_dir, dist_name)
+
+ # First we want to make sure all the templates get a chance to
+ # set their variables, all at once, with the most specialized
+ # template going first (the last template is the most
+ # specialized)...
+ for template in templates[::-1]:
+ vars = template.check_vars(vars, self)
+
+ # Gather all the templates egg_plugins into one var
+ egg_plugins = set()
+ for template in templates:
+ egg_plugins.update(template.egg_plugins)
+ egg_plugins = list(egg_plugins)
+ egg_plugins.sort()
+ vars['egg_plugins'] = egg_plugins
+
+ for template in templates:
+ self.create_template(
+ template, output_dir, vars)
+
+ found_setup_py = False
+ paster_plugins_mtime = None
+ if os.path.exists(os.path.join(output_dir, 'setup.py')):
+ # Grab paster_plugins.txt's mtime; used to determine if the
+ # egg_info command wrote to it
+ try:
+ egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name)
+ except IOError:
+ egg_info_dir = None
+ if egg_info_dir is not None:
+ plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt')
+ if os.path.exists(plugins_path):
+ paster_plugins_mtime = os.path.getmtime(plugins_path)
+
+ self.run_command(sys.executable, 'setup.py', 'egg_info',
+ cwd=output_dir,
+ # This shouldn't be necessary, but a bug in setuptools 0.6c3 is causing a (not entirely fatal) problem that I don't want to fix right now:
+ expect_returncode=True)
+ found_setup_py = True
+ elif self.verbose > 1:
+ print 'No setup.py (cannot run egg_info)'
+
+ package_dir = vars.get('package_dir', None)
+ if package_dir:
+ output_dir = os.path.join(output_dir, package_dir)
+
+ # With no setup.py this doesn't make sense:
+ if found_setup_py:
+ # Only write paster_plugins.txt if it wasn't written by
+ # egg_info (the correct way). leaving us to do it is
+ # deprecated and you'll get warned
+ egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name)
+ plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt')
+ if len(egg_plugins) and (not os.path.exists(plugins_path) or \
+ os.path.getmtime(plugins_path) == paster_plugins_mtime):
+ if self.verbose:
+ print >> sys.stderr, \
+ ('Manually creating paster_plugins.txt (deprecated! '
+ 'pass a paster_plugins keyword to setup() instead)')
+ for plugin in egg_plugins:
+ if self.verbose:
+ print 'Adding %s to paster_plugins.txt' % plugin
+ if not self.simulate:
+ pluginlib.add_plugin(egg_info_dir, plugin)
+
+ if self.options.svn_repository:
+ self.add_svn_repository(vars, output_dir)
+
+ if self.options.config:
+ write_vars = vars.copy()
+ del write_vars['project']
+ del write_vars['package']
+ self.write_vars(self.options.config, write_vars)
+
+ def create_template(self, template, output_dir, vars):
+ if self.verbose:
+ print 'Creating template %s' % template.name
+ template.run(self, output_dir, vars)
+
+ def setup_svn_repository(self, output_dir, dist_name):
+ # @@: Use subprocess
+ svn_repos = self.options.svn_repository
+ svn_repos_path = os.path.join(svn_repos, dist_name).replace('\\','/')
+ svn_command = 'svn'
+ if sys.platform == 'win32':
+ svn_command += '.exe'
+ # @@: The previous method of formatting this string using \ doesn't work on Windows
+ cmd = '%(svn_command)s mkdir %(svn_repos_path)s' + \
+ ' %(svn_repos_path)s/trunk %(svn_repos_path)s/tags' + \
+ ' %(svn_repos_path)s/branches -m "New project %(dist_name)s"'
+ cmd = cmd % {
+ 'svn_repos_path': svn_repos_path,
+ 'dist_name': dist_name,
+ 'svn_command':svn_command,
+ }
+ if self.verbose:
+ print "Running:"
+ print cmd
+ if not self.simulate:
+ os.system(cmd)
+ svn_repos_path_trunk = os.path.join(svn_repos_path,'trunk').replace('\\','/')
+ cmd = svn_command+' co "%s" "%s"' % (svn_repos_path_trunk, output_dir)
+ if self.verbose:
+ print "Running %s" % cmd
+ if not self.simulate:
+ os.system(cmd)
+
+ ignore_egg_info_files = [
+ 'top_level.txt',
+ 'entry_points.txt',
+ 'requires.txt',
+ 'PKG-INFO',
+ 'namespace_packages.txt',
+ 'SOURCES.txt',
+ 'dependency_links.txt',
+ 'not-zip-safe']
+
+ def add_svn_repository(self, vars, output_dir):
+ svn_repos = self.options.svn_repository
+ egg_info_dir = pluginlib.egg_info_dir(output_dir, vars['project'])
+ svn_command = 'svn'
+ if sys.platform == 'win32':
+ svn_command += '.exe'
+ self.run_command(svn_command, 'add', '-N', egg_info_dir)
+ paster_plugins_file = os.path.join(
+ egg_info_dir, 'paster_plugins.txt')
+ if os.path.exists(paster_plugins_file):
+ self.run_command(svn_command, 'add', paster_plugins_file)
+ self.run_command(svn_command, 'ps', 'svn:ignore',
+ '\n'.join(self.ignore_egg_info_files),
+ egg_info_dir)
+ if self.verbose:
+ print ("You must next run 'svn commit' to commit the "
+ "files to repository")
+
+ def extend_templates(self, templates, tmpl_name):
+ if '#' in tmpl_name:
+ dist_name, tmpl_name = tmpl_name.split('#', 1)
+ else:
+ dist_name, tmpl_name = None, tmpl_name
+ if dist_name is None:
+ for entry in self.all_entry_points():
+ if entry.name == tmpl_name:
+ tmpl = entry.load()(entry.name)
+ dist_name = entry.dist.project_name
+ break
+ else:
+ raise LookupError(
+ 'Template by name %r not found' % tmpl_name)
+ else:
+ dist = pkg_resources.get_distribution(dist_name)
+ entry = dist.get_entry_info(
+ 'paste.paster_create_template', tmpl_name)
+ tmpl = entry.load()(entry.name)
+ full_name = '%s#%s' % (dist_name, tmpl_name)
+ for item_full_name, item_tmpl in templates:
+ if item_full_name == full_name:
+ # Already loaded
+ return
+ for req_name in tmpl.required_templates:
+ self.extend_templates(templates, req_name)
+ templates.append((full_name, tmpl))
+
+ def all_entry_points(self):
+ if not hasattr(self, '_entry_points'):
+ self._entry_points = list(pkg_resources.iter_entry_points(
+ 'paste.paster_create_template'))
+ return self._entry_points
+
+ def display_vars(self, vars):
+ vars = vars.items()
+ vars.sort()
+ print 'Variables:'
+ max_var = max([len(n) for n, v in vars])
+ for name, value in vars:
+ print ' %s:%s %s' % (
+ name, ' '*(max_var-len(name)), value)
+
+ def list_templates(self):
+ templates = []
+ for entry in self.all_entry_points():
+ try:
+ templates.append(entry.load()(entry.name))
+ except Exception, e:
+ # We will not be stopped!
+ print 'Warning: could not load entry point %s (%s: %s)' % (
+ entry.name, e.__class__.__name__, e)
+ max_name = max([len(t.name) for t in templates])
+ templates.sort(lambda a, b: cmp(a.name, b.name))
+ print 'Available templates:'
+ for template in templates:
+ # @@: Wrap description
+ print ' %s:%s %s' % (
+ template.name,
+ ' '*(max_name-len(template.name)),
+ template.summary)
+
+ def inspect_files(self, output_dir, templates, vars):
+ file_sources = {}
+ for template in templates:
+ self._find_files(template, vars, file_sources)
+ self._show_files(output_dir, file_sources)
+ self._show_leftovers(output_dir, file_sources)
+
+ def _find_files(self, template, vars, file_sources):
+ tmpl_dir = template.template_dir()
+ self._find_template_files(
+ template, tmpl_dir, vars, file_sources)
+
+ def _find_template_files(self, template, tmpl_dir, vars,
+ file_sources, join=''):
+ full_dir = os.path.join(tmpl_dir, join)
+ for name in os.listdir(full_dir):
+ if name.startswith('.'):
+ continue
+ if os.path.isdir(os.path.join(full_dir, name)):
+ self._find_template_files(
+ template, tmpl_dir, vars, file_sources,
+ join=os.path.join(join, name))
+ continue
+ partial = os.path.join(join, name)
+ for name, value in vars.items():
+ partial = partial.replace('+%s+' % name, value)
+ if partial.endswith('_tmpl'):
+ partial = partial[:-5]
+ file_sources.setdefault(partial, []).append(template)
+
+ _ignore_filenames = ['.*', '*.pyc', '*.bak*']
+ _ignore_dirs = ['CVS', '_darcs', '.svn']
+
+ def _show_files(self, output_dir, file_sources, join='', indent=0):
+ pad = ' '*(2*indent)
+ full_dir = os.path.join(output_dir, join)
+ names = os.listdir(full_dir)
+ dirs = [n for n in names
+ if os.path.isdir(os.path.join(full_dir, n))]
+ fns = [n for n in names
+ if not os.path.isdir(os.path.join(full_dir, n))]
+ dirs.sort()
+ names.sort()
+ for name in names:
+ skip_this = False
+ for ext in self._ignore_filenames:
+ if fnmatch.fnmatch(name, ext):
+ if self.verbose > 1:
+ print '%sIgnoring %s' % (pad, name)
+ skip_this = True
+ break
+ if skip_this:
+ continue
+ partial = os.path.join(join, name)
+ if partial not in file_sources:
+ if self.verbose > 1:
+ print '%s%s (not from template)' % (pad, name)
+ continue
+ templates = file_sources.pop(partial)
+ print '%s%s from:' % (pad, name)
+ for template in templates:
+ print '%s %s' % (pad, template.name)
+ for dir in dirs:
+ if dir in self._ignore_dirs:
+ continue
+ print '%sRecursing into %s/' % (pad, dir)
+ self._show_files(
+ output_dir, file_sources,
+ join=os.path.join(join, dir),
+ indent=indent+1)
+
+ def _show_leftovers(self, output_dir, file_sources):
+ if not file_sources:
+ return
+ print
+ print 'These files were supposed to be generated by templates'
+ print 'but were not found:'
+ file_sources = file_sources.items()
+ file_sources.sort()
+ for partial, templates in file_sources:
+ print ' %s from:' % partial
+ for template in templates:
+ print ' %s' % template.name
+
+ def list_variables(self, templates):
+ for tmpl_name, tmpl in templates:
+ if not tmpl.read_vars():
+ if self.verbose > 1:
+ self._show_template_vars(
+ tmpl_name, tmpl, 'No variables found')
+ continue
+ self._show_template_vars(tmpl_name, tmpl)
+
+ def _show_template_vars(self, tmpl_name, tmpl, message=None):
+ title = '%s (from %s)' % (tmpl.name, tmpl_name)
+ print title
+ print '-'*len(title)
+ if message is not None:
+ print ' %s' % message
+ print
+ return
+ tmpl.print_vars(indent=2)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/default_sysconfig.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/default_sysconfig.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/default_sysconfig.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+This module contains default sysconfig settings.
+
+The command object is inserted into this module as a global variable
+``paste_command``, and can be used inside functions.
+"""
+
+def add_custom_options(parser):
+ """
+ This method can modify the ``parser`` object (which is an
+ ``optparse.OptionParser`` instance). This can be used to add new
+ options to the command.
+ """
+ pass
+
+def default_config_filename(installer):
+ """
+ This function can return a default filename or directory for the
+ configuration file, if none was explicitly given.
+
+ Return None to mean no preference. The first non-None returning
+ value will be used.
+
+ Pay attention to ``installer.expect_config_directory`` here,
+ and to ``installer.default_config_filename``.
+ """
+ return installer.default_config_filename
+
+def install_variables(installer):
+ """
+ Returns a dictionary of variables for use later in the process
+ (e.g., filling a configuration file). These are combined from all
+ sysconfig files.
+ """
+ return {}
+
+def post_setup_hook(installer, config_file):
+ """
+ This is called at the very end of ``paster setup-app``. You
+ might use it to register an application globally.
+ """
+ pass
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/entrypoints.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/entrypoints.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/entrypoints.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,269 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import textwrap
+import os
+import pkg_resources
+from command import Command, BadCommand
+import fnmatch
+import re
+import traceback
+from cStringIO import StringIO
+import inspect
+import types
+
+class EntryPointCommand(Command):
+
+ usage = "ENTRY_POINT"
+ summary = "Show information about entry points"
+
+ description = """\
+ Shows information about one or many entry points (you can use
+ wildcards for entry point names). Entry points are used for Egg
+ plugins, and are named resources -- like an application, template
+ plugin, or other resource. Entry points have a [group] which
+ defines what kind of object they describe, and inside groups each
+ entry point is named.
+ """
+
+ max_args = 2
+
+ parser = Command.standard_parser(verbose=False)
+ parser.add_option('--list', '-l',
+ dest='list_entry_points',
+ action='store_true',
+ help='List all the kinds of entry points on the system')
+ parser.add_option('--egg', '-e',
+ dest='show_egg',
+ help="Show all the entry points for the given Egg")
+ parser.add_option('--regex',
+ dest='use_regex',
+ action='store_true',
+ help="Make pattern match as regular expression, not just a wildcard pattern")
+
+ def command(self):
+ if self.options.list_entry_points:
+ return self.list_entry_points()
+ if self.options.show_egg:
+ return self.show_egg(self.options.show_egg)
+ if not self.args:
+ raise BadCommand("You must give an entry point (or --list)")
+ pattern = self.get_pattern(self.args[0])
+ groups = self.get_groups_by_pattern(pattern)
+ if not groups:
+ raise BadCommand('No group matched %s' % self.args[0])
+ ep_pat = None
+ if len(self.args) > 1:
+ ep_pat = self.get_pattern(self.args[1])
+ for group in groups:
+ desc = self.get_group_description(group)
+ print '[%s]' % group
+ if desc:
+ print self.wrap(desc)
+ print
+ by_dist = {}
+ self.print_entry_points_by_group(group, ep_pat)
+
+ def print_entry_points_by_group(self, group, ep_pat):
+ env = pkg_resources.Environment()
+ project_names = list(env)
+ project_names.sort()
+ for project_name in project_names:
+ dists = list(env[project_name])
+ assert dists
+ dist = dists[0]
+ entries = dist.get_entry_map(group).values()
+ if ep_pat:
+ entries = [e for e in entries
+ if ep_pat.search(e.name)]
+ if not entries:
+ continue
+ if len(dists) > 1:
+ print '%s (+ %i older versions)' % (
+ dist, len(dists)-1)
+ else:
+ print '%s' % dist
+ entries.sort(lambda a, b: cmp(a.name, b.name))
+ for entry in entries:
+ print self._ep_description(entry)
+ desc = self.get_entry_point_description(entry, group)
+ if desc and desc.description:
+ print self.wrap(desc.description, indent=4)
+
+ def show_egg(self, egg_name):
+ group_pat = None
+ if self.args:
+ group_pat = self.get_pattern(self.args[0])
+ ep_pat = None
+ if len(self.args) > 1:
+ ep_pat = self.get_pattern(self.args[1])
+ if egg_name.startswith('egg:'):
+ egg_name = egg_name[4:]
+ dist = pkg_resources.get_distribution(egg_name)
+ entry_map = dist.get_entry_map()
+ entry_groups = entry_map.items()
+ entry_groups.sort()
+ for group, points in entry_groups:
+ if group_pat and not group_pat.search(group):
+ continue
+ print '[%s]' % group
+ points = points.items()
+ points.sort()
+ for name, entry in points:
+ if ep_pat:
+ if not ep_pat.search(name):
+ continue
+ print self._ep_description(entry)
+ desc = self.get_entry_point_description(entry, group)
+ if desc and desc.description:
+ print self.wrap(desc.description, indent=2)
+ print
+
+ def wrap(self, text, indent=0):
+ text = dedent(text)
+ width = int(os.environ.get('COLUMNS', 70)) - indent
+ text = '\n'.join([line.rstrip() for line in text.splitlines()])
+ paras = text.split('\n\n')
+ new_paras = []
+ for para in paras:
+ if para.lstrip() == para:
+ # leading whitespace means don't rewrap
+ para = '\n'.join(textwrap.wrap(para, width))
+ new_paras.append(para)
+ text = '\n\n'.join(new_paras)
+ lines = [' '*indent + line
+ for line in text.splitlines()]
+ return '\n'.join(lines)
+
+ def _ep_description(self, ep, pad_name=None):
+ name = ep.name
+ if pad_name is not None:
+ name = name + ' '*(pad_name-len(name))
+ dest = ep.module_name
+ if ep.attrs:
+ dest = dest + ':' + '.'.join(ep.attrs)
+ return '%s = %s' % (name, dest)
+
+ def get_pattern(self, s):
+ if not s:
+ return None
+ if self.options.use_regex:
+ return re.compile(s)
+ else:
+ return re.compile(fnmatch.translate(s), re.I)
+
+ def list_entry_points(self):
+ pattern = self.get_pattern(self.args and self.args[0])
+ groups = self.get_groups_by_pattern(pattern)
+ print '%i entry point groups found:' % len(groups)
+ for group in groups:
+ desc = self.get_group_description(group)
+ print '[%s]' % group
+ if desc:
+ if hasattr(desc, 'description'):
+ desc = desc.description
+ print self.wrap(desc, indent=2)
+
+ def get_groups_by_pattern(self, pattern):
+ env = pkg_resources.Environment()
+ eps = {}
+ for project_name in env:
+ for dist in env[project_name]:
+ for name in pkg_resources.get_entry_map(dist):
+ if pattern and not pattern.search(name):
+ continue
+ if (not pattern
+ and name.startswith('paste.description.')):
+ continue
+ eps[name] = None
+ eps = eps.keys()
+ eps.sort()
+ return eps
+
+ def get_group_description(self, group):
+ for entry in pkg_resources.iter_entry_points('paste.entry_point_description'):
+ if entry.name == group:
+ ep = entry.load()
+ if hasattr(ep, 'description'):
+ return ep.description
+ else:
+ return ep
+ return None
+
+ def get_entry_point_description(self, ep, group):
+ try:
+ return self._safe_get_entry_point_description(ep, group)
+ except Exception, e:
+ out = StringIO()
+ traceback.print_exc(file=out)
+ return ErrorDescription(e, out.getvalue())
+
+ def _safe_get_entry_point_description(self, ep, group):
+ ep.dist.activate()
+ meta_group = 'paste.description.'+group
+ meta = ep.dist.get_entry_info(meta_group, ep.name)
+ if not meta:
+ generic = list(pkg_resources.iter_entry_points(
+ meta_group, 'generic'))
+ if not generic:
+ return super_generic(ep.load())
+ # @@: Error if len(generic) > 1?
+ obj = generic[0].load()
+ desc = obj(ep, group)
+ else:
+ desc = meta.load()
+ return desc
+
+class EntryPointDescription(object):
+
+ def __init__(self, group):
+ self.group = group
+
+ # Should define:
+ # * description
+
+class SuperGeneric(object):
+
+ def __init__(self, doc_object):
+ self.doc_object = doc_object
+ self.description = dedent(self.doc_object.__doc__)
+ try:
+ if isinstance(self.doc_object, (type, types.ClassType)):
+ func = self.doc_object.__init__.im_func
+ elif (hasattr(self.doc_object, '__call__')
+ and not isinstance(self.doc_object, types.FunctionType)):
+ func = self.doc_object.__call__
+ else:
+ func = self.doc_object
+ if hasattr(func, '__paste_sig__'):
+ sig = func.__paste_sig__
+ else:
+ sig = inspect.getargspec(func)
+ sig = inspect.formatargspec(*sig)
+ except TypeError:
+ sig = None
+ if sig:
+ if self.description:
+ self.description = '%s\n\n%s' % (
+ sig, self.description)
+ else:
+ self.description = sig
+
+def dedent(s):
+ if s is None:
+ return s
+ s = s.strip('\n').strip('\r')
+ return textwrap.dedent(s)
+
+def super_generic(obj):
+ desc = SuperGeneric(obj)
+ if not desc.description:
+ return None
+ return desc
+
+class ErrorDescription(object):
+
+ def __init__(self, exc, tb):
+ self.exc = exc
+ self.tb = '\n'.join(tb)
+ self.description = 'Error loading: %s' % exc
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/epdesc.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/epdesc.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/epdesc.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,57 @@
+class MetaEntryPointDescription(object):
+ description = """
+ This is an entry point that describes other entry points.
+ """
+
+class CreateTemplateDescription(object):
+ description = """
+ Entry point for creating the file layout for a new project
+ from a template.
+ """
+
+class PasterCommandDescription(object):
+ description = """
+ Entry point that adds a command to the ``paster`` script
+ to a project that has specifically enabled the command.
+ """
+
+class GlobalPasterCommandDescription(object):
+ description = """
+ Entry point that adds a command to the ``paster`` script
+ globally.
+ """
+
+class AppInstallDescription(object):
+ description = """
+ This defines a runner that can install the application given a
+ configuration file.
+ """
+
+##################################################
+## Not in Paste per se, but we'll document
+## them...
+
+class ConsoleScriptsDescription(object):
+ description = """
+ When a package is installed, any entry point listed here will be
+ turned into a command-line script.
+ """
+
+class DistutilsCommandsDescription(object):
+ description = """
+ This will add a new command when running
+ ``python setup.py entry-point-name`` if the
+ package uses setuptools.
+ """
+
+class SetupKeywordsDescription(object):
+ description = """
+ This adds a new keyword to setup.py's setup() function, and a
+ validator to validate the value.
+ """
+
+class EggInfoWriters(object):
+ description = """
+ This adds a new writer that creates files in the PkgName.egg-info/
+ directory.
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/exe.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/exe.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/exe.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,107 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import re
+import os
+import sys
+import shlex
+import pkg_resources
+import command
+
+class ExeCommand(command.Command):
+
+ parser = command.Command.standard_parser(verbose=False)
+ summary = "Run #! executable files"
+ description = """\
+Use this at the top of files like:
+
+ #!/usr/bin/env /path/to/paster exe subcommand <command options>
+
+The rest of the file will be used as a config file for the given
+command, if it wants a config file.
+
+You can also include an [exe] section in the file, which looks
+like:
+
+ [exe]
+ command = serve
+ log_file = /path/to/log
+ add = /path/to/other/config.ini
+
+Which translates to:
+
+ paster serve --log-file=/path/to/log /path/to/other/config.ini
+"""
+
+ hidden = True
+
+ _exe_section_re = re.compile(r'^\s*\[\s*exe\s*\]\s*$')
+ _section_re = re.compile(r'^\s*\[')
+
+ def run(self, argv):
+ if argv and argv[0] in ('-h', '--help'):
+ print self.description
+ return
+
+ if os.environ.get('REQUEST_METHOD'):
+ # We're probably in a CGI environment
+ sys.stdout = sys.stderr
+ os.environ['PASTE_DEFAULT_QUIET'] = 'true'
+ # Maybe import cgitb or something?
+
+ if '_' not in os.environ:
+ print "Warning: this command is intended to be run with a #! like:"
+ print " #!/usr/bin/env paster exe"
+ print "It only works with /usr/bin/env, and only as a #! line."
+ # Should I actually shlex.split the args?
+ filename = argv[-1]
+ args = argv[:-1]
+ extra_args = []
+ else:
+ filename = os.environ['_']
+ extra_args = argv[:]
+ args = []
+ while extra_args:
+ if extra_args[0] == filename:
+ extra_args.pop(0)
+ break
+ args.append(extra_args.pop(0))
+ vars = {'here': os.path.dirname(filename),
+ '__file__': filename}
+ f = open(filename)
+ lines = f.readlines()
+ f.close()
+ options = {}
+ lineno = 1
+ while lines:
+ if self._exe_section_re.search(lines[0]):
+ lines.pop(0)
+ break
+ lines.pop(0)
+ lineno += 1
+ pre_options = []
+ options = args
+ for line in lines:
+ lineno += 1
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ if self._section_re.search(line):
+ break
+ if '=' not in line:
+ raise command.BadCommand('Missing = in %s at %s: %r'
+ % (filename, lineno, line))
+ name, value = line.split('=', 1)
+ name = name.strip()
+ value = value.strip()
+ if name == 'require':
+ pkg_resources.require(value)
+ elif name == 'command' or name == 'add':
+ options.extend(shlex.split(value))
+ elif name == 'plugin':
+ options[:0] = ['--plugin', value]
+ else:
+ value = value % vars
+ options.append('--%s=%s' % (name.replace('_', '-'), value))
+ os.environ['PASTE_CONFIG_FILE'] = filename
+ options.extend(extra_args)
+ command.run(options)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/filemaker.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/filemaker.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/filemaker.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,362 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import glob
+import pkg_resources
+from paste.script import pluginlib, copydir
+from paste.script.command import BadCommand
+difflib = None
+try:
+ import subprocess
+except ImportError:
+ from paste.script.util import subprocess24 as subprocess
+
+class FileOp(object):
+ """
+ Enhance the ease of file copying/processing from a package into a target
+ project
+ """
+
+ def __init__(self, simulate=False,
+ verbose=True,
+ interactive=True,
+ source_dir=None,
+ template_vars=None):
+ """
+ Initialize our File operation helper object
+
+ source_dir
+ Should refer to the directory within the package
+ that contains the templates to be used for the other copy
+ operations. It is assumed that packages will keep all their
+ templates under a hierarchy starting here.
+
+ This should be an absolute path passed in, for example::
+
+ FileOp(source_dir=os.path.dirname(__file__) + '/templates')
+ """
+ self.simulate = simulate
+ self.verbose = verbose
+ self.interactive = interactive
+ if template_vars is None:
+ template_vars = {}
+ self.template_vars = template_vars
+ self.source_dir = source_dir
+ self.use_pkg_resources = isinstance(source_dir, tuple)
+
+ def copy_file(self, template, dest, filename=None, add_py=True, package=True,
+ template_renderer=None):
+ """
+ Copy a file from the source location to somewhere in the
+ destination.
+
+ template
+ The filename underneath self.source_dir to copy/process
+ dest
+ The destination directory in the project relative to where
+ this command is being run
+ filename
+ What to name the file in the target project, use the same name
+ as the template if not provided
+ add_py
+ Add a .py extension to all files copied
+ package
+ Whether or not this file is part of a Python package, and any
+ directories created should contain a __init__.py file as well.
+ template_renderer
+ An optional template renderer
+
+ """
+ if not filename:
+ filename = template.split('/')[0]
+ if filename.endswith('_tmpl'):
+ filename = filename[:-5]
+ base_package, cdir = self.find_dir(dest, package)
+ self.template_vars['base_package'] = base_package
+ content = self.load_content(base_package, cdir, filename, template,
+ template_renderer=template_renderer)
+ if add_py:
+ # @@: Why is it a default to add a .py extension?
+ filename = '%s.py' % filename
+ dest = os.path.join(cdir, filename)
+ self.ensure_file(dest, content, package)
+
+ def copy_dir(self, template_dir, dest, destname=None, package=True):
+ """
+ Copy a directory recursively, processing any files within it
+ that need to be processed (end in _tmpl).
+
+ template_dir
+ Directory under self.source_dir to copy/process
+ dest
+ Destination directory into which this directory will be copied
+ to.
+ destname
+ Use this name instead of the original template_dir name for
+ creating the directory
+ package
+ This directory will be a Python package and needs to have a
+ __init__.py file.
+ """
+ # @@: This should actually be implemented
+ raise NotImplementedError
+
+ def load_content(self, base_package, base, name, template,
+ template_renderer=None):
+ blank = os.path.join(base, name + '.py')
+ read_content = True
+ if not os.path.exists(blank):
+ if self.use_pkg_resources:
+ fullpath = '/'.join([self.source_dir[1], template])
+ content = pkg_resources.resource_string(
+ self.source_dir[0], fullpath)
+ read_content = False
+ blank = fullpath
+ else:
+ blank = os.path.join(self.source_dir,
+ template)
+ if read_content:
+ f = open(blank, 'r')
+ content = f.read()
+ f.close()
+ if blank.endswith('_tmpl'):
+ content = copydir.substitute_content(
+ content, self.template_vars, filename=blank,
+ template_renderer=template_renderer)
+ return content
+
+ def find_dir(self, dirname, package=False):
+ egg_info = pluginlib.find_egg_info_dir(os.getcwd())
+ # @@: Should give error about egg_info when top_level.txt missing
+ f = open(os.path.join(egg_info, 'top_level.txt'))
+ packages = [l.strip() for l in f.readlines()
+ if l.strip() and not l.strip().startswith('#')]
+ f.close()
+ if not len(packages):
+ raise BadCommand("No top level dir found for %s" % dirname)
+ # @@: This doesn't support deeper servlet directories,
+ # or packages not kept at the top level.
+ base = os.path.dirname(egg_info)
+ possible = []
+ for pkg in packages:
+ d = os.path.join(base, pkg, dirname)
+ if os.path.exists(d):
+ possible.append((pkg, d))
+ if not possible:
+ self.ensure_dir(os.path.join(base, packages[0], dirname),
+ package=package)
+ return self.find_dir(dirname)
+ if len(possible) > 1:
+ raise BadCommand(
+ "Multiple %s dirs found (%s)" % (dirname, possible))
+ return possible[0]
+
+ def parse_path_name_args(self, name):
+ """
+ Given the name, assume that the first argument is a path/filename
+ combination. Return the name and dir of this. If the name ends with
+ '.py' that will be erased.
+
+ Examples:
+ comments -> comments, ''
+ admin/comments -> comments, 'admin'
+ h/ab/fred -> fred, 'h/ab'
+ """
+ if name.endswith('.py'):
+ # Erase extensions
+ name = name[:-3]
+ if '.' in name:
+ # Turn into directory name:
+ name = name.replace('.', os.path.sep)
+ if '/' != os.path.sep:
+ name = name.replace('/', os.path.sep)
+ parts = name.split(os.path.sep)
+ name = parts[-1]
+ if not parts[:-1]:
+ dir = ''
+ elif len(parts[:-1]) == 1:
+ dir = parts[0]
+ else:
+ dir = os.path.join(*parts[:-1])
+ return name, dir
+
+ def ensure_dir(self, dir, svn_add=True, package=False):
+ """
+ Ensure that the directory exists, creating it if necessary.
+ Respects verbosity and simulation.
+
+ Adds directory to subversion if ``.svn/`` directory exists in
+ parent, and directory was created.
+
+ package
+ If package is True, any directories created will contain a
+ __init__.py file.
+
+ """
+ dir = dir.rstrip(os.sep)
+ if not dir:
+ # we either reached the parent-most directory, or we got
+ # a relative directory
+ # @@: Should we make sure we resolve relative directories
+ # first? Though presumably the current directory always
+ # exists.
+ return
+ if not os.path.exists(dir):
+ self.ensure_dir(os.path.dirname(dir), svn_add=svn_add, package=package)
+ if self.verbose:
+ print 'Creating %s' % self.shorten(dir)
+ if not self.simulate:
+ os.mkdir(dir)
+ if (svn_add and
+ os.path.exists(os.path.join(os.path.dirname(dir), '.svn'))):
+ self.svn_command('add', dir)
+ if package:
+ initfile = os.path.join(dir, '__init__.py')
+ f = open(initfile, 'wb')
+ f.write("#\n")
+ f.close()
+ print 'Creating %s' % self.shorten(initfile)
+ if (svn_add and
+ os.path.exists(os.path.join(os.path.dirname(dir), '.svn'))):
+ self.svn_command('add', initfile)
+ else:
+ if self.verbose > 1:
+ print "Directory already exists: %s" % self.shorten(dir)
+
+ def ensure_file(self, filename, content, svn_add=True, package=False):
+ """
+ Ensure a file named ``filename`` exists with the given
+ content. If ``--interactive`` has been enabled, this will ask
+ the user what to do if a file exists with different content.
+ """
+ global difflib
+ self.ensure_dir(os.path.dirname(filename), svn_add=svn_add, package=package)
+ if not os.path.exists(filename):
+ if self.verbose:
+ print 'Creating %s' % filename
+ if not self.simulate:
+ f = open(filename, 'wb')
+ f.write(content)
+ f.close()
+ if svn_add and os.path.exists(os.path.join(os.path.dirname(filename), '.svn')):
+ self.svn_command('add', filename)
+ return
+ f = open(filename, 'rb')
+ old_content = f.read()
+ f.close()
+ if content == old_content:
+ if self.verbose > 1:
+ print 'File %s matches expected content' % filename
+ return
+ if self.interactive:
+ print 'Warning: file %s does not match expected content' % filename
+ if difflib is None:
+ import difflib
+ diff = difflib.context_diff(
+ content.splitlines(),
+ old_content.splitlines(),
+ 'expected ' + filename,
+ filename)
+ print '\n'.join(diff)
+ if self.interactive:
+ while 1:
+ s = raw_input(
+ 'Overwrite file with new content? [y/N] ').strip().lower()
+ if not s:
+ s = 'n'
+ if s.startswith('y'):
+ break
+ if s.startswith('n'):
+ return
+ print 'Unknown response; Y or N please'
+ else:
+ return
+
+ if self.verbose:
+ print 'Overwriting %s with new content' % filename
+ if not self.simulate:
+ f = open(filename, 'wb')
+ f.write(content)
+ f.close()
+
+ def shorten(self, fn, *paths):
+ """
+ Return a shorted form of the filename (relative to the current
+ directory), typically for displaying in messages. If
+ ``*paths`` are present, then use os.path.join to create the
+ full filename before shortening.
+ """
+ if paths:
+ fn = os.path.join(fn, *paths)
+ if fn.startswith(os.getcwd()):
+ return fn[len(os.getcwd()):].lstrip(os.path.sep)
+ else:
+ return fn
+
+ _svn_failed = False
+
+ def svn_command(self, *args, **kw):
+ """
+ Run an svn command, but don't raise an exception if it fails.
+ """
+ try:
+ return self.run_command('svn', *args, **kw)
+ except OSError, e:
+ if not self._svn_failed:
+ print 'Unable to run svn command (%s); proceeding anyway' % e
+ self._svn_failed = True
+
+ def run_command(self, cmd, *args, **kw):
+ """
+ Runs the command, respecting verbosity and simulation.
+ Returns stdout, or None if simulating.
+ """
+ cwd = popdefault(kw, 'cwd', os.getcwd())
+ capture_stderr = popdefault(kw, 'capture_stderr', False)
+ expect_returncode = popdefault(kw, 'expect_returncode', False)
+ assert not kw, ("Arguments not expected: %s" % kw)
+ if capture_stderr:
+ stderr_pipe = subprocess.STDOUT
+ else:
+ stderr_pipe = subprocess.PIPE
+ try:
+ proc = subprocess.Popen([cmd] + list(args),
+ cwd=cwd,
+ stderr=stderr_pipe,
+ stdout=subprocess.PIPE)
+ except OSError, e:
+ if e.errno != 2:
+ # File not found
+ raise
+ raise OSError(
+ "The expected executable %s was not found (%s)"
+ % (cmd, e))
+ if self.verbose:
+ print 'Running %s %s' % (cmd, ' '.join(args))
+ if self.simulate:
+ return None
+ stdout, stderr = proc.communicate()
+ if proc.returncode and not expect_returncode:
+ if not self.verbose:
+ print 'Running %s %s' % (cmd, ' '.join(args))
+ print 'Error (exit code: %s)' % proc.returncode
+ if stderr:
+ print stderr
+ raise OSError("Error executing command %s" % cmd)
+ if self.verbose > 2:
+ if stderr:
+ print 'Command error output:'
+ print stderr
+ if stdout:
+ print 'Command output:'
+ print stdout
+ return stdout
+
+def popdefault(dict, name, default=None):
+ if name not in dict:
+ return default
+ else:
+ v = dict[name]
+ del dict[name]
+ return v
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/flup_server.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/flup_server.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/flup_server.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,119 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+from paste.deploy.converters import aslist, asbool
+from paste.script.serve import ensure_port_cleanup
+import warnings
+
+def warn(name, stacklevel=3):
+ # Deprecated 2007-12-17
+ warnings.warn(
+ 'The egg:PasteScript#flup_%s entry point is deprecated; please use egg:Flup#%s instead'
+ % (name, name),
+ DeprecationWarning, stacklevel=stacklevel)
+
+def run_ajp_thread(wsgi_app, global_conf,
+ scriptName='', host='localhost', port='8009',
+ allowedServers='127.0.0.1'):
+ import flup.server.ajp
+ warn('ajp_thread')
+ addr = (host, int(port))
+ ensure_port_cleanup([addr])
+ s = flup.server.ajp.WSGIServer(
+ wsgi_app,
+ scriptName=scriptName,
+ bindAddress=addr,
+ allowedServers=aslist(allowedServers),
+ )
+ s.run()
+
+def run_ajp_fork(wsgi_app, global_conf,
+ scriptName='', host='localhost', port='8009',
+ allowedServers='127.0.0.1'):
+ import flup.server.ajp_fork
+ warn('ajp_fork')
+ addr = (host, int(port))
+ ensure_port_cleanup([addr])
+ s = flup.server.ajp_fork.WSGIServer(
+ wsgi_app,
+ scriptName=scriptName,
+ bindAddress=addr,
+ allowedServers=aslist(allowedServers),
+ )
+ s.run()
+
+def run_fcgi_thread(wsgi_app, global_conf,
+ host=None, port=None,
+ socket=None, umask=None,
+ multiplexed=False):
+ import flup.server.fcgi
+ warn('fcgi_thread')
+ if socket:
+ assert host is None and port is None
+ sock = socket
+ elif host:
+ assert host is not None and port is not None
+ sock = (host, int(port))
+ ensure_port_cleanup([sock])
+ else:
+ sock = None
+ if umask is not None:
+ umask = int(umask)
+ s = flup.server.fcgi.WSGIServer(
+ wsgi_app,
+ bindAddress=sock, umask=umask,
+ multiplexed=asbool(multiplexed))
+ s.run()
+
+def run_fcgi_fork(wsgi_app, global_conf,
+ host=None, port=None,
+ socket=None, umask=None,
+ multiplexed=False):
+ import flup.server.fcgi_fork
+ warn('fcgi_fork')
+ if socket:
+ assert host is None and port is None
+ sock = socket
+ elif host:
+ assert host is not None and port is not None
+ sock = (host, int(port))
+ ensure_port_cleanup([sock])
+ else:
+ sock = None
+ if umask is not None:
+ umask = int(umask)
+ s = flup.server.fcgi_fork.WSGIServer(
+ wsgi_app,
+ bindAddress=sock, umask=umask,
+ multiplexed=asbool(multiplexed))
+ s.run()
+
+def run_scgi_thread(wsgi_app, global_conf,
+ scriptName='', host='localhost', port='4000',
+ allowedServers='127.0.0.1'):
+ import flup.server.scgi
+ warn('scgi_thread')
+ addr = (host, int(port))
+ ensure_port_cleanup([addr])
+ s = flup.server.scgi.WSGIServer(
+ wsgi_app,
+ scriptName=scriptName,
+ bindAddress=addr,
+ allowedServers=aslist(allowedServers),
+ )
+ s.run()
+
+def run_scgi_fork(wsgi_app, global_conf,
+ scriptName='', host='localhost', port='4000',
+ allowedServers='127.0.0.1'):
+ import flup.server.scgi_fork
+ warn('scgi_fork')
+ addr = (host, int(port))
+ ensure_port_cleanup([addr])
+ s = flup.server.scgi_fork.WSGIServer(
+ wsgi_app,
+ scriptName=scriptName,
+ bindAddress=addr,
+ allowedServers=aslist(allowedServers),
+ )
+ s.run()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/grep.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/grep.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/grep.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,168 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import py_compile
+import marshal
+import inspect
+import re
+from command import Command
+import pluginlib
+
+class GrepCommand(Command):
+
+ summary = 'Search project for symbol'
+ usage = 'SYMBOL'
+
+ max_args = 1
+ min_args = 1
+
+ bad_names = ['.svn', 'CVS', '_darcs']
+
+ parser = Command.standard_parser()
+
+ parser.add_option(
+ '-x', '--exclude-module',
+ metavar="module.name",
+ dest="exclude_modules",
+ action="append",
+ help="Don't search the given module")
+
+ parser.add_option(
+ '-t', '--add-type',
+ metavar=".ext",
+ dest="add_types",
+ action="append",
+ help="Search the given type of files")
+
+ def command(self):
+ self.exclude_modules = self.options.exclude_modules or []
+ self.add_types = self.options.add_types or []
+ self.symbol = self.args[0]
+ self.basedir = os.path.dirname(
+ pluginlib.find_egg_info_dir(os.getcwd()))
+ if self.verbose:
+ print "Searching in %s" % self.basedir
+ self.total_files = 0
+ self.search_dir(self.basedir)
+ if self.verbose > 1:
+ print "Searched %i files" % self.total_files
+
+ def search_dir(self, dir):
+ names = os.listdir(dir)
+ names.sort()
+ dirs = []
+ for name in names:
+ full = os.path.join(dir, name)
+ if name in self.bad_names:
+ continue
+ if os.path.isdir(full):
+ # Breadth-first; we'll do this later...
+ dirs.append(full)
+ continue
+ for t in self.add_types:
+ if name.lower().endswith(t.lower()):
+ self.search_text(full)
+ if not name.endswith('.py'):
+ continue
+ self.search_file(full)
+ for dir in dirs:
+ self.search_dir(dir)
+
+ def search_file(self, filename):
+ self.total_files += 1
+ if not filename.endswith('.py'):
+ self.search_text(filename)
+ return
+ pyc = filename[:-2]+'pyc'
+ if not os.path.exists(pyc):
+ py_compile.compile(filename)
+ if not os.path.exists(pyc):
+ # Invalid syntax...
+ self.search_text(filename, as_module=True)
+ return
+ f = open(pyc, 'rb')
+ # .pyc Header:
+ f.read(8)
+ code = marshal.load(f)
+ f.close()
+ self.search_code(code, filename, [])
+
+ def search_code(self, code, filename, path):
+ if code.co_name != "?":
+ path = path + [code.co_name]
+ else:
+ path = path
+ sym = self.symbol
+ if sym in code.co_varnames:
+ self.found(code, filename, path)
+ elif sym in code.co_names:
+ self.found(code, filename, path)
+ for const in code.co_consts:
+ if const == sym:
+ self.found(code, filename, path)
+ if inspect.iscode(const):
+ if not const.co_filename == filename:
+ continue
+ self.search_code(const, filename, path)
+
+ def search_text(self, filename, as_module=False):
+ f = open(filename, 'rb')
+ lineno = 0
+ any = False
+ for line in f:
+ lineno += 1
+ if line.find(self.symbol) != -1:
+ if not any:
+ any = True
+ if as_module:
+ print '%s (unloadable)' % self.module_name(filename)
+ else:
+ print self.relative_name(filename)
+ print ' %3i %s' % (lineno, line)
+ if not self.verbose:
+ break
+ f.close()
+
+ def found(self, code, filename, path):
+ print self.display(filename, path)
+ self.find_occurance(code)
+
+ def find_occurance(self, code):
+ f = open(code.co_filename, 'rb')
+ lineno = 0
+ for index, line in zip(xrange(code.co_firstlineno), f):
+ lineno += 1
+ pass
+ lines = []
+ first_indent = None
+ for line in f:
+ lineno += 1
+ if line.find(self.symbol) != -1:
+ this_indent = len(re.match(r'^[ \t]*', line).group(0))
+ if first_indent is None:
+ first_indent = this_indent
+ else:
+ if this_indent < first_indent:
+ break
+ print ' %3i %s' % (lineno, line[first_indent:].rstrip())
+ if not self.verbose:
+ break
+
+ def module_name(self, filename):
+ assert filename, startswith(self.basedir)
+ mod = filename[len(self.basedir):].strip('/').strip(os.path.sep)
+ mod = os.path.splitext(mod)[0]
+ mod = mod.replace(os.path.sep, '.').replace('/', '.')
+ return mod
+
+ def relative_name(self, filename):
+ assert filename, startswith(self.basedir)
+ name = filename[len(self.basedir):].strip('/').strip(os.path.sep)
+ return name
+
+ def display(self, filename, path):
+ parts = '.'.join(path)
+ if parts:
+ parts = ':' + parts
+ return self.module_name(filename) + parts
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/help.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/help.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/help.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,60 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+from command import Command, get_commands
+from command import parser as base_parser
+
+class HelpCommand(Command):
+
+ summary = "Display help"
+ usage = '[COMMAND]'
+
+ max_args = 1
+
+ parser = Command.standard_parser()
+
+ def command(self):
+ if not self.args:
+ self.generic_help()
+ return
+
+ name = self.args[0]
+ commands = get_commands()
+ if name not in commands:
+ print 'No such command: %s' % name
+ self.generic_help()
+ return
+
+ command = commands[name].load()
+ runner = command(name)
+ runner.run(['-h'])
+
+ def generic_help(self):
+ base_parser.print_help()
+ print
+ commands_grouped = {}
+ commands = get_commands()
+ longest = max([len(n) for n in commands.keys()])
+ for name, command in commands.items():
+ try:
+ command = command.load()
+ except Exception, e:
+ print 'Cannot load command %s: %s' % (name, e)
+ continue
+ if getattr(command, 'hidden', False):
+ continue
+ commands_grouped.setdefault(
+ command.group_name, []).append((name, command))
+ commands_grouped = commands_grouped.items()
+ commands_grouped.sort()
+ print 'Commands:'
+ for group, commands in commands_grouped:
+ if group:
+ print group + ':'
+ commands.sort()
+ for name, command in commands:
+ print ' %s %s' % (self.pad(name, length=longest),
+ command.summary)
+ #if command.description:
+ # print self.indent_block(command.description, 4)
+ print
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/interfaces.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/interfaces.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/interfaces.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,49 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+class IAppInstall(object):
+
+ """
+ The interface for objects in the entry point group
+ ``paste.app_install``
+ """
+
+ def __init__(distribution, entry_group, entry_name):
+ """
+ An object representing a specific application (the
+ distribution is a pkg_resource.Distribution object), for the
+ given entry point name in the given group. Right now the only
+ group used for this is ``'paste.app_factory'``.
+ """
+
+ def description(sys_config):
+ """
+ Return a text description of the application and its
+ configuration. ``sys_config`` is a dictionary representing
+ the system configuration, and can be used for giving more
+ explicit defaults if the application preparation uses the
+ system configuration. It may be None, in which case the
+ description should be more abstract.
+
+ Applications are free to ignore ``sys_config``.
+ """
+
+ def write_config(command, filename, sys_config):
+ """
+ Write a fresh config file to ``filename``. ``command`` is a
+ ``paste.script.command.Command`` object, and should be used
+ for the actual operations. It handles things like simulation
+ and verbosity.
+
+ ``sys_config`` is (if given) a dictionary of system-wide
+ configuration options.
+ """
+
+ def setup_config(command, config_filename,
+ config_section, sys_config):
+ """
+ Set up the application, using ``command`` (to ensure simulate,
+ etc). The application is described by the configuration file
+ ``config_filename``. ``sys_config`` is the system
+ configuration (though probably the values from it should have
+ already been encorporated into the configuration file).
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/+package+/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/+package+/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/+package+/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.cfg
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.cfg (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.cfg 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/paster-templates/basic_package/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,26 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = {{repr(version or "0.0")}}
+
+setup(name={{repr(project)}},
+ version=version,
+ description="{{description or ''}}",
+ long_description="""\
+{{long_description or ''}}""",
+ classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ keywords={{repr(keywords or '')}},
+ author={{repr(author or '')}},
+ author_email={{repr(author_email or '')}},
+ url={{repr(url or '')}},
+ license={{repr(license_name or '')}},
+ packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+ include_package_data=True,
+ zip_safe={{repr(bool(zip_safe or False))}},
+ install_requires=[
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/pluginlib.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/pluginlib.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/pluginlib.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,134 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import pkg_resources
+
+def add_plugin(egg_info_dir, plugin_name):
+ """
+ Add the plugin to the given distribution (or spec), in
+ .egg-info/paster_plugins.txt
+ """
+ fn = os.path.join(egg_info_dir, 'paster_plugins.txt')
+ if not os.path.exists(fn):
+ lines = []
+ else:
+ f = open(fn)
+ lines = [l.strip() for l in f.readlines() if l.strip()]
+ f.close()
+ if plugin_name in lines:
+ # Nothing to do
+ return
+ lines.append(plugin_name)
+ if not os.path.exists(os.path.dirname(fn)):
+ os.makedirs(os.path.dirname(fn))
+ f = open(fn, 'w')
+ for line in lines:
+ f.write(line)
+ f.write('\n')
+ f.close()
+
+def remove_plugin(egg_info_dir, plugin_name):
+ """
+ Remove the plugin to the given distribution (or spec), in
+ .egg-info/paster_plugins.txt. Raises ValueError if the
+ plugin is not in the file.
+ """
+ fn = os.path.join(egg_info_dir, 'paster_plugins.txt')
+ if not os.path.exists(fn):
+ raise ValueError(
+ "Cannot remove plugin from %s; file does not exist"
+ % fn)
+ f = open(fn)
+ lines = [l.strip() for l in f.readlines() if l.strip()]
+ f.close()
+ for line in lines:
+ # What about version specs?
+ if line.lower() == plugin_name.lower():
+ break
+ else:
+ raise ValueError(
+ "Plugin %s not found in file %s (from: %s)"
+ % (plugin_name, fn, lines))
+ lines.remove(line)
+ print 'writing', lines
+ f = open(fn, 'w')
+ for line in lines:
+ f.write(line)
+ f.write('\n')
+ f.close()
+
+def find_egg_info_dir(dir):
+ while 1:
+ try:
+ filenames = os.listdir(dir)
+ except OSError:
+ # Probably permission denied or something
+ return None
+ for fn in filenames:
+ if fn.endswith('.egg-info'):
+ return os.path.join(dir, fn)
+ parent = os.path.dirname(dir)
+ if parent == dir:
+ # Top-most directory
+ return None
+ dir = parent
+
+def resolve_plugins(plugin_list):
+ found = []
+ while plugin_list:
+ plugin = plugin_list.pop()
+ try:
+ pkg_resources.require(plugin)
+ except pkg_resources.DistributionNotFound, e:
+ msg = '%sNot Found%s: %s (did you run python setup.py develop?)'
+ if str(e) != plugin:
+ e.args = (msg % (str(e) + ': ', ' for', plugin)),
+ else:
+ e.args = (msg % ('', '', plugin)),
+ raise
+ found.append(plugin)
+ dist = get_distro(plugin)
+ if dist.has_metadata('paster_plugins.txt'):
+ data = dist.get_metadata('paster_plugins.txt')
+ for add_plugin in parse_lines(data):
+ if add_plugin not in found:
+ plugin_list.append(add_plugin)
+ return map(get_distro, found)
+
+def get_distro(spec):
+ return pkg_resources.get_distribution(spec)
+
+def load_commands_from_plugins(plugins):
+ commands = {}
+ for plugin in plugins:
+ commands.update(pkg_resources.get_entry_map(
+ plugin, group='paste.paster_command'))
+ return commands
+
+def parse_lines(data):
+ result = []
+ for line in data.splitlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ result.append(line)
+ return result
+
+def load_global_commands():
+ commands = {}
+ for p in pkg_resources.iter_entry_points('paste.global_paster_command'):
+ commands[p.name] = p
+ return commands
+
+def egg_name(dist_name):
+ return pkg_resources.to_filename(pkg_resources.safe_name(dist_name))
+
+def egg_info_dir(base_dir, dist_name):
+ all = []
+ for dir_extension in ['.'] + os.listdir(base_dir):
+ full = os.path.join(base_dir, dir_extension,
+ egg_name(dist_name)+'.egg-info')
+ all.append(full)
+ if os.path.exists(full):
+ return full
+ raise IOError("No egg-info directory found (looked in %s)"
+ % ', '.join(all))
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/request.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/request.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/request.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,189 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import os
+import re
+import sys
+import urlparse
+import urllib
+from command import Command, BadCommand
+from paste.deploy import loadapp, loadserver
+from paste.wsgilib import raw_interactive
+
+class RequestCommand(Command):
+
+ min_args = 2
+ usage = 'CONFIG_FILE URL [OPTIONS/ARGUMENTS]'
+ takes_config_file = 1
+ summary = "Run a request for the described application"
+ description = """\
+ This command makes an artifical request to a web application that
+ uses a paste.deploy configuration file for the server and
+ application.
+
+ Use 'paster request config.ini /url' to request /url. Use
+ 'paster post config.ini /url < data' to do a POST with the given
+ request body.
+
+ If the URL is relative (doesn't begin with /) it is interpreted as
+ relative to /.command/. The variable environ['paste.command_request']
+ will be set to True in the request, so your application can distinguish
+ these calls from normal requests.
+
+ Note that you can pass options besides the options listed here; any unknown
+ options will be passed to the application in environ['QUERY_STRING'].
+ """
+
+ parser = Command.standard_parser(quiet=True)
+ parser.add_option('-n', '--app-name',
+ dest='app_name',
+ metavar='NAME',
+ help="Load the named application (default main)")
+ parser.add_option('--config-var',
+ dest='config_vars',
+ metavar='NAME:VALUE',
+ action='append',
+ help="Variable to make available in the config for %()s substitution "
+ "(you can use this option multiple times)")
+ parser.add_option('--header',
+ dest='headers',
+ metavar='NAME:VALUE',
+ action='append',
+ help="Header to add to request (you can use this option multiple times)")
+ parser.add_option('--display-headers',
+ dest='display_headers',
+ action='store_true',
+ help='Display headers before the response body')
+
+ ARG_OPTIONS = ['-n', '--app-name', '--config-var', '--header']
+ OTHER_OPTIONS = ['--display-headers']
+
+ ## FIXME: some kind of verbosity?
+ ## FIXME: allow other methods than POST and GET?
+
+ _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I)
+
+ def command(self):
+ vars = {}
+ app_spec = self.args[0]
+ url = self.args[1]
+ url = urlparse.urljoin('/.command/', url)
+ if self.options.config_vars:
+ for item in self.option.config_vars:
+ if ':' not in item:
+ raise BadCommand(
+ "Bad option, should be name:value : --config-var=%s" % item)
+ name, value = item.split(':', 1)
+ vars[name] = value
+ headers = {}
+ if self.options.headers:
+ for item in self.options.headers:
+ if ':' not in item:
+ raise BadCommand(
+ "Bad option, should be name:value : --header=%s" % item)
+ name, value = item.split(':', 1)
+ headers[name] = value.strip()
+ if not self._scheme_re.search(app_spec):
+ app_spec = 'config:'+app_spec
+ if self.options.app_name:
+ if '#' in app_spec:
+ app_spec = app_spec.split('#', 1)[0]
+ app_spec = app_spec + '#' + options.app_name
+ app = loadapp(app_spec, relative_to=os.getcwd(), global_conf=vars)
+ if self.command_name.lower() == 'post':
+ request_method = 'POST'
+ else:
+ request_method = 'GET'
+ qs = []
+ for item in self.args[2:]:
+ if '=' in item:
+ item = urllib.quote(item.split('=', 1)[0]) + '=' + urllib.quote(item.split('=', 1)[1])
+ else:
+ item = urllib.quote(item)
+ qs.append(item)
+ qs = '&'.join(qs)
+
+ environ = {
+ 'REQUEST_METHOD': request_method,
+ ## FIXME: shouldn't be static (an option?):
+ 'CONTENT_TYPE': 'text/plain',
+ 'wsgi.run_once': True,
+ 'wsgi.multithread': False,
+ 'wsgi.multiprocess': False,
+ 'wsgi.errors': sys.stderr,
+ 'QUERY_STRING': qs,
+ 'HTTP_ACCEPT': 'text/plain;q=1.0, */*;q=0.1',
+ 'paste.command_request': True,
+ }
+ if request_method == 'POST':
+ environ['wsgi.input'] = sys.stdin
+ environ['CONTENT_LENGTH'] = '-1'
+ for name, value in headers.items():
+ if name.lower() == 'content-type':
+ name = 'CONTENT_TYPE'
+ else:
+ name = 'HTTP_'+name.upper().replace('-', '_')
+ environ[name] = value
+
+ status, headers, output, errors = raw_interactive(app, url, **environ)
+ assert not errors, "errors should be printed directly to sys.stderr"
+ if self.options.display_headers:
+ for name, value in headers:
+ sys.stdout.write('%s: %s\n' % (name, value))
+ sys.stdout.write('\n')
+ sys.stdout.write(output)
+ sys.stdout.flush()
+ status_int = int(status.split()[0])
+ if status_int != 200:
+ return status_int
+
+ def parse_args(self, args):
+ if args == ['-h']:
+ Command.parse_args(self, args)
+ return
+ # These are the arguments parsed normally:
+ normal_args = []
+ # And these are arguments passed to the URL:
+ extra_args = []
+ # This keeps track of whether we have the two required positional arguments:
+ pos_args = 0
+ while args:
+ start = args[0]
+ if not start.startswith('-'):
+ if pos_args < 2:
+ pos_args += 1
+ normal_args.append(start)
+ args.pop(0)
+ continue
+ else:
+ normal_args.append(start)
+ args.pop(0)
+ continue
+ else:
+ found = False
+ for option in self.ARG_OPTIONS:
+ if start == option:
+ normal_args.append(start)
+ args.pop(0)
+ if not args:
+ raise BadCommand(
+ "Option %s takes an argument" % option)
+ normal_args.append(args.pop(0))
+ found = True
+ break
+ elif start.startswith(option+'='):
+ normal_args.append(start)
+ args.pop(0)
+ found = True
+ break
+ if found:
+ continue
+ if start in self.OTHER_OPTIONS:
+ normal_args.append(start)
+ args.pop(0)
+ continue
+ extra_args.append(start)
+ args.pop(0)
+ Command.parse_args(self, normal_args)
+ # Add the extra arguments back in:
+ self.args = self.args + extra_args
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/serve.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/serve.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/serve.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,643 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# @@: This should be moved to paste.deploy
+# For discussion of daemonizing:
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
+# Code taken also from QP:
+# http://www.mems-exchange.org/software/qp/
+# From lib/site.py
+import re
+import os
+import errno
+import sys
+import time
+try:
+ import subprocess
+except ImportError:
+ from paste.util import subprocess24 as subprocess
+from command import Command, BadCommand
+from paste.deploy import loadapp, loadserver
+import threading
+import atexit
+import logging
+import ConfigParser
+
+MAXFD = 1024
+
+jython = sys.platform.startswith('java')
+
+class DaemonizeException(Exception):
+ pass
+
+
+class ServeCommand(Command):
+
+ min_args = 0
+ usage = 'CONFIG_FILE [start|stop|restart|status] [var=value]'
+ takes_config_file = 1
+ summary = "Serve the described application"
+ description = """\
+ This command serves a web application that uses a paste.deploy
+ configuration file for the server and application.
+
+ If start/stop/restart is given, then --daemon is implied, and it will
+ start (normal operation), stop (--stop-daemon), or do both.
+
+ You can also include variable assignments like 'http_port=8080'
+ and then use %(http_port)s in your config files.
+ """
+
+ # used by subclasses that configure apps and servers differently
+ requires_config_file = True
+
+ parser = Command.standard_parser(quiet=True)
+ parser.add_option('-n', '--app-name',
+ dest='app_name',
+ metavar='NAME',
+ help="Load the named application (default main)")
+ parser.add_option('-s', '--server',
+ dest='server',
+ metavar='SERVER_TYPE',
+ help="Use the named server.")
+ parser.add_option('--server-name',
+ dest='server_name',
+ metavar='SECTION_NAME',
+ help="Use the named server as defined in the configuration file (default: main)")
+ if hasattr(os, 'fork'):
+ parser.add_option('--daemon',
+ dest="daemon",
+ action="store_true",
+ help="Run in daemon (background) mode")
+ parser.add_option('--pid-file',
+ dest='pid_file',
+ metavar='FILENAME',
+ help="Save PID to file (default to paster.pid if running in daemon mode)")
+ parser.add_option('--log-file',
+ dest='log_file',
+ metavar='LOG_FILE',
+ help="Save output to the given log file (redirects stdout)")
+ parser.add_option('--reload',
+ dest='reload',
+ action='store_true',
+ help="Use auto-restart file monitor")
+ parser.add_option('--reload-interval',
+ dest='reload_interval',
+ default=1,
+ help="Seconds between checking files (low number can cause significant CPU usage)")
+ parser.add_option('--monitor-restart',
+ dest='monitor_restart',
+ action='store_true',
+ help="Auto-restart server if it dies")
+ parser.add_option('--status',
+ action='store_true',
+ dest='show_status',
+ help="Show the status of the (presumably daemonized) server")
+
+
+ if hasattr(os, 'setuid'):
+ # I don't think these are available on Windows
+ parser.add_option('--user',
+ dest='set_user',
+ metavar="USERNAME",
+ help="Set the user (usually only possible when run as root)")
+ parser.add_option('--group',
+ dest='set_group',
+ metavar="GROUP",
+ help="Set the group (usually only possible when run as root)")
+
+ parser.add_option('--stop-daemon',
+ dest='stop_daemon',
+ action='store_true',
+ help='Stop a daemonized server (given a PID file, or default paster.pid file)')
+
+ if jython:
+ parser.add_option('--disable-jython-reloader',
+ action='store_true',
+ dest='disable_jython_reloader',
+ help="Disable the Jython reloader")
+
+
+ _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I)
+
+ default_verbosity = 1
+
+ _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN'
+ _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN'
+
+ possible_subcommands = ('start', 'stop', 'restart', 'status')
+ def command(self):
+ if self.options.stop_daemon:
+ return self.stop_daemon()
+
+ if not hasattr(self.options, 'set_user'):
+ # Windows case:
+ self.options.set_user = self.options.set_group = None
+ # @@: Is this the right stage to set the user at?
+ self.change_user_group(
+ self.options.set_user, self.options.set_group)
+
+ if self.requires_config_file:
+ if not self.args:
+ raise BadCommand('You must give a config file')
+ app_spec = self.args[0]
+ if (len(self.args) > 1
+ and self.args[1] in self.possible_subcommands):
+ cmd = self.args[1]
+ restvars = self.args[2:]
+ else:
+ cmd = None
+ restvars = self.args[1:]
+ else:
+ app_spec = ""
+ if (self.args
+ and self.args[0] in self.possible_subcommands):
+ cmd = self.args[0]
+ restvars = self.args[1:]
+ else:
+ cmd = None
+ restvars = self.args[:]
+
+ jython_monitor = False
+ if self.options.reload:
+ if jython and not self.options.disable_jython_reloader:
+ # JythonMonitor raises the special SystemRestart
+ # exception that'll cause the Jython interpreter to
+ # reload in the existing Java process (avoiding
+ # subprocess startup time)
+ try:
+ from paste.reloader import JythonMonitor
+ except ImportError:
+ pass
+ else:
+ jython_monitor = JythonMonitor(poll_interval=int(
+ self.options.reload_interval))
+ if self.requires_config_file:
+ jython_monitor.watch_file(self.args[0])
+
+ if not jython_monitor:
+ if os.environ.get(self._reloader_environ_key):
+ from paste import reloader
+ if self.verbose > 1:
+ print 'Running reloading file monitor'
+ reloader.install(int(self.options.reload_interval))
+ if self.requires_config_file:
+ reloader.watch_file(self.args[0])
+ else:
+ return self.restart_with_reloader()
+
+ if cmd not in (None, 'start', 'stop', 'restart', 'status'):
+ raise BadCommand(
+ 'Error: must give start|stop|restart (not %s)' % cmd)
+
+ if cmd == 'status' or self.options.show_status:
+ return self.show_status()
+
+ if cmd == 'restart' or cmd == 'stop':
+ result = self.stop_daemon()
+ if result:
+ if cmd == 'restart':
+ print "Could not stop daemon; aborting"
+ else:
+ print "Could not stop daemon"
+ return result
+ if cmd == 'stop':
+ return result
+
+ app_name = self.options.app_name
+ vars = self.parse_vars(restvars)
+ if not self._scheme_re.search(app_spec):
+ app_spec = 'config:' + app_spec
+ server_name = self.options.server_name
+ if self.options.server:
+ server_spec = 'egg:PasteScript'
+ assert server_name is None
+ server_name = self.options.server
+ else:
+ server_spec = app_spec
+ base = os.getcwd()
+
+ if getattr(self.options, 'daemon', False):
+ if not self.options.pid_file:
+ self.options.pid_file = 'paster.pid'
+ if not self.options.log_file:
+ self.options.log_file = 'paster.log'
+
+ # Ensure the log file is writeable
+ if self.options.log_file:
+ try:
+ writeable_log_file = open(self.options.log_file, 'a')
+ except IOError, ioe:
+ msg = 'Error: Unable to write to log file: %s' % ioe
+ raise BadCommand(msg)
+ writeable_log_file.close()
+
+ # Ensure the pid file is writeable
+ if self.options.pid_file:
+ try:
+ writeable_pid_file = open(self.options.pid_file, 'a')
+ except IOError, ioe:
+ msg = 'Error: Unable to write to pid file: %s' % ioe
+ raise BadCommand(msg)
+ writeable_pid_file.close()
+
+ if getattr(self.options, 'daemon', False):
+ try:
+ self.daemonize()
+ except DaemonizeException, ex:
+ if self.verbose > 0:
+ print str(ex)
+ return
+
+ if (self.options.monitor_restart
+ and not os.environ.get(self._monitor_environ_key)):
+ return self.restart_with_monitor()
+
+ if self.options.pid_file:
+ self.record_pid(self.options.pid_file)
+
+ if self.options.log_file:
+ stdout_log = LazyWriter(self.options.log_file, 'a')
+ sys.stdout = stdout_log
+ sys.stderr = stdout_log
+ logging.basicConfig(stream=stdout_log)
+
+ log_fn = app_spec
+ if log_fn.startswith('config:'):
+ log_fn = app_spec[len('config:'):]
+ elif log_fn.startswith('egg:'):
+ log_fn = None
+ if log_fn:
+ log_fn = os.path.join(base, log_fn)
+ self.logging_file_config(log_fn)
+
+ server = self.loadserver(server_spec, name=server_name,
+ relative_to=base, global_conf=vars)
+ app = self.loadapp(app_spec, name=app_name,
+ relative_to=base, global_conf=vars)
+
+ if self.verbose > 0:
+ if hasattr(os, 'getpid'):
+ msg = 'Starting server in PID %i.' % os.getpid()
+ else:
+ msg = 'Starting server.'
+ print msg
+
+ def serve():
+ try:
+ server(app)
+ except (SystemExit, KeyboardInterrupt), e:
+ if self.verbose > 1:
+ raise
+ if str(e):
+ msg = ' '+str(e)
+ else:
+ msg = ''
+ print 'Exiting%s (-v to see traceback)' % msg
+
+ if jython_monitor:
+ # JythonMonitor has to be ran from the main thread
+ threading.Thread(target=serve).start()
+ print 'Starting Jython file monitor'
+ jython_monitor.periodic_reload()
+ else:
+ serve()
+
+ def loadserver(self, server_spec, name, relative_to, **kw):
+ return loadserver(
+ server_spec, name=name,
+ relative_to=relative_to, **kw)
+
+ def loadapp(self, app_spec, name, relative_to, **kw):
+ return loadapp(
+ app_spec, name=name, relative_to=relative_to,
+ **kw)
+
+ def daemonize(self):
+ pid = live_pidfile(self.options.pid_file)
+ if pid:
+ raise DaemonizeException(
+ "Daemon is already running (PID: %s from PID file %s)"
+ % (pid, self.options.pid_file))
+
+ if self.verbose > 0:
+ print 'Entering daemon mode'
+ pid = os.fork()
+ if pid:
+ # The forked process also has a handle on resources, so we
+ # *don't* want proper termination of the process, we just
+ # want to exit quick (which os._exit() does)
+ os._exit(0)
+ # Make this the session leader
+ os.setsid()
+ # Fork again for good measure!
+ pid = os.fork()
+ if pid:
+ os._exit(0)
+
+ # @@: Should we set the umask and cwd now?
+
+ import resource # Resource usage information.
+ maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
+ if (maxfd == resource.RLIM_INFINITY):
+ maxfd = MAXFD
+ # Iterate through and close all file descriptors.
+ for fd in range(0, maxfd):
+ try:
+ os.close(fd)
+ except OSError: # ERROR, fd wasn't open to begin with (ignored)
+ pass
+
+ if (hasattr(os, "devnull")):
+ REDIRECT_TO = os.devnull
+ else:
+ REDIRECT_TO = "/dev/null"
+ os.open(REDIRECT_TO, os.O_RDWR) # standard input (0)
+ # Duplicate standard input to standard output and standard error.
+ os.dup2(0, 1) # standard output (1)
+ os.dup2(0, 2) # standard error (2)
+
+ def record_pid(self, pid_file):
+ pid = os.getpid()
+ if self.verbose > 1:
+ print 'Writing PID %s to %s' % (pid, pid_file)
+ f = open(pid_file, 'w')
+ f.write(str(pid))
+ f.close()
+ atexit.register(_remove_pid_file, pid, pid_file, self.verbose)
+
+ def stop_daemon(self):
+ pid_file = self.options.pid_file or 'paster.pid'
+ if not os.path.exists(pid_file):
+ print 'No PID file exists in %s' % pid_file
+ return 1
+ pid = read_pidfile(pid_file)
+ if not pid:
+ print "Not a valid PID file in %s" % pid_file
+ return 1
+ pid = live_pidfile(pid_file)
+ if not pid:
+ print "PID in %s is not valid (deleting)" % pid_file
+ try:
+ os.unlink(pid_file)
+ except (OSError, IOError), e:
+ print "Could not delete: %s" % e
+ return 2
+ return 1
+ for j in range(10):
+ if not live_pidfile(pid_file):
+ break
+ import signal
+ os.kill(pid, signal.SIGTERM)
+ time.sleep(1)
+ else:
+ print "failed to kill web process %s" % pid
+ return 3
+ if os.path.exists(pid_file):
+ os.unlink(pid_file)
+ return 0
+
+ def show_status(self):
+ pid_file = self.options.pid_file or 'paster.pid'
+ if not os.path.exists(pid_file):
+ print 'No PID file %s' % pid_file
+ return 1
+ pid = read_pidfile(pid_file)
+ if not pid:
+ print 'No PID in file %s' % pid_file
+ return 1
+ pid = live_pidfile(pid_file)
+ if not pid:
+ print 'PID %s in %s is not running' % (pid, pid_file)
+ return 1
+ print 'Server running in PID %s' % pid
+ return 0
+
+ def restart_with_reloader(self):
+ self.restart_with_monitor(reloader=True)
+
+ def restart_with_monitor(self, reloader=False):
+ if self.verbose > 0:
+ if reloader:
+ print 'Starting subprocess with file monitor'
+ else:
+ print 'Starting subprocess with monitor parent'
+ while 1:
+ args = [self.quote_first_command_arg(sys.executable)] + sys.argv
+ new_environ = os.environ.copy()
+ if reloader:
+ new_environ[self._reloader_environ_key] = 'true'
+ else:
+ new_environ[self._monitor_environ_key] = 'true'
+ proc = None
+ try:
+ try:
+ _turn_sigterm_into_systemexit()
+ proc = subprocess.Popen(args, env=new_environ)
+ exit_code = proc.wait()
+ proc = None
+ except KeyboardInterrupt:
+ print '^C caught in monitor process'
+ if self.verbose > 1:
+ raise
+ return 1
+ finally:
+ if (proc is not None
+ and hasattr(os, 'kill')):
+ import signal
+ try:
+ os.kill(proc.pid, signal.SIGTERM)
+ except (OSError, IOError):
+ pass
+
+ if reloader:
+ # Reloader always exits with code 3; but if we are
+ # a monitor, any exit code will restart
+ if exit_code != 3:
+ return exit_code
+ if self.verbose > 0:
+ print '-'*20, 'Restarting', '-'*20
+
+ def change_user_group(self, user, group):
+ if not user and not group:
+ return
+ import pwd, grp
+ uid = gid = None
+ if group:
+ try:
+ gid = int(group)
+ group = grp.getgrgid(gid).gr_name
+ except ValueError:
+ import grp
+ try:
+ entry = grp.getgrnam(group)
+ except KeyError:
+ raise BadCommand(
+ "Bad group: %r; no such group exists" % group)
+ gid = entry.gr_gid
+ try:
+ uid = int(user)
+ user = pwd.getpwuid(uid).pw_name
+ except ValueError:
+ try:
+ entry = pwd.getpwnam(user)
+ except KeyError:
+ raise BadCommand(
+ "Bad username: %r; no such user exists" % user)
+ if not gid:
+ gid = entry.pw_gid
+ uid = entry.pw_uid
+ if self.verbose > 0:
+ print 'Changing user to %s:%s (%s:%s)' % (
+ user, group or '(unknown)', uid, gid)
+ if gid:
+ os.setgid(gid)
+ if uid:
+ os.setuid(uid)
+
+class LazyWriter(object):
+
+ """
+ File-like object that opens a file lazily when it is first written
+ to.
+ """
+
+ def __init__(self, filename, mode='w'):
+ self.filename = filename
+ self.fileobj = None
+ self.lock = threading.Lock()
+ self.mode = mode
+
+ def open(self):
+ if self.fileobj is None:
+ self.lock.acquire()
+ try:
+ if self.fileobj is None:
+ self.fileobj = open(self.filename, self.mode)
+ finally:
+ self.lock.release()
+ return self.fileobj
+
+ def write(self, text):
+ fileobj = self.open()
+ fileobj.write(text)
+ fileobj.flush()
+
+ def writelines(self, text):
+ fileobj = self.open()
+ fileobj.writelines(text)
+ fileobj.flush()
+
+ def flush(self):
+ self.open().flush()
+
+def live_pidfile(pidfile):
+ """(pidfile:str) -> int | None
+ Returns an int found in the named file, if there is one,
+ and if there is a running process with that process id.
+ Return None if no such process exists.
+ """
+ pid = read_pidfile(pidfile)
+ if pid:
+ try:
+ os.kill(int(pid), 0)
+ return pid
+ except OSError, e:
+ if e.errno == errno.EPERM:
+ return pid
+ return None
+
+def read_pidfile(filename):
+ if os.path.exists(filename):
+ try:
+ f = open(filename)
+ content = f.read()
+ f.close()
+ return int(content.strip())
+ except (ValueError, IOError):
+ return None
+ else:
+ return None
+
+def _remove_pid_file(written_pid, filename, verbosity):
+ current_pid = os.getpid()
+ if written_pid != current_pid:
+ # A forked process must be exiting, not the process that
+ # wrote the PID file
+ return
+ if not os.path.exists(filename):
+ return
+ f = open(filename)
+ content = f.read().strip()
+ f.close()
+ try:
+ pid_in_file = int(content)
+ except ValueError:
+ pass
+ else:
+ if pid_in_file != current_pid:
+ print "PID file %s contains %s, not expected PID %s" % (
+ filename, pid_in_file, current_pid)
+ return
+ if verbosity > 0:
+ print "Removing PID file %s" % filename
+ try:
+ os.unlink(filename)
+ return
+ except OSError, e:
+ # Record, but don't give traceback
+ print "Cannot remove PID file: %s" % e
+ # well, at least lets not leave the invalid PID around...
+ try:
+ f = open(filename, 'w')
+ f.write('')
+ f.close()
+ except OSError, e:
+ print 'Stale PID left in file: %s (%e)' % (filename, e)
+ else:
+ print 'Stale PID removed'
+
+
+def ensure_port_cleanup(bound_addresses, maxtries=30, sleeptime=2):
+ """
+ This makes sure any open ports are closed.
+
+ Does this by connecting to them until they give connection
+ refused. Servers should call like::
+
+ import paste.script
+ ensure_port_cleanup([80, 443])
+ """
+ atexit.register(_cleanup_ports, bound_addresses, maxtries=maxtries,
+ sleeptime=sleeptime)
+
+def _cleanup_ports(bound_addresses, maxtries=30, sleeptime=2):
+ # Wait for the server to bind to the port.
+ import socket
+ import errno
+ for bound_address in bound_addresses:
+ for attempt in range(maxtries):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ sock.connect(bound_address)
+ except socket.error, e:
+ if e.args[0] != errno.ECONNREFUSED:
+ raise
+ break
+ else:
+ time.sleep(sleeptime)
+ else:
+ raise SystemExit('Timeout waiting for port.')
+ sock.close()
+
+def _turn_sigterm_into_systemexit():
+ """
+ Attempts to turn a SIGTERM exception into a SystemExit exception.
+ """
+ try:
+ import signal
+ except ImportError:
+ return
+ def handle_term(signo, frame):
+ raise SystemExit
+ signal.signal(signal.SIGTERM, handle_term)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/templates.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/templates.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/templates.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,278 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import sys
+import os
+import inspect
+import copydir
+import command
+
+from paste.util.template import paste_script_template_renderer
+
+class Template(object):
+
+ # Subclasses must define:
+ # _template_dir (or template_dir())
+ # summary
+
+ # Variables this template uses (mostly for documentation now)
+ # a list of instances of var()
+ vars = []
+
+ # Eggs that should be added as plugins:
+ egg_plugins = []
+
+ # Templates that must be applied first:
+ required_templates = []
+
+ # Use Cheetah for substituting templates:
+ use_cheetah = False
+ # If true, then read all the templates to find the variables:
+ read_vars_from_templates = False
+
+ # You can also give this function/method to use something other
+ # than Cheetah or string.Template. The function should be of the
+ # signature template_renderer(content, vars, filename=filename).
+ # Careful you don't turn this into a method by putting a function
+ # here (without staticmethod)!
+ template_renderer = None
+
+ def __init__(self, name):
+ self.name = name
+ self._read_vars = None
+
+ def module_dir(self):
+ """Returns the module directory of this template."""
+ mod = sys.modules[self.__class__.__module__]
+ return os.path.dirname(mod.__file__)
+
+ def template_dir(self):
+ assert self._template_dir is not None, (
+ "Template %r didn't set _template_dir" % self)
+ if isinstance( self._template_dir, tuple):
+ return self._template_dir
+ else:
+ return os.path.join(self.module_dir(), self._template_dir)
+
+ def run(self, command, output_dir, vars):
+ self.pre(command, output_dir, vars)
+ self.write_files(command, output_dir, vars)
+ self.post(command, output_dir, vars)
+
+ def check_vars(self, vars, cmd):
+ expect_vars = self.read_vars(cmd)
+ if not expect_vars:
+ # Assume that variables aren't defined
+ return vars
+ converted_vars = {}
+ unused_vars = vars.copy()
+ errors = []
+ for var in expect_vars:
+ if var.name not in unused_vars:
+ if cmd.interactive:
+ prompt = 'Enter %s' % var.full_description()
+ response = cmd.challenge(prompt, var.default, var.should_echo)
+ converted_vars[var.name] = response
+ elif var.default is command.NoDefault:
+ errors.append('Required variable missing: %s'
+ % var.full_description())
+ else:
+ converted_vars[var.name] = var.default
+ else:
+ converted_vars[var.name] = unused_vars.pop(var.name)
+ if errors:
+ raise command.BadCommand(
+ 'Errors in variables:\n%s' % '\n'.join(errors))
+ converted_vars.update(unused_vars)
+ vars.update(converted_vars)
+ return converted_vars
+
+ def read_vars(self, command=None):
+ if self._read_vars is not None:
+ return self._read_vars
+ assert (not self.read_vars_from_templates
+ or self.use_cheetah), (
+ "You can only read variables from templates if using Cheetah")
+ if not self.read_vars_from_templates:
+ self._read_vars = self.vars
+ return self.vars
+
+ vars = self.vars[:]
+ var_names = [var.name for var in self.vars]
+ read_vars = find_args_in_dir(
+ self.template_dir(),
+ verbose=command and command.verbose > 1).items()
+ read_vars.sort()
+ for var_name, var in read_vars:
+ if var_name not in var_names:
+ vars.append(var)
+ self._read_vars = vars
+ return vars
+
+ def write_files(self, command, output_dir, vars):
+ template_dir = self.template_dir()
+ if not os.path.exists(output_dir):
+ print "Creating directory %s" % output_dir
+ if not command.simulate:
+ # Don't let copydir create this top-level directory,
+ # since copydir will svn add it sometimes:
+ os.makedirs(output_dir)
+ copydir.copy_dir(template_dir, output_dir,
+ vars,
+ verbosity=command.verbose,
+ simulate=command.options.simulate,
+ interactive=command.interactive,
+ overwrite=command.options.overwrite,
+ indent=1,
+ use_cheetah=self.use_cheetah,
+ template_renderer=self.template_renderer)
+
+ def print_vars(self, indent=0):
+ vars = self.read_vars()
+ var.print_vars(vars)
+
+ def pre(self, command, output_dir, vars):
+ """
+ Called before template is applied.
+ """
+ pass
+
+ def post(self, command, output_dir, vars):
+ """
+ Called after template is applied.
+ """
+ pass
+
+NoDefault = command.NoDefault
+
+class var(object):
+
+ def __init__(self, name, description,
+ default='', should_echo=True):
+ self.name = name
+ self.description = description
+ self.default = default
+ self.should_echo = should_echo
+
+ def __repr__(self):
+ return '<%s %s default=%r should_echo=%s>' % (
+ self.__class__.__name__,
+ self.name, self.default, self.should_echo)
+
+ def full_description(self):
+ if self.description:
+ return '%s (%s)' % (self.name, self.description)
+ else:
+ return self.name
+
+ def print_vars(cls, vars, indent=0):
+ max_name = max([len(v.name) for v in vars])
+ for var in vars:
+ if var.description:
+ print '%s%s%s %s' % (
+ ' '*indent,
+ var.name,
+ ' '*(max_name-len(var.name)),
+ var.description)
+ else:
+ print ' %s' % var.name
+ if var.default is not command.NoDefault:
+ print ' default: %r' % var.default
+ if var.should_echo is True:
+ print ' should_echo: %s' % var.should_echo
+ print
+
+ print_vars = classmethod(print_vars)
+
+class BasicPackage(Template):
+
+ _template_dir = 'paster-templates/basic_package'
+ summary = "A basic setuptools-enabled package"
+ vars = [
+ var('version', 'Version (like 0.1)'),
+ var('description', 'One-line description of the package'),
+ var('long_description', 'Multi-line description (in reST)'),
+ var('keywords', 'Space-separated keywords/tags'),
+ var('author', 'Author name'),
+ var('author_email', 'Author email'),
+ var('url', 'URL of homepage'),
+ var('license_name', 'License name'),
+ var('zip_safe', 'True/False: if the package can be distributed as a .zip file', default=False),
+ ]
+
+ template_renderer = staticmethod(paste_script_template_renderer)
+
+_skip_variables = ['VFN', 'currentTime', 'self', 'VFFSL', 'dummyTrans',
+ 'getmtime', 'trans']
+
+def find_args_in_template(template):
+ if isinstance(template, (str, unicode)):
+ # Treat as filename:
+ import Cheetah.Template
+ template = Cheetah.Template.Template(file=template)
+ if not hasattr(template, 'body'):
+ # Don't know...
+ return None
+ method = template.body
+ args, varargs, varkw, defaults = inspect.getargspec(method)
+ defaults=list(defaults or [])
+ vars = []
+ while args:
+ if len(args) == len(defaults):
+ default = defaults.pop(0)
+ else:
+ default = command.NoDefault
+ arg = args.pop(0)
+ if arg in _skip_variables:
+ continue
+ # @@: No way to get description yet
+ vars.append(
+ var(arg, description=None,
+ default=default))
+ return vars
+
+def find_args_in_dir(dir, verbose=False):
+ all_vars = {}
+ for fn in os.listdir(dir):
+ if fn.startswith('.') or fn == 'CVS' or fn == '_darcs':
+ continue
+ full = os.path.join(dir, fn)
+ if os.path.isdir(full):
+ inner_vars = find_args_in_dir(full)
+ elif full.endswith('_tmpl'):
+ inner_vars = {}
+ found = find_args_in_template(full)
+ if found is None:
+ # Couldn't read variables
+ if verbose:
+ print 'Template %s has no parseable variables' % full
+ continue
+ for var in found:
+ inner_vars[var.name] = var
+ else:
+ # Not a template, don't read it
+ continue
+ if verbose:
+ print 'Found variable(s) %s in Template %s' % (
+ ', '.join(inner_vars.keys()), full)
+ for var_name, var in inner_vars.items():
+ # Easy case:
+ if var_name not in all_vars:
+ all_vars[var_name] = var
+ continue
+ # Emit warnings if the variables don't match well:
+ cur_var = all_vars[var_name]
+ if not cur_var.description:
+ cur_var.description = var.description
+ elif (cur_var.description and var.description
+ and var.description != cur_var.description):
+ print >> sys.stderr, (
+ "Variable descriptions do not match: %s: %s and %s"
+ % (var_name, cur_var.description, var.description))
+ if (cur_var.default is not command.NoDefault
+ and var.default is not command.NoDefault
+ and cur_var.default != var.default):
+ print >> sys.stderr, (
+ "Variable defaults do not match: %s: %r and %r"
+ % (var_name, cur_var.default, var.default))
+ return all_vars
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/testapp.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/testapp.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/testapp.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,101 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import cgi
+import os
+
+html_page_template = '''
+<html>
+<head>
+ <title>Test Application</title>
+</head>
+<body>
+<h1>Test Application: Working!</h1>
+
+<table border="1">
+%(environ)s
+</table>
+
+<p>
+Note: to see an error report, append <code>?error=true</code>
+to the URL
+</p>
+
+</body>
+</html>
+'''
+
+html_row_template = '''
+<tr>
+ <td><b>%(key)s</b></td>
+ <td><tt>%(value_literal)s</b></td>
+</tr>
+'''
+
+text_page_template = '%(environ)s'
+text_row_template = '%(key)s: %(value_repr)s\n'
+
+def make_literal(value):
+ value = cgi.escape(value, 1)
+ value = value.replace('\n\r', '\n')
+ value = value.replace('\r', '\n')
+ value = value.replace('\n', '<br>\n')
+ return value
+
+class TestApplication(object):
+
+ """
+ A test WSGI application, that prints out all the environmental
+ variables, and if you add ``?error=t`` to the URL it will
+ deliberately throw an exception.
+ """
+
+ def __init__(self, global_conf=None, text=False):
+ self.global_conf = global_conf
+ self.text = text
+
+ def __call__(self, environ, start_response):
+ if environ.get('QUERY_STRING', '').find('error=') >= 0:
+ assert 0, "Here is your error report, ordered and delivered"
+ if self.text:
+ page_template = text_page_template
+ row_template = text_row_template
+ content_type = 'text/plain; charset=utf8'
+ else:
+ page_template = html_page_template
+ row_template = html_row_template
+ content_type = 'text/html; charset=utf8'
+ keys = environ.keys()
+ keys.sort()
+ rows = []
+ for key in keys:
+ data = {'key': key}
+ value = environ[key]
+ data['value'] = value
+ try:
+ value = repr(value)
+ except Exception, e:
+ value = 'Cannot use repr(): %s' % e
+ data['value_repr'] = value
+ data['value_literal'] = make_literal(value)
+ row = row_template % data
+ rows.append(row)
+ rows = ''.join(rows)
+ page = page_template % {'environ': rows}
+ if isinstance(page, unicode):
+ page = page.encode('utf8')
+ headers = [('Content-type', content_type)]
+ start_response('200 OK', headers)
+ return [page]
+
+
+def make_test_application(global_conf, text=False, lint=False):
+ from paste.deploy.converters import asbool
+ text = asbool(text)
+ lint = asbool(lint)
+ app = TestApplication(global_conf=global_conf, text=text)
+ if lint:
+ from paste.lint import middleware
+ app = middleware(app)
+ return app
+
+make_test_application.__doc__ = TestApplication.__doc__
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/twisted_web2_server.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/twisted_web2_server.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/twisted_web2_server.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# @@: THIS IS INCOMPLETE!
+
+def run_twisted(wsgi_app, global_conf,
+ host='127.0.0.1', port='8080'):
+ host = host or None
+ import twisted.web2.wsgi
+ import twisted.web2.log
+ import twisted.web2.channel
+ import twisted.web2.server
+ import twisted.internet.reactor
+ wsgi_resource = twisted.web2.wsgi.WSGIResource(wsgi_app)
+ resource = twisted.web2.log.LogWrapperResource(wsgi_resource)
+ twisted.web2.log.DefaultCommonAccessLoggingObserver().start()
+ site = twisted.web2.server.Site(resource)
+ factory = twisted.web2.channel.HTTPFactory(site)
+ # --- start reactor for listen port
+ twisted.internet.reactor.listenTCP(int(port), factory, interface=host)
+ twisted.internet.reactor.run()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/logging_config.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/logging_config.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/logging_config.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,354 @@
+# Copyright 2001-2005 by Vinay Sajip. All Rights Reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of Vinay Sajip
+# not be used in advertising or publicity pertaining to distribution
+# of the software without specific, written prior permission.
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+Configuration functions for the logging package for Python. The core package
+is based on PEP 282 and comments thereto in comp.lang.python, and influenced
+by Apache's log4j system.
+
+Should work under Python versions >= 1.5.2, except that source line
+information is not available unless 'sys._getframe()' is.
+
+Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
+
+To use, simply 'import logging' and log away!
+"""
+
+import sys, logging, logging.handlers, string, socket, struct, os, traceback, types
+
+try:
+ import thread
+ import threading
+except ImportError:
+ thread = None
+
+from SocketServer import ThreadingTCPServer, StreamRequestHandler
+
+
+DEFAULT_LOGGING_CONFIG_PORT = 9030
+
+if sys.platform == "win32":
+ RESET_ERROR = 10054 #WSAECONNRESET
+else:
+ RESET_ERROR = 104 #ECONNRESET
+
+#
+# The following code implements a socket listener for on-the-fly
+# reconfiguration of logging.
+#
+# _listener holds the server object doing the listening
+_listener = None
+
+def fileConfig(fname, defaults=None):
+ """
+ Read the logging configuration from a ConfigParser-format file.
+
+ This can be called several times from an application, allowing an end user
+ the ability to select from various pre-canned configurations (if the
+ developer provides a mechanism to present the choices and load the chosen
+ configuration).
+ In versions of ConfigParser which have the readfp method [typically
+ shipped in 2.x versions of Python], you can pass in a file-like object
+ rather than a filename, in which case the file-like object will be read
+ using readfp.
+ """
+ import ConfigParser
+
+ cp = ConfigParser.ConfigParser(defaults)
+ if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
+ cp.readfp(fname)
+ else:
+ cp.read(fname)
+
+ formatters = _create_formatters(cp)
+
+ # critical section
+ logging._acquireLock()
+ try:
+ logging._handlers.clear()
+ if hasattr(logging, '_handlerList'):
+ del logging._handlerList[:]
+ # Handlers add themselves to logging._handlers
+ handlers = _install_handlers(cp, formatters)
+ _install_loggers(cp, handlers)
+ finally:
+ logging._releaseLock()
+
+
+def _resolve(name):
+ """Resolve a dotted name to a global object."""
+ name = string.split(name, '.')
+ used = name.pop(0)
+ found = __import__(used)
+ for n in name:
+ used = used + '.' + n
+ try:
+ found = getattr(found, n)
+ except AttributeError:
+ __import__(used)
+ found = getattr(found, n)
+ return found
+
+
+def _create_formatters(cp):
+ """Create and return formatters"""
+ flist = cp.get("formatters", "keys")
+ if not len(flist):
+ return {}
+ flist = string.split(flist, ",")
+ formatters = {}
+ for form in flist:
+ form = string.strip(form)
+ sectname = "formatter_%s" % form
+ opts = cp.options(sectname)
+ if "format" in opts:
+ fs = cp.get(sectname, "format", 1)
+ else:
+ fs = None
+ if "datefmt" in opts:
+ dfs = cp.get(sectname, "datefmt", 1)
+ else:
+ dfs = None
+ c = logging.Formatter
+ if "class" in opts:
+ class_name = cp.get(sectname, "class")
+ if class_name:
+ c = _resolve(class_name)
+ f = c(fs, dfs)
+ formatters[form] = f
+ return formatters
+
+
+def _install_handlers(cp, formatters):
+ """Install and return handlers"""
+ hlist = cp.get("handlers", "keys")
+ if not len(hlist):
+ return {}
+ hlist = string.split(hlist, ",")
+ handlers = {}
+ fixups = [] #for inter-handler references
+ for hand in hlist:
+ hand = string.strip(hand)
+ sectname = "handler_%s" % hand
+ klass = cp.get(sectname, "class")
+ opts = cp.options(sectname)
+ if "formatter" in opts:
+ fmt = cp.get(sectname, "formatter")
+ else:
+ fmt = ""
+ try:
+ klass = eval(klass, vars(logging))
+ except (AttributeError, NameError):
+ klass = _resolve(klass)
+ args = cp.get(sectname, "args")
+ args = eval(args, vars(logging))
+ h = apply(klass, args)
+ if "level" in opts:
+ level = cp.get(sectname, "level")
+ h.setLevel(logging._levelNames[level])
+ if len(fmt):
+ h.setFormatter(formatters[fmt])
+ #temporary hack for FileHandler and MemoryHandler.
+ if klass == logging.handlers.MemoryHandler:
+ if "target" in opts:
+ target = cp.get(sectname,"target")
+ else:
+ target = ""
+ if len(target): #the target handler may not be loaded yet, so keep for later...
+ fixups.append((h, target))
+ handlers[hand] = h
+ #now all handlers are loaded, fixup inter-handler references...
+ for h, t in fixups:
+ h.setTarget(handlers[t])
+ return handlers
+
+
+def _install_loggers(cp, handlers):
+ """Create and install loggers"""
+
+ # configure the root first
+ llist = cp.get("loggers", "keys")
+ llist = string.split(llist, ",")
+ llist = map(lambda x: string.strip(x), llist)
+ llist.remove("root")
+ sectname = "logger_root"
+ root = logging.root
+ log = root
+ opts = cp.options(sectname)
+ if "level" in opts:
+ level = cp.get(sectname, "level")
+ log.setLevel(logging._levelNames[level])
+ for h in root.handlers[:]:
+ root.removeHandler(h)
+ hlist = cp.get(sectname, "handlers")
+ if len(hlist):
+ hlist = string.split(hlist, ",")
+ for hand in hlist:
+ log.addHandler(handlers[string.strip(hand)])
+
+ #and now the others...
+ #we don't want to lose the existing loggers,
+ #since other threads may have pointers to them.
+ #existing is set to contain all existing loggers,
+ #and as we go through the new configuration we
+ #remove any which are configured. At the end,
+ #what's left in existing is the set of loggers
+ #which were in the previous configuration but
+ #which are not in the new configuration.
+ existing = root.manager.loggerDict.keys()
+ #now set up the new ones...
+ for log in llist:
+ sectname = "logger_%s" % log
+ qn = cp.get(sectname, "qualname")
+ opts = cp.options(sectname)
+ if "propagate" in opts:
+ propagate = cp.getint(sectname, "propagate")
+ else:
+ propagate = 1
+ logger = logging.getLogger(qn)
+ if qn in existing:
+ existing.remove(qn)
+ if "level" in opts:
+ level = cp.get(sectname, "level")
+ logger.setLevel(logging._levelNames[level])
+ for h in logger.handlers[:]:
+ logger.removeHandler(h)
+ logger.propagate = propagate
+ logger.disabled = 0
+ hlist = cp.get(sectname, "handlers")
+ if len(hlist):
+ hlist = string.split(hlist, ",")
+ for hand in hlist:
+ logger.addHandler(handlers[string.strip(hand)])
+
+ #Disable any old loggers. There's no point deleting
+ #them as other threads may continue to hold references
+ #and by disabling them, you stop them doing any logging.
+ for log in existing:
+ root.manager.loggerDict[log].disabled = 1
+
+
+def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
+ """
+ Start up a socket server on the specified port, and listen for new
+ configurations.
+
+ These will be sent as a file suitable for processing by fileConfig().
+ Returns a Thread object on which you can call start() to start the server,
+ and which you can join() when appropriate. To stop the server, call
+ stopListening().
+ """
+ if not thread:
+ raise NotImplementedError, "listen() needs threading to work"
+
+ class ConfigStreamHandler(StreamRequestHandler):
+ """
+ Handler for a logging configuration request.
+
+ It expects a completely new logging configuration and uses fileConfig
+ to install it.
+ """
+ def handle(self):
+ """
+ Handle a request.
+
+ Each request is expected to be a 4-byte length, packed using
+ struct.pack(">L", n), followed by the config file.
+ Uses fileConfig() to do the grunt work.
+ """
+ import tempfile
+ try:
+ conn = self.connection
+ chunk = conn.recv(4)
+ if len(chunk) == 4:
+ slen = struct.unpack(">L", chunk)[0]
+ chunk = self.connection.recv(slen)
+ while len(chunk) < slen:
+ chunk = chunk + conn.recv(slen - len(chunk))
+ #Apply new configuration. We'd like to be able to
+ #create a StringIO and pass that in, but unfortunately
+ #1.5.2 ConfigParser does not support reading file
+ #objects, only actual files. So we create a temporary
+ #file and remove it later.
+ file = tempfile.mktemp(".ini")
+ f = open(file, "w")
+ f.write(chunk)
+ f.close()
+ try:
+ fileConfig(file)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ traceback.print_exc()
+ os.remove(file)
+ except socket.error, e:
+ if type(e.args) != types.TupleType:
+ raise
+ else:
+ errcode = e.args[0]
+ if errcode != RESET_ERROR:
+ raise
+
+ class ConfigSocketReceiver(ThreadingTCPServer):
+ """
+ A simple TCP socket-based logging config receiver.
+ """
+
+ allow_reuse_address = 1
+
+ def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
+ handler=None):
+ ThreadingTCPServer.__init__(self, (host, port), handler)
+ logging._acquireLock()
+ self.abort = 0
+ logging._releaseLock()
+ self.timeout = 1
+
+ def serve_until_stopped(self):
+ import select
+ abort = 0
+ while not abort:
+ rd, wr, ex = select.select([self.socket.fileno()],
+ [], [],
+ self.timeout)
+ if rd:
+ self.handle_request()
+ logging._acquireLock()
+ abort = self.abort
+ logging._releaseLock()
+
+ def serve(rcvr, hdlr, port):
+ server = rcvr(port=port, handler=hdlr)
+ global _listener
+ logging._acquireLock()
+ _listener = server
+ logging._releaseLock()
+ server.serve_until_stopped()
+
+ return threading.Thread(target=serve,
+ args=(ConfigSocketReceiver,
+ ConfigStreamHandler, port))
+
+def stopListening():
+ """
+ Stop the listening server which was created with a call to listen().
+ """
+ global _listener
+ if _listener:
+ logging._acquireLock()
+ _listener.abort = 1
+ _listener = None
+ logging._releaseLock()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/secret.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/secret.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/secret.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Create random secrets.
+"""
+
+import os
+import random
+
+def random_bytes(length):
+ """
+ Return a string of the given length. Uses ``os.urandom`` if it
+ can, or just pseudo-random numbers otherwise.
+ """
+ try:
+ return os.urandom(length)
+ except AttributeError:
+ return ''.join([
+ chr(random.randrange(256)) for i in xrange(length)])
+
+def secret_string(length=25):
+ """
+ Returns a random string of the given length. The string
+ is a base64-encoded version of a set of random bytes, truncated
+ to the given length (and without any newlines).
+ """
+ s = random_bytes(length).encode('base64')
+ for badchar in '\n\r=':
+ s = s.replace(badchar, '')
+ # We're wasting some characters here. But random characters are
+ # cheap ;)
+ return s[:length]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/string24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/string24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/string24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,533 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""A collection of string operations (most are no longer used).
+
+Warning: most of the code you see here isn't normally used nowadays.
+Beginning with Python 1.6, many of these functions are implemented as
+methods on the standard string object. They used to be implemented by
+a built-in module called strop, but strop is now obsolete itself.
+
+Public module variables:
+
+whitespace -- a string containing all characters considered whitespace
+lowercase -- a string containing all characters considered lowercase letters
+uppercase -- a string containing all characters considered uppercase letters
+letters -- a string containing all characters considered letters
+digits -- a string containing all characters considered decimal digits
+hexdigits -- a string containing all characters considered hexadecimal digits
+octdigits -- a string containing all characters considered octal digits
+punctuation -- a string containing all characters considered punctuation
+printable -- a string containing all characters considered printable
+
+"""
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n\r\v\f'
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+letters = lowercase + uppercase
+ascii_lowercase = lowercase
+ascii_uppercase = uppercase
+ascii_letters = ascii_lowercase + ascii_uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+printable = digits + letters + punctuation + whitespace
+
+# Case conversion helpers
+# Use str to convert Unicode literal in case of -U
+# Note that Cookie.py bogusly uses _idmap :(
+l = map(chr, xrange(256))
+_idmap = str('').join(l)
+del l
+
+# Functions which aren't available as string methods.
+
+# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
+# See also regsub.capwords().
+def capwords(s, sep=None):
+ """capwords(s, [sep]) -> string
+
+ Split the argument into words using split, capitalize each
+ word using capitalize, and join the capitalized words using
+ join. Note that this replaces runs of whitespace characters by
+ a single space.
+
+ """
+ return (sep or ' ').join([x.capitalize() for x in s.split(sep)])
+
+
+# Construct a translation string
+_idmapL = None
+def maketrans(fromstr, tostr):
+ """maketrans(frm, to) -> string
+
+ Return a translation table (a string of 256 bytes long)
+ suitable for use in string.translate. The strings frm and to
+ must be of the same length.
+
+ """
+ if len(fromstr) != len(tostr):
+ raise ValueError, "maketrans arguments must have same length"
+ global _idmapL
+ if not _idmapL:
+ _idmapL = map(None, _idmap)
+ L = _idmapL[:]
+ fromstr = map(ord, fromstr)
+ for i in range(len(fromstr)):
+ L[fromstr[i]] = tostr[i]
+ return ''.join(L)
+
+
+
+####################################################################
+import re as _re
+
+class _multimap:
+ """Helper class for combining multiple mappings.
+
+ Used by .{safe_,}substitute() to combine the mapping and keyword
+ arguments.
+ """
+ def __init__(self, primary, secondary):
+ self._primary = primary
+ self._secondary = secondary
+
+ def __getitem__(self, key):
+ try:
+ return self._primary[key]
+ except KeyError:
+ return self._secondary[key]
+
+
+class _TemplateMetaclass(type):
+ pattern = r"""
+ %(delim)s(?:
+ (?P<escaped>%(delim)s) | # Escape sequence of two delimiters
+ (?P<named>%(id)s) | # delimiter and a Python identifier
+ {(?P<braced>%(id)s)} | # delimiter and a braced identifier
+ (?P<invalid>) # Other ill-formed delimiter exprs
+ )
+ """
+
+ def __init__(cls, name, bases, dct):
+ super(_TemplateMetaclass, cls).__init__(name, bases, dct)
+ if 'pattern' in dct:
+ pattern = cls.pattern
+ else:
+ pattern = _TemplateMetaclass.pattern % {
+ 'delim' : _re.escape(cls.delimiter),
+ 'id' : cls.idpattern,
+ }
+ cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
+
+
+class Template:
+ """A string class for supporting $-substitutions."""
+ __metaclass__ = _TemplateMetaclass
+
+ delimiter = '$'
+ idpattern = r'[_a-z][_a-z0-9]*'
+
+ def __init__(self, template):
+ self.template = template
+
+ # Search for $$, $identifier, ${identifier}, and any bare $'s
+
+ def _invalid(self, mo):
+ i = mo.start('invalid')
+ lines = self.template[:i].splitlines(True)
+ if not lines:
+ colno = 1
+ lineno = 1
+ else:
+ colno = i - len(''.join(lines[:-1]))
+ lineno = len(lines)
+ raise ValueError('Invalid placeholder in string: line %d, col %d' %
+ (lineno, colno))
+
+ def substitute(self, *args, **kws):
+ if len(args) > 1:
+ raise TypeError('Too many positional arguments')
+ if not args:
+ mapping = kws
+ elif kws:
+ mapping = _multimap(kws, args[0])
+ else:
+ mapping = args[0]
+ # Helper function for .sub()
+ def convert(mo):
+ # Check the most common path first.
+ named = mo.group('named') or mo.group('braced')
+ if named is not None:
+ val = mapping[named]
+ # We use this idiom instead of str() because the latter will
+ # fail if val is a Unicode containing non-ASCII characters.
+ return '%s' % val
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ self._invalid(mo)
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+ def safe_substitute(self, *args, **kws):
+ if len(args) > 1:
+ raise TypeError('Too many positional arguments')
+ if not args:
+ mapping = kws
+ elif kws:
+ mapping = _multimap(kws, args[0])
+ else:
+ mapping = args[0]
+ # Helper function for .sub()
+ def convert(mo):
+ named = mo.group('named')
+ if named is not None:
+ try:
+ # We use this idiom instead of str() because the latter
+ # will fail if val is a Unicode containing non-ASCII
+ return '%s' % mapping[named]
+ except KeyError:
+ return self.delimiter + named
+ braced = mo.group('braced')
+ if braced is not None:
+ try:
+ return '%s' % mapping[braced]
+ except KeyError:
+ return self.delimiter + '{' + braced + '}'
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ return self.delimiter
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+
+
+####################################################################
+# NOTE: Everything below here is deprecated. Use string methods instead.
+# This stuff will go away in Python 3.0.
+
+# Backward compatible names for exceptions
+index_error = ValueError
+atoi_error = ValueError
+atof_error = ValueError
+atol_error = ValueError
+
+# convert UPPER CASE letters to lower case
+def lower(s):
+ """lower(s) -> string
+
+ Return a copy of the string s converted to lowercase.
+
+ """
+ return s.lower()
+
+# Convert lower case letters to UPPER CASE
+def upper(s):
+ """upper(s) -> string
+
+ Return a copy of the string s converted to uppercase.
+
+ """
+ return s.upper()
+
+# Swap lower case letters and UPPER CASE
+def swapcase(s):
+ """swapcase(s) -> string
+
+ Return a copy of the string s with upper case characters
+ converted to lowercase and vice versa.
+
+ """
+ return s.swapcase()
+
+# Strip leading and trailing tabs and spaces
+def strip(s, chars=None):
+ """strip(s [,chars]) -> string
+
+ Return a copy of the string s with leading and trailing
+ whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+ If chars is unicode, S will be converted to unicode before stripping.
+
+ """
+ return s.strip(chars)
+
+# Strip leading tabs and spaces
+def lstrip(s, chars=None):
+ """lstrip(s [,chars]) -> string
+
+ Return a copy of the string s with leading whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+
+ """
+ return s.lstrip(chars)
+
+# Strip trailing tabs and spaces
+def rstrip(s, chars=None):
+ """rstrip(s [,chars]) -> string
+
+ Return a copy of the string s with trailing whitespace removed.
+ If chars is given and not None, remove characters in chars instead.
+
+ """
+ return s.rstrip(chars)
+
+
+# Split a string into a list of space/tab-separated words
+def split(s, sep=None, maxsplit=-1):
+ """split(s [,sep [,maxsplit]]) -> list of strings
+
+ Return a list of the words in the string s, using sep as the
+ delimiter string. If maxsplit is given, splits at no more than
+ maxsplit places (resulting in at most maxsplit+1 words). If sep
+ is not specified or is None, any whitespace string is a separator.
+
+ (split and splitfields are synonymous)
+
+ """
+ return s.split(sep, maxsplit)
+splitfields = split
+
+# Split a string into a list of space/tab-separated words
+def rsplit(s, sep=None, maxsplit=-1):
+ """rsplit(s [,sep [,maxsplit]]) -> list of strings
+
+ Return a list of the words in the string s, using sep as the
+ delimiter string, starting at the end of the string and working
+ to the front. If maxsplit is given, at most maxsplit splits are
+ done. If sep is not specified or is None, any whitespace string
+ is a separator.
+ """
+ return s.rsplit(sep, maxsplit)
+
+# Join fields with optional separator
+def join(words, sep = ' '):
+ """join(list [,sep]) -> string
+
+ Return a string composed of the words in list, with
+ intervening occurrences of sep. The default separator is a
+ single space.
+
+ (joinfields and join are synonymous)
+
+ """
+ return sep.join(words)
+joinfields = join
+
+# Find substring, raise exception if not found
+def index(s, *args):
+ """index(s, sub [,start [,end]]) -> int
+
+ Like find but raises ValueError when the substring is not found.
+
+ """
+ return s.index(*args)
+
+# Find last substring, raise exception if not found
+def rindex(s, *args):
+ """rindex(s, sub [,start [,end]]) -> int
+
+ Like rfind but raises ValueError when the substring is not found.
+
+ """
+ return s.rindex(*args)
+
+# Count non-overlapping occurrences of substring
+def count(s, *args):
+ """count(s, sub[, start[,end]]) -> int
+
+ Return the number of occurrences of substring sub in string
+ s[start:end]. Optional arguments start and end are
+ interpreted as in slice notation.
+
+ """
+ return s.count(*args)
+
+# Find substring, return -1 if not found
+def find(s, *args):
+ """find(s, sub [,start [,end]]) -> in
+
+ Return the lowest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return s.find(*args)
+
+# Find last substring, return -1 if not found
+def rfind(s, *args):
+ """rfind(s, sub [,start [,end]]) -> int
+
+ Return the highest index in s where substring sub is found,
+ such that sub is contained within s[start,end]. Optional
+ arguments start and end are interpreted as in slice notation.
+
+ Return -1 on failure.
+
+ """
+ return s.rfind(*args)
+
+# for a bit of speed
+_float = float
+_int = int
+_long = long
+
+# Convert string to float
+def atof(s):
+ """atof(s) -> float
+
+ Return the floating point number represented by the string s.
+
+ """
+ return _float(s)
+
+
+# Convert string to integer
+def atoi(s , base=10):
+ """atoi(s [,base]) -> int
+
+ Return the integer represented by the string s in the given
+ base, which defaults to 10. The string s must consist of one
+ or more digits, possibly preceded by a sign. If base is 0, it
+ is chosen from the leading characters of s, 0 for octal, 0x or
+ 0X for hexadecimal. If base is 16, a preceding 0x or 0X is
+ accepted.
+
+ """
+ return _int(s, base)
+
+
+# Convert string to long integer
+def atol(s, base=10):
+ """atol(s [,base]) -> long
+
+ Return the long integer represented by the string s in the
+ given base, which defaults to 10. The string s must consist
+ of one or more digits, possibly preceded by a sign. If base
+ is 0, it is chosen from the leading characters of s, 0 for
+ octal, 0x or 0X for hexadecimal. If base is 16, a preceding
+ 0x or 0X is accepted. A trailing L or l is not accepted,
+ unless base is 0.
+
+ """
+ return _long(s, base)
+
+
+# Left-justify a string
+def ljust(s, width, *args):
+ """ljust(s, width[, fillchar]) -> string
+
+ Return a left-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.ljust(width, *args)
+
+# Right-justify a string
+def rjust(s, width, *args):
+ """rjust(s, width[, fillchar]) -> string
+
+ Return a right-justified version of s, in a field of the
+ specified width, padded with spaces as needed. The string is
+ never truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.rjust(width, *args)
+
+# Center a string
+def center(s, width, *args):
+ """center(s, width[, fillchar]) -> string
+
+ Return a center version of s, in a field of the specified
+ width. padded with spaces as needed. The string is never
+ truncated. If specified the fillchar is used instead of spaces.
+
+ """
+ return s.center(width, *args)
+
+# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
+# Decadent feature: the argument may be a string or a number
+# (Use of this is deprecated; it should be a string as with ljust c.s.)
+def zfill(x, width):
+ """zfill(x, width) -> string
+
+ Pad a numeric string x with zeros on the left, to fill a field
+ of the specified width. The string x is never truncated.
+
+ """
+ if not isinstance(x, basestring):
+ x = repr(x)
+ return x.zfill(width)
+
+# Expand tabs in a string.
+# Doesn't take non-printing chars into account, but does understand \n.
+def expandtabs(s, tabsize=8):
+ """expandtabs(s [,tabsize]) -> string
+
+ Return a copy of the string s with all tab characters replaced
+ by the appropriate number of spaces, depending on the current
+ column, and the tabsize (default 8).
+
+ """
+ return s.expandtabs(tabsize)
+
+# Character translation through look-up table.
+def translate(s, table, deletions=""):
+ """translate(s,table [,deletions]) -> string
+
+ Return a copy of the string s, where all characters occurring
+ in the optional argument deletions are removed, and the
+ remaining characters have been mapped through the given
+ translation table, which must be a string of length 256. The
+ deletions argument is not allowed for Unicode strings.
+
+ """
+ if deletions:
+ return s.translate(table, deletions)
+ else:
+ # Add s[:0] so that if s is Unicode and table is an 8-bit string,
+ # table is converted to Unicode. This means that table *cannot*
+ # be a dictionary -- for that feature, use u.translate() directly.
+ return s.translate(table + s[:0])
+
+# Capitalize a string, e.g. "aBc dEf" -> "Abc def".
+def capitalize(s):
+ """capitalize(s) -> string
+
+ Return a copy of the string s with only its first character
+ capitalized.
+
+ """
+ return s.capitalize()
+
+# Substring replacement (global)
+def replace(s, old, new, maxsplit=-1):
+ """replace (str, old, new[, maxsplit]) -> string
+
+ Return a copy of string str with all occurrences of substring
+ old replaced by new. If the optional argument maxsplit is
+ given, only the first maxsplit occurrences are replaced.
+
+ """
+ return s.replace(old, new, maxsplit)
+
+
+# Try importing optional built-in module "strop" -- if it exists,
+# it redefines some string operations that are 100-1000 times faster.
+# It also defines values for whitespace, lowercase and uppercase
+# that match <ctype.h>'s definitions.
+
+try:
+ from strop import maketrans, lowercase, uppercase, whitespace
+ letters = lowercase + uppercase
+except ImportError:
+ pass # Use the original versions
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/subprocess24.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/subprocess24.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/subprocess24.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1154 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+# subprocess - Subprocesses with accessible I/O streams
+#
+# For more information about this module, see PEP 324.
+#
+# This module should remain compatible with Python 2.2, see PEP 291.
+#
+# Copyright (c) 2003-2005 by Peter Astrand <astrand at lysator.liu.se>
+#
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/2.4/license for licensing details.
+
+r"""subprocess - Subprocesses with accessible I/O streams
+
+This module allows you to spawn processes, connect to their
+input/output/error pipes, and obtain their return codes. This module
+intends to replace several other, older modules and functions, like:
+
+os.system
+os.spawn*
+os.popen*
+popen2.*
+commands.*
+
+Information about how the subprocess module can be used to replace these
+modules and functions can be found below.
+
+
+
+Using the subprocess module
+===========================
+This module defines one class called Popen:
+
+class Popen(args, bufsize=0, executable=None,
+ stdin=None, stdout=None, stderr=None,
+ preexec_fn=None, close_fds=False, shell=False,
+ cwd=None, env=None, universal_newlines=False,
+ startupinfo=None, creationflags=0):
+
+
+Arguments are:
+
+args should be a string, or a sequence of program arguments. The
+program to execute is normally the first item in the args sequence or
+string, but can be explicitly set by using the executable argument.
+
+On UNIX, with shell=False (default): In this case, the Popen class
+uses os.execvp() to execute the child program. args should normally
+be a sequence. A string will be treated as a sequence with the string
+as the only item (the program to execute).
+
+On UNIX, with shell=True: If args is a string, it specifies the
+command string to execute through the shell. If args is a sequence,
+the first item specifies the command string, and any additional items
+will be treated as additional shell arguments.
+
+On Windows: the Popen class uses CreateProcess() to execute the child
+program, which operates on strings. If args is a sequence, it will be
+converted to a string using the list2cmdline method. Please note that
+not all MS Windows applications interpret the command line the same
+way: The list2cmdline is designed for applications using the same
+rules as the MS C runtime.
+
+bufsize, if given, has the same meaning as the corresponding argument
+to the built-in open() function: 0 means unbuffered, 1 means line
+buffered, any other positive value means use a buffer of
+(approximately) that size. A negative bufsize means to use the system
+default, which usually means fully buffered. The default value for
+bufsize is 0 (unbuffered).
+
+stdin, stdout and stderr specify the executed programs' standard
+input, standard output and standard error file handles, respectively.
+Valid values are PIPE, an existing file descriptor (a positive
+integer), an existing file object, and None. PIPE indicates that a
+new pipe to the child should be created. With None, no redirection
+will occur; the child's file handles will be inherited from the
+parent. Additionally, stderr can be STDOUT, which indicates that the
+stderr data from the applications should be captured into the same
+file handle as for stdout.
+
+If preexec_fn is set to a callable object, this object will be called
+in the child process just before the child is executed.
+
+If close_fds is true, all file descriptors except 0, 1 and 2 will be
+closed before the child process is executed.
+
+if shell is true, the specified command will be executed through the
+shell.
+
+If cwd is not None, the current directory will be changed to cwd
+before the child is executed.
+
+If env is not None, it defines the environment variables for the new
+process.
+
+If universal_newlines is true, the file objects stdout and stderr are
+opened as a text files, but lines may be terminated by any of '\n',
+the Unix end-of-line convention, '\r', the Macintosh convention or
+'\r\n', the Windows convention. All of these external representations
+are seen as '\n' by the Python program. Note: This feature is only
+available if Python is built with universal newline support (the
+default). Also, the newlines attribute of the file objects stdout,
+stdin and stderr are not updated by the communicate() method.
+
+The startupinfo and creationflags, if given, will be passed to the
+underlying CreateProcess() function. They can specify things such as
+appearance of the main window and priority for the new process.
+(Windows only)
+
+
+This module also defines two shortcut functions:
+
+call(*args, **kwargs):
+ Run command with arguments. Wait for command to complete, then
+ return the returncode attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ retcode = call(["ls", "-l"])
+
+
+Exceptions
+----------
+Exceptions raised in the child process, before the new program has
+started to execute, will be re-raised in the parent. Additionally,
+the exception object will have one extra attribute called
+'child_traceback', which is a string containing traceback information
+from the childs point of view.
+
+The most common exception raised is OSError. This occurs, for
+example, when trying to execute a non-existent file. Applications
+should prepare for OSErrors.
+
+A ValueError will be raised if Popen is called with invalid arguments.
+
+
+Security
+--------
+Unlike some other popen functions, this implementation will never call
+/bin/sh implicitly. This means that all characters, including shell
+metacharacters, can safely be passed to child processes.
+
+
+Popen objects
+=============
+Instances of the Popen class have the following methods:
+
+poll()
+ Check if child process has terminated. Returns returncode
+ attribute.
+
+wait()
+ Wait for child process to terminate. Returns returncode attribute.
+
+communicate(input=None)
+ Interact with process: Send data to stdin. Read data from stdout
+ and stderr, until end-of-file is reached. Wait for process to
+ terminate. The optional stdin argument should be a string to be
+ sent to the child process, or None, if no data should be sent to
+ the child.
+
+ communicate() returns a tuple (stdout, stderr).
+
+ Note: The data read is buffered in memory, so do not use this
+ method if the data size is large or unlimited.
+
+The following attributes are also available:
+
+stdin
+ If the stdin argument is PIPE, this attribute is a file object
+ that provides input to the child process. Otherwise, it is None.
+
+stdout
+ If the stdout argument is PIPE, this attribute is a file object
+ that provides output from the child process. Otherwise, it is
+ None.
+
+stderr
+ If the stderr argument is PIPE, this attribute is file object that
+ provides error output from the child process. Otherwise, it is
+ None.
+
+pid
+ The process ID of the child process.
+
+returncode
+ The child return code. A None value indicates that the process
+ hasn't terminated yet. A negative value -N indicates that the
+ child was terminated by signal N (UNIX only).
+
+
+Replacing older functions with the subprocess module
+====================================================
+In this section, "a ==> b" means that b can be used as a replacement
+for a.
+
+Note: All functions in this section fail (more or less) silently if
+the executed program cannot be found; this module raises an OSError
+exception.
+
+In the following examples, we assume that the subprocess module is
+imported with "from subprocess import *".
+
+
+Replacing /bin/sh shell backquote
+---------------------------------
+output=`mycmd myarg`
+==>
+output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
+
+
+Replacing shell pipe line
+-------------------------
+output=`dmesg | grep hda`
+==>
+p1 = Popen(["dmesg"], stdout=PIPE)
+p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+output = p2.communicate()[0]
+
+
+Replacing os.system()
+---------------------
+sts = os.system("mycmd" + " myarg")
+==>
+p = Popen("mycmd" + " myarg", shell=True)
+sts = os.waitpid(p.pid, 0)
+
+Note:
+
+* Calling the program through the shell is usually not required.
+
+* It's easier to look at the returncode attribute than the
+ exitstatus.
+
+A more real-world example would look like this:
+
+try:
+ retcode = call("mycmd" + " myarg", shell=True)
+ if retcode < 0:
+ print >>sys.stderr, "Child was terminated by signal", -retcode
+ else:
+ print >>sys.stderr, "Child returned", retcode
+except OSError, e:
+ print >>sys.stderr, "Execution failed:", e
+
+
+Replacing os.spawn*
+-------------------
+P_NOWAIT example:
+
+pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+pid = Popen(["/bin/mycmd", "myarg"]).pid
+
+
+P_WAIT example:
+
+retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+retcode = call(["/bin/mycmd", "myarg"])
+
+
+Vector example:
+
+os.spawnvp(os.P_NOWAIT, path, args)
+==>
+Popen([path] + args[1:])
+
+
+Environment example:
+
+os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
+==>
+Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
+
+
+Replacing os.popen*
+-------------------
+pipe = os.popen(cmd, mode='r', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
+
+pipe = os.popen(cmd, mode='w', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
+
+
+(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdin, child_stdout) = (p.stdin, p.stdout)
+
+
+(child_stdin,
+ child_stdout,
+ child_stderr) = os.popen3(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
+(child_stdin,
+ child_stdout,
+ child_stderr) = (p.stdin, p.stdout, p.stderr)
+
+
+(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
+
+
+Replacing popen2.*
+------------------
+Note: If the cmd argument to popen2 functions is a string, the command
+is executed through /bin/sh. If it is a list, the command is directly
+executed.
+
+(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
+==>
+p = Popen(["somestring"], shell=True, bufsize=bufsize
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+
+(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
+==>
+p = Popen(["mycmd", "myarg"], bufsize=bufsize,
+ stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
+except that:
+
+* subprocess.Popen raises an exception if the execution fails
+* the capturestderr argument is replaced with the stderr argument.
+* stdin=PIPE and stdout=PIPE must be specified.
+* popen2 closes all filedescriptors by default, but you have to specify
+ close_fds=True with subprocess.Popen.
+
+
+"""
+
+import sys
+mswindows = (sys.platform == "win32")
+
+import os
+import types
+import traceback
+
+if mswindows:
+ import threading
+ import msvcrt
+ if 0: # <-- change this to use pywin32 instead of the _subprocess driver
+ import pywintypes
+ from win32api import GetStdHandle, STD_INPUT_HANDLE, \
+ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
+ from win32api import GetCurrentProcess, DuplicateHandle, \
+ GetModuleFileName, GetVersion
+ from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE
+ from win32pipe import CreatePipe
+ from win32process import CreateProcess, STARTUPINFO, \
+ GetExitCodeProcess, STARTF_USESTDHANDLES, \
+ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
+ from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
+ else:
+ raise ImportError(
+ "Windows subprocess module must be installed: see "
+ "http://effbot.org/downloads/#subprocess")
+ from _subprocess import *
+ class STARTUPINFO:
+ dwFlags = 0
+ hStdInput = None
+ hStdOutput = None
+ hStdError = None
+ class pywintypes:
+ error = IOError
+else:
+ import select
+ import errno
+ import fcntl
+ import pickle
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call"]
+
+try:
+ MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+ MAXFD = 256
+
+# True/False does not exist on 2.2.0
+try:
+ False
+except NameError:
+ False = 0
+ True = 1
+
+_active = []
+
+def _cleanup():
+ for inst in _active[:]:
+ inst.poll()
+
+PIPE = -1
+STDOUT = -2
+
+
+def call(*args, **kwargs):
+ """Run command with arguments. Wait for command to complete, then
+ return the returncode attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ retcode = call(["ls", "-l"])
+ """
+ return Popen(*args, **kwargs).wait()
+
+
+def list2cmdline(seq):
+ """
+ Translate a sequence of arguments into a command line
+ string, using the same rules as the MS C runtime:
+
+ 1) Arguments are delimited by white space, which is either a
+ space or a tab.
+
+ 2) A string surrounded by double quotation marks is
+ interpreted as a single argument, regardless of white space
+ contained within. A quoted string can be embedded in an
+ argument.
+
+ 3) A double quotation mark preceded by a backslash is
+ interpreted as a literal double quotation mark.
+
+ 4) Backslashes are interpreted literally, unless they
+ immediately precede a double quotation mark.
+
+ 5) If backslashes immediately precede a double quotation mark,
+ every pair of backslashes is interpreted as a literal
+ backslash. If the number of backslashes is odd, the last
+ backslash escapes the next double quotation mark as
+ described in rule 3.
+ """
+
+ # See
+ # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
+ result = []
+ needquote = False
+ for arg in seq:
+ bs_buf = []
+
+ # Add a space to separate this argument from the others
+ if result:
+ result.append(' ')
+
+ needquote = (" " in arg) or ("\t" in arg)
+ if needquote:
+ result.append('"')
+
+ for c in arg:
+ if c == '\\':
+ # Don't know if we need to double yet.
+ bs_buf.append(c)
+ elif c == '"':
+ # Double backspaces.
+ result.append('\\' * len(bs_buf)*2)
+ bs_buf = []
+ result.append('\\"')
+ else:
+ # Normal char
+ if bs_buf:
+ result.extend(bs_buf)
+ bs_buf = []
+ result.append(c)
+
+ # Add remaining backspaces, if any.
+ if bs_buf:
+ result.extend(bs_buf)
+
+ if needquote:
+ result.extend(bs_buf)
+ result.append('"')
+
+ return ''.join(result)
+
+
+class Popen(object):
+ def __init__(self, args, bufsize=0, executable=None,
+ stdin=None, stdout=None, stderr=None,
+ preexec_fn=None, close_fds=False, shell=False,
+ cwd=None, env=None, universal_newlines=False,
+ startupinfo=None, creationflags=0):
+ """Create new Popen instance."""
+ _cleanup()
+
+ if not isinstance(bufsize, (int, long)):
+ raise TypeError("bufsize must be an integer")
+
+ if mswindows:
+ if preexec_fn is not None:
+ raise ValueError("preexec_fn is not supported on Windows "
+ "platforms")
+ if close_fds:
+ raise ValueError("close_fds is not supported on Windows "
+ "platforms")
+ else:
+ # POSIX
+ if startupinfo is not None:
+ raise ValueError("startupinfo is only supported on Windows "
+ "platforms")
+ if creationflags != 0:
+ raise ValueError("creationflags is only supported on Windows "
+ "platforms")
+
+ self.stdin = None
+ self.stdout = None
+ self.stderr = None
+ self.pid = None
+ self.returncode = None
+ self.universal_newlines = universal_newlines
+
+ # Input and output objects. The general principle is like
+ # this:
+ #
+ # Parent Child
+ # ------ -----
+ # p2cwrite ---stdin---> p2cread
+ # c2pread <--stdout--- c2pwrite
+ # errread <--stderr--- errwrite
+ #
+ # On POSIX, the child objects are file descriptors. On
+ # Windows, these are Windows file handles. The parent objects
+ # are file descriptors on both platforms. The parent objects
+ # are None when not using PIPEs. The child objects are None
+ # when not redirecting.
+
+ (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+ self._execute_child(args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+ if p2cwrite:
+ self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
+ if c2pread:
+ if universal_newlines:
+ self.stdout = os.fdopen(c2pread, 'rU', bufsize)
+ else:
+ self.stdout = os.fdopen(c2pread, 'rb', bufsize)
+ if errread:
+ if universal_newlines:
+ self.stderr = os.fdopen(errread, 'rU', bufsize)
+ else:
+ self.stderr = os.fdopen(errread, 'rb', bufsize)
+
+ _active.append(self)
+
+
+ def _translate_newlines(self, data):
+ data = data.replace("\r\n", "\n")
+ data = data.replace("\r", "\n")
+ return data
+
+
+ if mswindows:
+ #
+ # Windows methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tupel with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ if stdin == None and stdout == None and stderr == None:
+ return (None, None, None, None, None, None)
+
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+ errread, errwrite = None, None
+
+ if stdin == None:
+ p2cread = GetStdHandle(STD_INPUT_HANDLE)
+ elif stdin == PIPE:
+ p2cread, p2cwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ p2cwrite = p2cwrite.Detach()
+ p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+ elif type(stdin) == types.IntType:
+ p2cread = msvcrt.get_osfhandle(stdin)
+ else:
+ # Assuming file-like object
+ p2cread = msvcrt.get_osfhandle(stdin.fileno())
+ p2cread = self._make_inheritable(p2cread)
+
+ if stdout == None:
+ c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
+ elif stdout == PIPE:
+ c2pread, c2pwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ c2pread = c2pread.Detach()
+ c2pread = msvcrt.open_osfhandle(c2pread, 0)
+ elif type(stdout) == types.IntType:
+ c2pwrite = msvcrt.get_osfhandle(stdout)
+ else:
+ # Assuming file-like object
+ c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+ c2pwrite = self._make_inheritable(c2pwrite)
+
+ if stderr == None:
+ errwrite = GetStdHandle(STD_ERROR_HANDLE)
+ elif stderr == PIPE:
+ errread, errwrite = CreatePipe(None, 0)
+ # Detach and turn into fd
+ errread = errread.Detach()
+ errread = msvcrt.open_osfhandle(errread, 0)
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif type(stderr) == types.IntType:
+ errwrite = msvcrt.get_osfhandle(stderr)
+ else:
+ # Assuming file-like object
+ errwrite = msvcrt.get_osfhandle(stderr.fileno())
+ errwrite = self._make_inheritable(errwrite)
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _make_inheritable(self, handle):
+ """Return a duplicate of handle, which is inheritable"""
+ return DuplicateHandle(GetCurrentProcess(), handle,
+ GetCurrentProcess(), 0, 1,
+ DUPLICATE_SAME_ACCESS)
+
+
+ def _find_w9xpopen(self):
+ """Find and return absolut path to w9xpopen.exe"""
+ w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
+ "w9xpopen.exe")
+ if not os.path.exists(w9xpopen):
+ # Eeek - file-not-found - possibly an embedding
+ # situation - see if we can locate it in sys.exec_prefix
+ w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
+ "w9xpopen.exe")
+ if not os.path.exists(w9xpopen):
+ raise RuntimeError("Cannot locate w9xpopen.exe, which is "
+ "needed for Popen to work with your "
+ "shell or platform.")
+ return w9xpopen
+
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ """Execute program (MS Windows version)"""
+
+ if not isinstance(args, types.StringTypes):
+ args = list2cmdline(args)
+
+ # Process startup details
+ default_startupinfo = STARTUPINFO()
+ if startupinfo == None:
+ startupinfo = default_startupinfo
+ if not None in (p2cread, c2pwrite, errwrite):
+ startupinfo.dwFlags |= STARTF_USESTDHANDLES
+ startupinfo.hStdInput = p2cread
+ startupinfo.hStdOutput = c2pwrite
+ startupinfo.hStdError = errwrite
+
+ if shell:
+ default_startupinfo.dwFlags |= STARTF_USESHOWWINDOW
+ default_startupinfo.wShowWindow = SW_HIDE
+ comspec = os.environ.get("COMSPEC", "cmd.exe")
+ args = comspec + " /c " + args
+ if (GetVersion() >= 0x80000000L or
+ os.path.basename(comspec).lower() == "command.com"):
+ # Win9x, or using command.com on NT. We need to
+ # use the w9xpopen intermediate program. For more
+ # information, see KB Q150956
+ # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
+ w9xpopen = self._find_w9xpopen()
+ args = '"%s" %s' % (w9xpopen, args)
+ # Not passing CREATE_NEW_CONSOLE has been known to
+ # cause random failures on win9x. Specifically a
+ # dialog: "Your program accessed mem currently in
+ # use at xxx" and a hopeful warning about the
+ # stability of your system. Cost is Ctrl+C wont
+ # kill children.
+ creationflags |= CREATE_NEW_CONSOLE
+
+ # Start the process
+ try:
+ hp, ht, pid, tid = CreateProcess(executable, args,
+ # no special security
+ None, None,
+ # must inherit handles to pass std
+ # handles
+ 1,
+ creationflags,
+ env,
+ cwd,
+ startupinfo)
+ except pywintypes.error, e:
+ # Translate pywintypes.error to WindowsError, which is
+ # a subclass of OSError. FIXME: We should really
+ # translate errno using _sys_errlist (or simliar), but
+ # how can this be done from Python?
+ raise WindowsError(*e.args)
+
+ # Retain the process handle, but close the thread handle
+ self._handle = hp
+ self.pid = pid
+ ht.Close()
+
+ # Child is launched. Close the parent's copy of those pipe
+ # handles that only the child should have open. You need
+ # to make sure that no handles to the write end of the
+ # output pipe are maintained in this process or else the
+ # pipe will not close when the child process exits and the
+ # ReadFile will hang.
+ if p2cread != None:
+ p2cread.Close()
+ if c2pwrite != None:
+ c2pwrite.Close()
+ if errwrite != None:
+ errwrite.Close()
+
+
+ def poll(self):
+ """Check if child process has terminated. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
+ self.returncode = GetExitCodeProcess(self._handle)
+ _active.remove(self)
+ return self.returncode
+
+
+ def wait(self):
+ """Wait for child process to terminate. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ obj = WaitForSingleObject(self._handle, INFINITE)
+ self.returncode = GetExitCodeProcess(self._handle)
+ _active.remove(self)
+ return self.returncode
+
+
+ def _readerthread(self, fh, buffer):
+ buffer.append(fh.read())
+
+
+ def communicate(self, input=None):
+ """Interact with process: Send data to stdin. Read data from
+ stdout and stderr, until end-of-file is reached. Wait for
+ process to terminate. The optional input argument should be a
+ string to be sent to the child process, or None, if no data
+ should be sent to the child.
+
+ communicate() returns a tuple (stdout, stderr)."""
+ stdout = None # Return
+ stderr = None # Return
+
+ if self.stdout:
+ stdout = []
+ stdout_thread = threading.Thread(target=self._readerthread,
+ args=(self.stdout, stdout))
+ stdout_thread.setDaemon(True)
+ stdout_thread.start()
+ if self.stderr:
+ stderr = []
+ stderr_thread = threading.Thread(target=self._readerthread,
+ args=(self.stderr, stderr))
+ stderr_thread.setDaemon(True)
+ stderr_thread.start()
+
+ if self.stdin:
+ if input != None:
+ self.stdin.write(input)
+ self.stdin.close()
+
+ if self.stdout:
+ stdout_thread.join()
+ if self.stderr:
+ stderr_thread.join()
+
+ # All data exchanged. Translate lists into strings.
+ if stdout != None:
+ stdout = stdout[0]
+ if stderr != None:
+ stderr = stderr[0]
+
+ # Translate newlines, if requested. We cannot let the file
+ # object do the translation: It is based on stdio, which is
+ # impossible to combine with select (unless forcing no
+ # buffering).
+ if self.universal_newlines and hasattr(open, 'newlines'):
+ if stdout:
+ stdout = self._translate_newlines(stdout)
+ if stderr:
+ stderr = self._translate_newlines(stderr)
+
+ self.wait()
+ return (stdout, stderr)
+
+ else:
+ #
+ # POSIX methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tupel with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ p2cread, p2cwrite = None, None
+ c2pread, c2pwrite = None, None
+ errread, errwrite = None, None
+
+ if stdin == None:
+ pass
+ elif stdin == PIPE:
+ p2cread, p2cwrite = os.pipe()
+ elif type(stdin) == types.IntType:
+ p2cread = stdin
+ else:
+ # Assuming file-like object
+ p2cread = stdin.fileno()
+
+ if stdout == None:
+ pass
+ elif stdout == PIPE:
+ c2pread, c2pwrite = os.pipe()
+ elif type(stdout) == types.IntType:
+ c2pwrite = stdout
+ else:
+ # Assuming file-like object
+ c2pwrite = stdout.fileno()
+
+ if stderr == None:
+ pass
+ elif stderr == PIPE:
+ errread, errwrite = os.pipe()
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif type(stderr) == types.IntType:
+ errwrite = stderr
+ else:
+ # Assuming file-like object
+ errwrite = stderr.fileno()
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _set_cloexec_flag(self, fd):
+ try:
+ cloexec_flag = fcntl.FD_CLOEXEC
+ except AttributeError:
+ cloexec_flag = 1
+
+ old = fcntl.fcntl(fd, fcntl.F_GETFD)
+ fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
+
+
+ def _close_fds(self, but):
+ for i in range(3, MAXFD):
+ if i == but:
+ continue
+ try:
+ os.close(i)
+ except:
+ pass
+
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ """Execute program (POSIX version)"""
+
+ if isinstance(args, types.StringTypes):
+ args = [args]
+
+ if shell:
+ args = ["/bin/sh", "-c"] + args
+
+ if executable == None:
+ executable = args[0]
+
+ # For transferring possible exec failure from child to parent
+ # The first char specifies the exception type: 0 means
+ # OSError, 1 means some other error.
+ errpipe_read, errpipe_write = os.pipe()
+ self._set_cloexec_flag(errpipe_write)
+
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ try:
+ # Close parent's pipe ends
+ if p2cwrite:
+ os.close(p2cwrite)
+ if c2pread:
+ os.close(c2pread)
+ if errread:
+ os.close(errread)
+ os.close(errpipe_read)
+
+ # Dup fds for child
+ if p2cread:
+ os.dup2(p2cread, 0)
+ if c2pwrite:
+ os.dup2(c2pwrite, 1)
+ if errwrite:
+ os.dup2(errwrite, 2)
+
+ # Close pipe fds. Make sure we doesn't close the same
+ # fd more than once.
+ if p2cread:
+ os.close(p2cread)
+ if c2pwrite and c2pwrite not in (p2cread,):
+ os.close(c2pwrite)
+ if errwrite and errwrite not in (p2cread, c2pwrite):
+ os.close(errwrite)
+
+ # Close all other fds, if asked for
+ if close_fds:
+ self._close_fds(but=errpipe_write)
+
+ if cwd != None:
+ os.chdir(cwd)
+
+ if preexec_fn:
+ apply(preexec_fn)
+
+ if env == None:
+ os.execvp(executable, args)
+ else:
+ os.execvpe(executable, args, env)
+
+ except:
+ exc_type, exc_value, tb = sys.exc_info()
+ # Save the traceback and attach it to the exception object
+ exc_lines = traceback.format_exception(exc_type,
+ exc_value,
+ tb)
+ exc_value.child_traceback = ''.join(exc_lines)
+ os.write(errpipe_write, pickle.dumps(exc_value))
+
+ # This exitcode won't be reported to applications, so it
+ # really doesn't matter what we return.
+ os._exit(255)
+
+ # Parent
+ os.close(errpipe_write)
+ if p2cread and p2cwrite:
+ os.close(p2cread)
+ if c2pwrite and c2pread:
+ os.close(c2pwrite)
+ if errwrite and errread:
+ os.close(errwrite)
+
+ # Wait for exec to fail or succeed; possibly raising exception
+ data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
+ os.close(errpipe_read)
+ if data != "":
+ os.waitpid(self.pid, 0)
+ child_exception = pickle.loads(data)
+ raise child_exception
+
+
+ def _handle_exitstatus(self, sts):
+ if os.WIFSIGNALED(sts):
+ self.returncode = -os.WTERMSIG(sts)
+ elif os.WIFEXITED(sts):
+ self.returncode = os.WEXITSTATUS(sts)
+ else:
+ # Should never happen
+ raise RuntimeError("Unknown child exit status!")
+
+ _active.remove(self)
+
+
+ def poll(self):
+ """Check if child process has terminated. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ try:
+ pid, sts = os.waitpid(self.pid, os.WNOHANG)
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ except os.error:
+ pass
+ return self.returncode
+
+
+ def wait(self):
+ """Wait for child process to terminate. Returns returncode
+ attribute."""
+ if self.returncode == None:
+ pid, sts = os.waitpid(self.pid, 0)
+ self._handle_exitstatus(sts)
+ return self.returncode
+
+
+ def communicate(self, input=None):
+ """Interact with process: Send data to stdin. Read data from
+ stdout and stderr, until end-of-file is reached. Wait for
+ process to terminate. The optional input argument should be a
+ string to be sent to the child process, or None, if no data
+ should be sent to the child.
+
+ communicate() returns a tuple (stdout, stderr)."""
+ read_set = []
+ write_set = []
+ stdout = None # Return
+ stderr = None # Return
+
+ if self.stdin:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ self.stdin.flush()
+ if input:
+ write_set.append(self.stdin)
+ else:
+ self.stdin.close()
+ if self.stdout:
+ read_set.append(self.stdout)
+ stdout = []
+ if self.stderr:
+ read_set.append(self.stderr)
+ stderr = []
+
+ while read_set or write_set:
+ rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+ if self.stdin in wlist:
+ # When select has indicated that the file is writable,
+ # we can write up to PIPE_BUF bytes without risk
+ # blocking. POSIX defines PIPE_BUF >= 512
+ bytes_written = os.write(self.stdin.fileno(), input[:512])
+ input = input[bytes_written:]
+ if not input:
+ self.stdin.close()
+ write_set.remove(self.stdin)
+
+ if self.stdout in rlist:
+ data = os.read(self.stdout.fileno(), 1024)
+ if data == "":
+ self.stdout.close()
+ read_set.remove(self.stdout)
+ stdout.append(data)
+
+ if self.stderr in rlist:
+ data = os.read(self.stderr.fileno(), 1024)
+ if data == "":
+ self.stderr.close()
+ read_set.remove(self.stderr)
+ stderr.append(data)
+
+ # All data exchanged. Translate lists into strings.
+ if stdout != None:
+ stdout = ''.join(stdout)
+ if stderr != None:
+ stderr = ''.join(stderr)
+
+ # Translate newlines, if requested. We cannot let the file
+ # object do the translation: It is based on stdio, which is
+ # impossible to combine with select (unless forcing no
+ # buffering).
+ if self.universal_newlines and hasattr(open, 'newlines'):
+ if stdout:
+ stdout = self._translate_newlines(stdout)
+ if stderr:
+ stderr = self._translate_newlines(stderr)
+
+ self.wait()
+ return (stdout, stderr)
+
+
+def _demo_posix():
+ #
+ # Example 1: Simple redirection: Get process list
+ #
+ plist = Popen(["ps"], stdout=PIPE).communicate()[0]
+ print "Process list:"
+ print plist
+
+ #
+ # Example 2: Change uid before executing child
+ #
+ if os.getuid() == 0:
+ p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
+ p.wait()
+
+ #
+ # Example 3: Connecting several subprocesses
+ #
+ print "Looking for 'hda'..."
+ p1 = Popen(["dmesg"], stdout=PIPE)
+ p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+ print repr(p2.communicate()[0])
+
+ #
+ # Example 4: Catch execution error
+ #
+ print
+ print "Trying a weird file..."
+ try:
+ print Popen(["/this/path/does/not/exist"]).communicate()
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ print "The file didn't exist. I thought so..."
+ print "Child traceback:"
+ print e.child_traceback
+ else:
+ print "Error", e.errno
+ else:
+ print >>sys.stderr, "Gosh. No error."
+
+
+def _demo_windows():
+ #
+ # Example 1: Connecting several subprocesses
+ #
+ print "Looking for 'PROMPT' in set output..."
+ p1 = Popen("set", stdout=PIPE, shell=True)
+ p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
+ print repr(p2.communicate()[0])
+
+ #
+ # Example 2: Simple execution of program
+ #
+ print "Executing calc..."
+ p = Popen("calc")
+ p.wait()
+
+
+if __name__ == "__main__":
+ if mswindows:
+ _demo_windows()
+ else:
+ _demo_posix()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/uuid.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/uuid.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/util/uuid.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,240 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""UUID (universally unique identifiers) as specified in RFC 4122.
+
+This module provides the UUID class and the functions uuid1(), uuid3(),
+uuid4(), uuid5() for generating version 1, 3, 4, and 5 UUIDs respectively.
+
+This module works with Python 2.3 or higher."""
+
+__author__ = 'Ka-Ping Yee <ping at zesty.ca>'
+__date__ = '$Date: 2005/11/30 11:51:58 $'.split()[1].replace('/', '-')
+__version__ = '$Revision: 1.10 $'
+
+RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
+ 'reserved for NCS compatibility', 'specified in RFC 4122',
+ 'reserved for Microsoft compatibility', 'reserved for future definition']
+
+class UUID(object):
+ """Instances of the UUID class represent UUIDs as specified in RFC 4122.
+ Converting a UUID to a string using str() produces a string in the form
+ "{12345678-1234-1234-1234-123456789abc}". The UUID constructor accepts
+ a similar string (braces and hyphens optional), or six integer arguments
+ (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and 48-bit values
+ respectively). UUID objects have the following attributes:
+
+ bytes gets or sets the UUID as a 16-byte string
+
+ urn gets the UUID as a URN as specified in RFC 4122
+
+ variant gets or sets the UUID variant as one of the constants
+ RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE
+
+ version gets or sets the UUID version number (1 through 5)
+ """
+
+ def __init__(self, *args):
+ """Create a UUID either from a string representation in hexadecimal
+ or from six integers (32-bit time_low, 16-bit time_mid, 16-bit
+ time_hi_ver, 8-bit clock_hi_res, 8-bit clock_low, 48-bit node)."""
+ if len(args) == 1:
+ digits = args[0].replace('urn:', '').replace('uuid:', '')
+ digits = digits.replace('{', '').replace('}', '').replace('-', '')
+ assert len(digits) == 32, ValueError('badly formed UUID string')
+ time_low = int(digits[:8], 16)
+ time_mid = int(digits[8:12], 16)
+ time_hi_ver = int(digits[12:16], 16)
+ clock_hi_res = int(digits[16:18], 16)
+ clock_low = int(digits[18:20], 16)
+ node = int(digits[20:32], 16)
+ else:
+ (time_low, time_mid, time_hi_ver,
+ clock_hi_res, clock_low, node) = args
+ assert 0 <= time_low < 0x100000000, ValueError('time_low out of range')
+ assert 0 <= time_mid < 1<<16, ValueError('time_mid out of range')
+ assert 0 <= time_hi_ver < 1<<16, ValueError('time_hi_ver out of range')
+ assert 0 <= clock_hi_res < 1<<8, ValueError('clock_hi_res out of range')
+ assert 0 <= clock_low < 1<<8, ValueError('clock_low out of range')
+ assert 0 <= node < 0x1000000000000, ValueError('node out of range')
+ self.time_low = time_low
+ self.time_mid = time_mid
+ self.time_hi_ver = time_hi_ver
+ self.clock_hi_res = clock_hi_res
+ self.clock_low = clock_low
+ self.node = node
+
+ def __cmp__(self, other):
+ return cmp(self.bytes, getattr(other, 'bytes', other))
+
+ def __str__(self):
+ return '{%08x-%04x-%04x-%02x%02x-%012x}' % (
+ self.time_low, self.time_mid, self.time_hi_ver,
+ self.clock_hi_res, self.clock_low, self.node)
+
+ def __repr__(self):
+ return 'UUID(%r)' % str(self)
+
+ def get_bytes(self):
+ def byte(n):
+ return chr(n & 0xff)
+
+ return (byte(self.time_low >> 24) + byte(self.time_low >> 16) +
+ byte(self.time_low >> 8) + byte(self.time_low) +
+ byte(self.time_mid >> 8) + byte(self.time_mid) +
+ byte(self.time_hi_ver >> 8) + byte(self.time_hi_ver) +
+ byte(self.clock_hi_res) + byte(self.clock_low) +
+ byte(self.node >> 40) + byte(self.node >> 32) +
+ byte(self.node >> 24) + byte(self.node >> 16) +
+ byte(self.node >> 8) + byte(self.node))
+
+ def set_bytes(self, bytes):
+ values = map(ord, bytes)
+ self.time_low = ((values[0] << 24) + (values[1] << 16) +
+ (values[2] << 8) + values[3])
+ self.time_mid = (values[4] << 8) + values[5]
+ self.time_hi_ver = (values[6] << 8) + values[7]
+ self.clock_hi_res = values[8]
+ self.clock_low = values[9]
+ self.node = ((values[10] << 40) + (values[11] << 32) +
+ (values[12] << 24) + (values[13] << 16) +
+ (values[14] << 8) + values[15])
+
+ bytes = property(get_bytes, set_bytes)
+
+ def get_urn(self):
+ return 'urn:uuid:%08x-%04x-%04x-%02x%02x-%012x' % (
+ self.time_low, self.time_mid, self.time_hi_ver,
+ self.clock_hi_res, self.clock_low, self.node)
+
+ urn = property(get_urn)
+
+ def get_variant(self):
+ if not self.clock_hi_res & 0x80:
+ return RESERVED_NCS
+ elif not self.clock_hi_res & 0x40:
+ return RFC_4122
+ elif not self.clock_hi_res & 0x20:
+ return RESERVED_MICROSOFT
+ else:
+ return RESERVED_FUTURE
+
+ def set_variant(self, variant):
+ if variant == RESERVED_NCS:
+ self.clock_hi_res &= 0x7f
+ elif variant == RFC_4122:
+ self.clock_hi_res &= 0x3f
+ self.clock_hi_res |= 0x80
+ elif variant == RESERVED_MICROSOFT:
+ self.clock_hi_res &= 0x1f
+ self.clock_hi_res |= 0xc0
+ elif variant == RESERVED_FUTURE:
+ self.clock_hi_res &= 0x1f
+ self.clock_hi_res |= 0xe0
+ else:
+ raise ValueError('illegal variant identifier')
+
+ variant = property(get_variant, set_variant)
+
+ def get_version(self):
+ return self.time_hi_ver >> 12
+
+ def set_version(self, version):
+ assert 1 <= version <= 5, ValueError('illegal version number')
+ self.time_hi_ver &= 0x0fff
+ self.time_hi_ver |= (version << 12)
+
+ version = property(get_version, set_version)
+
+def unixgetaddr(program):
+ """Get the hardware address on a Unix machine."""
+ from os import popen
+ for line in popen(program):
+ words = line.lower().split()
+ if 'hwaddr' in words:
+ addr = words[words.index('hwaddr') + 1]
+ return int(addr.replace(':', ''), 16)
+ if 'ether' in words:
+ addr = words[words.index('ether') + 1]
+ return int(addr.replace(':', ''), 16)
+
+def wingetaddr(program):
+ """Get the hardware address on a Windows machine."""
+ from os import popen
+ for line in popen(program + ' /all'):
+ if line.strip().lower().startswith('physical address'):
+ addr = line.split(':')[-1].strip()
+ return int(addr.replace('-', ''), 16)
+
+def getaddr():
+ """Get the hardware address as a 48-bit integer."""
+ from os.path import join, isfile
+ for dir in ['/sbin', '/usr/sbin', r'c:\windows',
+ r'c:\windows\system', r'c:\windows\system32']:
+ if isfile(join(dir, 'ifconfig')):
+ return unixgetaddr(join(dir, 'ifconfig'))
+ if isfile(join(dir, 'ipconfig.exe')):
+ return wingetaddr(join(dir, 'ipconfig.exe'))
+
+def uuid1():
+ """Generate a UUID based on the time and hardware address."""
+ from time import time
+ from random import randrange
+ nanoseconds = int(time() * 1e9)
+ # 0x01b21dd213814000 is the number of 100-ns intervals between the
+ # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
+ timestamp = int(nanoseconds/100) + 0x01b21dd213814000
+ clock = randrange(1<<16) # don't use stable storage
+ time_low = timestamp & (0x100000000 - 1)
+ time_mid = (timestamp >> 32) & 0xffff
+ time_hi_ver = (timestamp >> 48) & 0x0fff
+ clock_low = clock & 0xff
+ clock_hi_res = (clock >> 8) & 0x3f
+ node = getaddr()
+ uuid = UUID(time_low, time_mid, time_hi_ver, clock_low, clock_hi_res, node)
+ uuid.variant = RFC_4122
+ uuid.version = 1
+ return uuid
+
+def uuid3(namespace, name):
+ """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
+ try:
+ from hashlib import md5
+ except ImportError:
+ from md5 import md5
+ uuid = UUID(0, 0, 0, 0, 0, 0)
+ uuid.bytes = md5(namespace.bytes + name).digest()[:16]
+ uuid.variant = RFC_4122
+ uuid.version = 3
+ return uuid
+
+def uuid4():
+ """Generate a random UUID."""
+ try:
+ from os import urandom
+ except:
+ from random import randrange
+ uuid = UUID(randrange(1<<32L), randrange(1<<16), randrange(1<<16),
+ randrange(1<<8), randrange(1<<8), randrange(1<<48L))
+ else:
+ uuid = UUID(0, 0, 0, 0, 0, 0)
+ uuid.bytes = urandom(16)
+ uuid.variant = RFC_4122
+ uuid.version = 4
+ return uuid
+
+def uuid5(namespace, name):
+ """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
+ try:
+ from hashlib import sha1
+ except ImportError:
+ from sha import sha as sha1
+ uuid = UUID(0, 0, 0, 0, 0, 0)
+ uuid.bytes = sha1(namespace.bytes + name).digest()[:16]
+ uuid.variant = RFC_4122
+ uuid.version = 5
+ return uuid
+
+NAMESPACE_DNS = UUID('{6ba7b810-9dad-11d1-80b4-00c04fd430c8}')
+NAMESPACE_URL = UUID('{6ba7b811-9dad-11d1-80b4-00c04fd430c8}')
+NAMESPACE_OID = UUID('{6ba7b812-9dad-11d1-80b4-00c04fd430c8}')
+NAMESPACE_X500 = UUID('{6ba7b814-9dad-11d1-80b4-00c04fd430c8}')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1783 @@
+"""A high-speed, production ready, thread pooled, generic WSGI server.
+
+Simplest example on how to use this module directly
+(without using CherryPy's application machinery):
+
+ from cherrypy import wsgiserver
+
+ def my_crazy_app(environ, start_response):
+ status = '200 OK'
+ response_headers = [('Content-type','text/plain')]
+ start_response(status, response_headers)
+ return ['Hello world!\n']
+
+ server = wsgiserver.CherryPyWSGIServer(
+ ('0.0.0.0', 8070), my_crazy_app,
+ server_name='www.cherrypy.example')
+
+The CherryPy WSGI server can serve as many WSGI applications
+as you want in one instance by using a WSGIPathInfoDispatcher:
+
+ d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
+ server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
+
+Want SSL support? Just set these attributes:
+
+ server.ssl_certificate = <filename>
+ server.ssl_private_key = <filename>
+
+ if __name__ == '__main__':
+ try:
+ server.start()
+ except KeyboardInterrupt:
+ server.stop()
+
+This won't call the CherryPy engine (application side) at all, only the
+WSGI server, which is independant from the rest of CherryPy. Don't
+let the name "CherryPyWSGIServer" throw you; the name merely reflects
+its origin, not its coupling.
+
+For those of you wanting to understand internals of this module, here's the
+basic call flow. The server's listening thread runs a very tight loop,
+sticking incoming connections onto a Queue:
+
+ server = CherryPyWSGIServer(...)
+ server.start()
+ while True:
+ tick()
+ # This blocks until a request comes in:
+ child = socket.accept()
+ conn = HTTPConnection(child, ...)
+ server.requests.put(conn)
+
+Worker threads are kept in a pool and poll the Queue, popping off and then
+handling each connection in turn. Each connection can consist of an arbitrary
+number of requests and their responses, so we run a nested loop:
+
+ while True:
+ conn = server.requests.get()
+ conn.communicate()
+ -> while True:
+ req = HTTPRequest(...)
+ req.parse_request()
+ -> # Read the Request-Line, e.g. "GET /page HTTP/1.1"
+ req.rfile.readline()
+ req.read_headers()
+ req.respond()
+ -> response = wsgi_app(...)
+ try:
+ for chunk in response:
+ if chunk:
+ req.write(chunk)
+ finally:
+ if hasattr(response, "close"):
+ response.close()
+ if req.close_connection:
+ return
+"""
+
+
+import base64
+import os
+import Queue
+import re
+quoted_slash = re.compile("(?i)%2F")
+import rfc822
+import socket
+try:
+ import cStringIO as StringIO
+except ImportError:
+ import StringIO
+
+_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
+
+import sys
+import threading
+import time
+import traceback
+from urllib import unquote
+from urlparse import urlparse
+import warnings
+
+try:
+ from OpenSSL import SSL
+ from OpenSSL import crypto
+except ImportError:
+ SSL = None
+
+import errno
+
+def plat_specific_errors(*errnames):
+ """Return error numbers for all errors in errnames on this platform.
+
+ The 'errno' module contains different global constants depending on
+ the specific platform (OS). This function will return the list of
+ numeric values for a given list of potential names.
+ """
+ errno_names = dir(errno)
+ nums = [getattr(errno, k) for k in errnames if k in errno_names]
+ # de-dupe the list
+ return dict.fromkeys(nums).keys()
+
+socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
+
+socket_errors_to_ignore = plat_specific_errors(
+ "EPIPE",
+ "EBADF", "WSAEBADF",
+ "ENOTSOCK", "WSAENOTSOCK",
+ "ETIMEDOUT", "WSAETIMEDOUT",
+ "ECONNREFUSED", "WSAECONNREFUSED",
+ "ECONNRESET", "WSAECONNRESET",
+ "ECONNABORTED", "WSAECONNABORTED",
+ "ENETRESET", "WSAENETRESET",
+ "EHOSTDOWN", "EHOSTUNREACH",
+ )
+socket_errors_to_ignore.append("timed out")
+
+socket_errors_nonblocking = plat_specific_errors(
+ 'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
+
+comma_separated_headers = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
+ 'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
+ 'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
+ 'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
+ 'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
+ 'WWW-AUTHENTICATE']
+
+
+class WSGIPathInfoDispatcher(object):
+ """A WSGI dispatcher for dispatch based on the PATH_INFO.
+
+ apps: a dict or list of (path_prefix, app) pairs.
+ """
+
+ def __init__(self, apps):
+ try:
+ apps = apps.items()
+ except AttributeError:
+ pass
+
+ # Sort the apps by len(path), descending
+ apps.sort()
+ apps.reverse()
+
+ # The path_prefix strings must start, but not end, with a slash.
+ # Use "" instead of "/".
+ self.apps = [(p.rstrip("/"), a) for p, a in apps]
+
+ def __call__(self, environ, start_response):
+ path = environ["PATH_INFO"] or "/"
+ for p, app in self.apps:
+ # The apps list should be sorted by length, descending.
+ if path.startswith(p + "/") or path == p:
+ environ = environ.copy()
+ environ["SCRIPT_NAME"] = environ["SCRIPT_NAME"] + p
+ environ["PATH_INFO"] = path[len(p):]
+ return app(environ, start_response)
+
+ start_response('404 Not Found', [('Content-Type', 'text/plain'),
+ ('Content-Length', '0')])
+ return ['']
+
+
+class MaxSizeExceeded(Exception):
+ pass
+
+class SizeCheckWrapper(object):
+ """Wraps a file-like object, raising MaxSizeExceeded if too large."""
+
+ def __init__(self, rfile, maxlen):
+ self.rfile = rfile
+ self.maxlen = maxlen
+ self.bytes_read = 0
+
+ def _check_length(self):
+ if self.maxlen and self.bytes_read > self.maxlen:
+ raise MaxSizeExceeded()
+
+ def read(self, size=None):
+ data = self.rfile.read(size)
+ self.bytes_read += len(data)
+ self._check_length()
+ return data
+
+ def readline(self, size=None):
+ if size is not None:
+ data = self.rfile.readline(size)
+ self.bytes_read += len(data)
+ self._check_length()
+ return data
+
+ # User didn't specify a size ...
+ # We read the line in chunks to make sure it's not a 100MB line !
+ res = []
+ while True:
+ data = self.rfile.readline(256)
+ self.bytes_read += len(data)
+ self._check_length()
+ res.append(data)
+ # See http://www.cherrypy.org/ticket/421
+ if len(data) < 256 or data[-1:] == "\n":
+ return ''.join(res)
+
+ def readlines(self, sizehint=0):
+ # Shamelessly stolen from StringIO
+ total = 0
+ lines = []
+ line = self.readline()
+ while line:
+ lines.append(line)
+ total += len(line)
+ if 0 < sizehint <= total:
+ break
+ line = self.readline()
+ return lines
+
+ def close(self):
+ self.rfile.close()
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ data = self.rfile.next()
+ self.bytes_read += len(data)
+ self._check_length()
+ return data
+
+
+class HTTPRequest(object):
+ """An HTTP Request (and response).
+
+ A single HTTP connection may consist of multiple request/response pairs.
+
+ send: the 'send' method from the connection's socket object.
+ wsgi_app: the WSGI application to call.
+ environ: a partial WSGI environ (server and connection entries).
+ The caller MUST set the following entries:
+ * All wsgi.* entries, including .input
+ * SERVER_NAME and SERVER_PORT
+ * Any SSL_* entries
+ * Any custom entries like REMOTE_ADDR and REMOTE_PORT
+ * SERVER_SOFTWARE: the value to write in the "Server" response header.
+ * ACTUAL_SERVER_PROTOCOL: the value to write in the Status-Line of
+ the response. From RFC 2145: "An HTTP server SHOULD send a
+ response version equal to the highest version for which the
+ server is at least conditionally compliant, and whose major
+ version is less than or equal to the one received in the
+ request. An HTTP server MUST NOT send a version for which
+ it is not at least conditionally compliant."
+
+ outheaders: a list of header tuples to write in the response.
+ ready: when True, the request has been parsed and is ready to begin
+ generating the response. When False, signals the calling Connection
+ that the response should not be generated and the connection should
+ close.
+ close_connection: signals the calling Connection that the request
+ should close. This does not imply an error! The client and/or
+ server may each request that the connection be closed.
+ chunked_write: if True, output will be encoded with the "chunked"
+ transfer-coding. This value is set automatically inside
+ send_headers.
+ """
+
+ max_request_header_size = 0
+ max_request_body_size = 0
+
+ def __init__(self, wfile, environ, wsgi_app):
+ self.rfile = environ['wsgi.input']
+ self.wfile = wfile
+ self.environ = environ.copy()
+ self.wsgi_app = wsgi_app
+
+ self.ready = False
+ self.started_response = False
+ self.status = ""
+ self.outheaders = []
+ self.sent_headers = False
+ self.close_connection = False
+ self.chunked_write = False
+
+ def parse_request(self):
+ """Parse the next HTTP request start-line and message-headers."""
+ self.rfile.maxlen = self.max_request_header_size
+ self.rfile.bytes_read = 0
+
+ try:
+ self._parse_request()
+ except MaxSizeExceeded:
+ self.simple_response("413 Request Entity Too Large")
+ return
+
+ def _parse_request(self):
+ # HTTP/1.1 connections are persistent by default. If a client
+ # requests a page, then idles (leaves the connection open),
+ # then rfile.readline() will raise socket.error("timed out").
+ # Note that it does this based on the value given to settimeout(),
+ # and doesn't need the client to request or acknowledge the close
+ # (although your TCP stack might suffer for it: cf Apache's history
+ # with FIN_WAIT_2).
+ request_line = self.rfile.readline()
+ if not request_line:
+ # Force self.ready = False so the connection will close.
+ self.ready = False
+ return
+
+ if request_line == "\r\n":
+ # RFC 2616 sec 4.1: "...if the server is reading the protocol
+ # stream at the beginning of a message and receives a CRLF
+ # first, it should ignore the CRLF."
+ # But only ignore one leading line! else we enable a DoS.
+ request_line = self.rfile.readline()
+ if not request_line:
+ self.ready = False
+ return
+
+ environ = self.environ
+
+ try:
+ method, path, req_protocol = request_line.strip().split(" ", 2)
+ except ValueError:
+ self.simple_response(400, "Malformed Request-Line")
+ return
+
+ environ["REQUEST_METHOD"] = method
+
+ # path may be an abs_path (including "http://host.domain.tld");
+ scheme, location, path, params, qs, frag = urlparse(path)
+
+ if frag:
+ self.simple_response("400 Bad Request",
+ "Illegal #fragment in Request-URI.")
+ return
+
+ if scheme:
+ environ["wsgi.url_scheme"] = scheme
+ if params:
+ path = path + ";" + params
+
+ environ["SCRIPT_NAME"] = ""
+
+ # Unquote the path+params (e.g. "/this%20path" -> "this path").
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
+ #
+ # But note that "...a URI must be separated into its components
+ # before the escaped characters within those components can be
+ # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
+ atoms = [unquote(x) for x in quoted_slash.split(path)]
+ path = "%2F".join(atoms)
+ environ["PATH_INFO"] = path
+
+ # Note that, like wsgiref and most other WSGI servers,
+ # we unquote the path but not the query string.
+ environ["QUERY_STRING"] = qs
+
+ # Compare request and server HTTP protocol versions, in case our
+ # server does not support the requested protocol. Limit our output
+ # to min(req, server). We want the following output:
+ # request server actual written supported response
+ # protocol protocol response protocol feature set
+ # a 1.0 1.0 1.0 1.0
+ # b 1.0 1.1 1.1 1.0
+ # c 1.1 1.0 1.0 1.0
+ # d 1.1 1.1 1.1 1.1
+ # Notice that, in (b), the response will be "HTTP/1.1" even though
+ # the client only understands 1.0. RFC 2616 10.5.6 says we should
+ # only return 505 if the _major_ version is different.
+ rp = int(req_protocol[5]), int(req_protocol[7])
+ server_protocol = environ["ACTUAL_SERVER_PROTOCOL"]
+ sp = int(server_protocol[5]), int(server_protocol[7])
+ if sp[0] != rp[0]:
+ self.simple_response("505 HTTP Version Not Supported")
+ return
+ # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
+ environ["SERVER_PROTOCOL"] = req_protocol
+ self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
+
+ # If the Request-URI was an absoluteURI, use its location atom.
+ if location:
+ environ["SERVER_NAME"] = location
+
+ # then all the http headers
+ try:
+ self.read_headers()
+ except ValueError, ex:
+ self.simple_response("400 Bad Request", repr(ex.args))
+ return
+
+ mrbs = self.max_request_body_size
+ if mrbs and int(environ.get("CONTENT_LENGTH", 0)) > mrbs:
+ self.simple_response("413 Request Entity Too Large")
+ return
+
+ # Persistent connection support
+ if self.response_protocol == "HTTP/1.1":
+ # Both server and client are HTTP/1.1
+ if environ.get("HTTP_CONNECTION", "") == "close":
+ self.close_connection = True
+ else:
+ # Either the server or client (or both) are HTTP/1.0
+ if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
+ self.close_connection = True
+
+ # Transfer-Encoding support
+ te = None
+ if self.response_protocol == "HTTP/1.1":
+ te = environ.get("HTTP_TRANSFER_ENCODING")
+ if te:
+ te = [x.strip().lower() for x in te.split(",") if x.strip()]
+
+ self.chunked_read = False
+
+ if te:
+ for enc in te:
+ if enc == "chunked":
+ self.chunked_read = True
+ else:
+ # Note that, even if we see "chunked", we must reject
+ # if there is an extension we don't recognize.
+ self.simple_response("501 Unimplemented")
+ self.close_connection = True
+ return
+
+ # From PEP 333:
+ # "Servers and gateways that implement HTTP 1.1 must provide
+ # transparent support for HTTP 1.1's "expect/continue" mechanism.
+ # This may be done in any of several ways:
+ # 1. Respond to requests containing an Expect: 100-continue request
+ # with an immediate "100 Continue" response, and proceed normally.
+ # 2. Proceed with the request normally, but provide the application
+ # with a wsgi.input stream that will send the "100 Continue"
+ # response if/when the application first attempts to read from
+ # the input stream. The read request must then remain blocked
+ # until the client responds.
+ # 3. Wait until the client decides that the server does not support
+ # expect/continue, and sends the request body on its own.
+ # (This is suboptimal, and is not recommended.)
+ #
+ # We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
+ # but it seems like it would be a big slowdown for such a rare case.
+ if environ.get("HTTP_EXPECT", "") == "100-continue":
+ self.simple_response(100)
+
+ self.ready = True
+
+ def read_headers(self):
+ """Read header lines from the incoming stream."""
+ environ = self.environ
+
+ while True:
+ line = self.rfile.readline()
+ if not line:
+ # No more data--illegal end of headers
+ raise ValueError("Illegal end of headers.")
+
+ if line == '\r\n':
+ # Normal end of headers
+ break
+
+ if line[0] in ' \t':
+ # It's a continuation line.
+ v = line.strip()
+ else:
+ k, v = line.split(":", 1)
+ k, v = k.strip().upper(), v.strip()
+ envname = "HTTP_" + k.replace("-", "_")
+
+ if k in comma_separated_headers:
+ existing = environ.get(envname)
+ if existing:
+ v = ", ".join((existing, v))
+ environ[envname] = v
+
+ ct = environ.pop("HTTP_CONTENT_TYPE", None)
+ if ct is not None:
+ environ["CONTENT_TYPE"] = ct
+ cl = environ.pop("HTTP_CONTENT_LENGTH", None)
+ if cl is not None:
+ environ["CONTENT_LENGTH"] = cl
+
+ def decode_chunked(self):
+ """Decode the 'chunked' transfer coding."""
+ cl = 0
+ data = StringIO.StringIO()
+ while True:
+ line = self.rfile.readline().strip().split(";", 1)
+ chunk_size = int(line.pop(0), 16)
+ if chunk_size <= 0:
+ break
+## if line: chunk_extension = line[0]
+ cl += chunk_size
+ data.write(self.rfile.read(chunk_size))
+ crlf = self.rfile.read(2)
+ if crlf != "\r\n":
+ self.simple_response("400 Bad Request",
+ "Bad chunked transfer coding "
+ "(expected '\\r\\n', got %r)" % crlf)
+ return
+
+ # Grab any trailer headers
+ self.read_headers()
+
+ data.seek(0)
+ self.environ["wsgi.input"] = data
+ self.environ["CONTENT_LENGTH"] = str(cl) or ""
+ return True
+
+ def respond(self):
+ """Call the appropriate WSGI app and write its iterable output."""
+ # Set rfile.maxlen to ensure we don't read past Content-Length.
+ # This will also be used to read the entire request body if errors
+ # are raised before the app can read the body.
+ if self.chunked_read:
+ # If chunked, Content-Length will be 0.
+ self.rfile.maxlen = self.max_request_body_size
+ else:
+ cl = int(self.environ.get("CONTENT_LENGTH", 0))
+ if self.max_request_body_size:
+ self.rfile.maxlen = min(cl, self.max_request_body_size)
+ else:
+ self.rfile.maxlen = cl
+ self.rfile.bytes_read = 0
+
+ try:
+ self._respond()
+ except MaxSizeExceeded:
+ if not self.sent_headers:
+ self.simple_response("413 Request Entity Too Large")
+ return
+
+ def _respond(self):
+ if self.chunked_read:
+ if not self.decode_chunked():
+ self.close_connection = True
+ return
+
+ response = self.wsgi_app(self.environ, self.start_response)
+ try:
+ for chunk in response:
+ # "The start_response callable must not actually transmit
+ # the response headers. Instead, it must store them for the
+ # server or gateway to transmit only after the first
+ # iteration of the application return value that yields
+ # a NON-EMPTY string, or upon the application's first
+ # invocation of the write() callable." (PEP 333)
+ if chunk:
+ self.write(chunk)
+ finally:
+ if hasattr(response, "close"):
+ response.close()
+
+ if (self.ready and not self.sent_headers):
+ self.sent_headers = True
+ self.send_headers()
+ if self.chunked_write:
+ self.wfile.sendall("0\r\n\r\n")
+
+ def simple_response(self, status, msg=""):
+ """Write a simple response back to the client."""
+ status = str(status)
+ buf = ["%s %s\r\n" % (self.environ['ACTUAL_SERVER_PROTOCOL'], status),
+ "Content-Length: %s\r\n" % len(msg),
+ "Content-Type: text/plain\r\n"]
+
+ if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
+ # Request Entity Too Large
+ self.close_connection = True
+ buf.append("Connection: close\r\n")
+
+ buf.append("\r\n")
+ if msg:
+ buf.append(msg)
+
+ try:
+ self.wfile.sendall("".join(buf))
+ except socket.error, x:
+ if x.args[0] not in socket_errors_to_ignore:
+ raise
+
+ def start_response(self, status, headers, exc_info = None):
+ """WSGI callable to begin the HTTP response."""
+ # "The application may call start_response more than once,
+ # if and only if the exc_info argument is provided."
+ if self.started_response and not exc_info:
+ raise AssertionError("WSGI start_response called a second "
+ "time with no exc_info.")
+
+ # "if exc_info is provided, and the HTTP headers have already been
+ # sent, start_response must raise an error, and should raise the
+ # exc_info tuple."
+ if self.sent_headers:
+ try:
+ raise exc_info[0], exc_info[1], exc_info[2]
+ finally:
+ exc_info = None
+
+ self.started_response = True
+ self.status = status
+ self.outheaders.extend(headers)
+ return self.write
+
+ def write(self, chunk):
+ """WSGI callable to write unbuffered data to the client.
+
+ This method is also used internally by start_response (to write
+ data from the iterable returned by the WSGI application).
+ """
+ if not self.started_response:
+ raise AssertionError("WSGI write called before start_response.")
+
+ if not self.sent_headers:
+ self.sent_headers = True
+ self.send_headers()
+
+ if self.chunked_write and chunk:
+ buf = [hex(len(chunk))[2:], "\r\n", chunk, "\r\n"]
+ self.wfile.sendall("".join(buf))
+ else:
+ self.wfile.sendall(chunk)
+
+ def send_headers(self):
+ """Assert, process, and send the HTTP response message-headers."""
+ hkeys = [key.lower() for key, value in self.outheaders]
+ status = int(self.status[:3])
+
+ if status == 413:
+ # Request Entity Too Large. Close conn to avoid garbage.
+ self.close_connection = True
+ elif "content-length" not in hkeys:
+ # "All 1xx (informational), 204 (no content),
+ # and 304 (not modified) responses MUST NOT
+ # include a message-body." So no point chunking.
+ if status < 200 or status in (204, 205, 304):
+ pass
+ else:
+ if (self.response_protocol == 'HTTP/1.1'
+ and self.environ["REQUEST_METHOD"] != 'HEAD'):
+ # Use the chunked transfer-coding
+ self.chunked_write = True
+ self.outheaders.append(("Transfer-Encoding", "chunked"))
+ else:
+ # Closing the conn is the only way to determine len.
+ self.close_connection = True
+
+ if "connection" not in hkeys:
+ if self.response_protocol == 'HTTP/1.1':
+ # Both server and client are HTTP/1.1 or better
+ if self.close_connection:
+ self.outheaders.append(("Connection", "close"))
+ else:
+ # Server and/or client are HTTP/1.0
+ if not self.close_connection:
+ self.outheaders.append(("Connection", "Keep-Alive"))
+
+ if (not self.close_connection) and (not self.chunked_read):
+ # Read any remaining request body data on the socket.
+ # "If an origin server receives a request that does not include an
+ # Expect request-header field with the "100-continue" expectation,
+ # the request includes a request body, and the server responds
+ # with a final status code before reading the entire request body
+ # from the transport connection, then the server SHOULD NOT close
+ # the transport connection until it has read the entire request,
+ # or until the client closes the connection. Otherwise, the client
+ # might not reliably receive the response message. However, this
+ # requirement is not be construed as preventing a server from
+ # defending itself against denial-of-service attacks, or from
+ # badly broken client implementations."
+ size = self.rfile.maxlen - self.rfile.bytes_read
+ if size > 0:
+ self.rfile.read(size)
+
+ if "date" not in hkeys:
+ self.outheaders.append(("Date", rfc822.formatdate()))
+
+ if "server" not in hkeys:
+ self.outheaders.append(("Server", self.environ['SERVER_SOFTWARE']))
+
+ buf = [self.environ['ACTUAL_SERVER_PROTOCOL'], " ", self.status, "\r\n"]
+ try:
+ buf += [k + ": " + v + "\r\n" for k, v in self.outheaders]
+ except TypeError:
+ if not isinstance(k, str):
+ raise TypeError("WSGI response header key %r is not a string.")
+ if not isinstance(v, str):
+ raise TypeError("WSGI response header value %r is not a string.")
+ else:
+ raise
+ buf.append("\r\n")
+ self.wfile.sendall("".join(buf))
+
+
+class NoSSLError(Exception):
+ """Exception raised when a client speaks HTTP to an HTTPS socket."""
+ pass
+
+
+class FatalSSLAlert(Exception):
+ """Exception raised when the SSL implementation signals a fatal alert."""
+ pass
+
+
+if not _fileobject_uses_str_type:
+ class CP_fileobject(socket._fileobject):
+ """Faux file object attached to a socket object."""
+
+ def sendall(self, data):
+ """Sendall for non-blocking sockets."""
+ while data:
+ try:
+ bytes_sent = self.send(data)
+ data = data[bytes_sent:]
+ except socket.error, e:
+ if e.args[0] not in socket_errors_nonblocking:
+ raise
+
+ def send(self, data):
+ return self._sock.send(data)
+
+ def flush(self):
+ if self._wbuf:
+ buffer = "".join(self._wbuf)
+ self._wbuf = []
+ self.sendall(buffer)
+
+ def recv(self, size):
+ while True:
+ try:
+ return self._sock.recv(size)
+ except socket.error, e:
+ if (e.args[0] not in socket_errors_nonblocking
+ and e.args[0] not in socket_error_eintr):
+ raise
+
+ def read(self, size=-1):
+ # Use max, disallow tiny reads in a loop as they are very inefficient.
+ # We never leave read() with any leftover data from a new recv() call
+ # in our internal buffer.
+ rbufsize = max(self._rbufsize, self.default_bufsize)
+ # Our use of StringIO rather than lists of string objects returned by
+ # recv() minimizes memory usage and fragmentation that occurs when
+ # rbufsize is large compared to the typical return value of recv().
+ buf = self._rbuf
+ buf.seek(0, 2) # seek end
+ if size < 0:
+ # Read until EOF
+ self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
+ while True:
+ data = self.recv(rbufsize)
+ if not data:
+ break
+ buf.write(data)
+ return buf.getvalue()
+ else:
+ # Read until size bytes or EOF seen, whichever comes first
+ buf_len = buf.tell()
+ if buf_len >= size:
+ # Already have size bytes in our buffer? Extract and return.
+ buf.seek(0)
+ rv = buf.read(size)
+ self._rbuf = StringIO.StringIO()
+ self._rbuf.write(buf.read())
+ return rv
+
+ self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
+ while True:
+ left = size - buf_len
+ # recv() will malloc the amount of memory given as its
+ # parameter even though it often returns much less data
+ # than that. The returned data string is short lived
+ # as we copy it into a StringIO and free it. This avoids
+ # fragmentation issues on many platforms.
+ data = self.recv(left)
+ if not data:
+ break
+ n = len(data)
+ if n == size and not buf_len:
+ # Shortcut. Avoid buffer data copies when:
+ # - We have no data in our buffer.
+ # AND
+ # - Our call to recv returned exactly the
+ # number of bytes we were asked to read.
+ return data
+ if n == left:
+ buf.write(data)
+ del data # explicit free
+ break
+ assert n <= left, "recv(%d) returned %d bytes" % (left, n)
+ buf.write(data)
+ buf_len += n
+ del data # explicit free
+ #assert buf_len == buf.tell()
+ return buf.getvalue()
+
+ def readline(self, size=-1):
+ buf = self._rbuf
+ buf.seek(0, 2) # seek end
+ if buf.tell() > 0:
+ # check if we already have it in our buffer
+ buf.seek(0)
+ bline = buf.readline(size)
+ if bline.endswith('\n') or len(bline) == size:
+ self._rbuf = StringIO.StringIO()
+ self._rbuf.write(buf.read())
+ return bline
+ del bline
+ if size < 0:
+ # Read until \n or EOF, whichever comes first
+ if self._rbufsize <= 1:
+ # Speed up unbuffered case
+ buf.seek(0)
+ buffers = [buf.read()]
+ self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
+ data = None
+ recv = self.recv
+ while data != "\n":
+ data = recv(1)
+ if not data:
+ break
+ buffers.append(data)
+ return "".join(buffers)
+
+ buf.seek(0, 2) # seek end
+ self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
+ while True:
+ data = self.recv(self._rbufsize)
+ if not data:
+ break
+ nl = data.find('\n')
+ if nl >= 0:
+ nl += 1
+ buf.write(data[:nl])
+ self._rbuf.write(data[nl:])
+ del data
+ break
+ buf.write(data)
+ return buf.getvalue()
+ else:
+ # Read until size bytes or \n or EOF seen, whichever comes first
+ buf.seek(0, 2) # seek end
+ buf_len = buf.tell()
+ if buf_len >= size:
+ buf.seek(0)
+ rv = buf.read(size)
+ self._rbuf = StringIO.StringIO()
+ self._rbuf.write(buf.read())
+ return rv
+ self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
+ while True:
+ data = self.recv(self._rbufsize)
+ if not data:
+ break
+ left = size - buf_len
+ # did we just receive a newline?
+ nl = data.find('\n', 0, left)
+ if nl >= 0:
+ nl += 1
+ # save the excess data to _rbuf
+ self._rbuf.write(data[nl:])
+ if buf_len:
+ buf.write(data[:nl])
+ break
+ else:
+ # Shortcut. Avoid data copy through buf when returning
+ # a substring of our first recv().
+ return data[:nl]
+ n = len(data)
+ if n == size and not buf_len:
+ # Shortcut. Avoid data copy through buf when
+ # returning exactly all of our first recv().
+ return data
+ if n >= left:
+ buf.write(data[:left])
+ self._rbuf.write(data[left:])
+ break
+ buf.write(data)
+ buf_len += n
+ #assert buf_len == buf.tell()
+ return buf.getvalue()
+
+else:
+ class CP_fileobject(socket._fileobject):
+ """Faux file object attached to a socket object."""
+
+ def sendall(self, data):
+ """Sendall for non-blocking sockets."""
+ while data:
+ try:
+ bytes_sent = self.send(data)
+ data = data[bytes_sent:]
+ except socket.error, e:
+ if e.args[0] not in socket_errors_nonblocking:
+ raise
+
+ def send(self, data):
+ return self._sock.send(data)
+
+ def flush(self):
+ if self._wbuf:
+ buffer = "".join(self._wbuf)
+ self._wbuf = []
+ self.sendall(buffer)
+
+ def recv(self, size):
+ while True:
+ try:
+ return self._sock.recv(size)
+ except socket.error, e:
+ if (e.args[0] not in socket_errors_nonblocking
+ and e.args[0] not in socket_error_eintr):
+ raise
+
+ def read(self, size=-1):
+ if size < 0:
+ # Read until EOF
+ buffers = [self._rbuf]
+ self._rbuf = ""
+ if self._rbufsize <= 1:
+ recv_size = self.default_bufsize
+ else:
+ recv_size = self._rbufsize
+
+ while True:
+ data = self.recv(recv_size)
+ if not data:
+ break
+ buffers.append(data)
+ return "".join(buffers)
+ else:
+ # Read until size bytes or EOF seen, whichever comes first
+ data = self._rbuf
+ buf_len = len(data)
+ if buf_len >= size:
+ self._rbuf = data[size:]
+ return data[:size]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self._rbuf = ""
+ while True:
+ left = size - buf_len
+ recv_size = max(self._rbufsize, left)
+ data = self.recv(recv_size)
+ if not data:
+ break
+ buffers.append(data)
+ n = len(data)
+ if n >= left:
+ self._rbuf = data[left:]
+ buffers[-1] = data[:left]
+ break
+ buf_len += n
+ return "".join(buffers)
+
+ def readline(self, size=-1):
+ data = self._rbuf
+ if size < 0:
+ # Read until \n or EOF, whichever comes first
+ if self._rbufsize <= 1:
+ # Speed up unbuffered case
+ assert data == ""
+ buffers = []
+ while data != "\n":
+ data = self.recv(1)
+ if not data:
+ break
+ buffers.append(data)
+ return "".join(buffers)
+ nl = data.find('\n')
+ if nl >= 0:
+ nl += 1
+ self._rbuf = data[nl:]
+ return data[:nl]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self._rbuf = ""
+ while True:
+ data = self.recv(self._rbufsize)
+ if not data:
+ break
+ buffers.append(data)
+ nl = data.find('\n')
+ if nl >= 0:
+ nl += 1
+ self._rbuf = data[nl:]
+ buffers[-1] = data[:nl]
+ break
+ return "".join(buffers)
+ else:
+ # Read until size bytes or \n or EOF seen, whichever comes first
+ nl = data.find('\n', 0, size)
+ if nl >= 0:
+ nl += 1
+ self._rbuf = data[nl:]
+ return data[:nl]
+ buf_len = len(data)
+ if buf_len >= size:
+ self._rbuf = data[size:]
+ return data[:size]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self._rbuf = ""
+ while True:
+ data = self.recv(self._rbufsize)
+ if not data:
+ break
+ buffers.append(data)
+ left = size - buf_len
+ nl = data.find('\n', 0, left)
+ if nl >= 0:
+ nl += 1
+ self._rbuf = data[nl:]
+ buffers[-1] = data[:nl]
+ break
+ n = len(data)
+ if n >= left:
+ self._rbuf = data[left:]
+ buffers[-1] = data[:left]
+ break
+ buf_len += n
+ return "".join(buffers)
+
+
+class SSL_fileobject(CP_fileobject):
+ """SSL file object attached to a socket object."""
+
+ ssl_timeout = 3
+ ssl_retry = .01
+
+ def _safe_call(self, is_reader, call, *args, **kwargs):
+ """Wrap the given call with SSL error-trapping.
+
+ is_reader: if False EOF errors will be raised. If True, EOF errors
+ will return "" (to emulate normal sockets).
+ """
+ start = time.time()
+ while True:
+ try:
+ return call(*args, **kwargs)
+ except SSL.WantReadError:
+ # Sleep and try again. This is dangerous, because it means
+ # the rest of the stack has no way of differentiating
+ # between a "new handshake" error and "client dropped".
+ # Note this isn't an endless loop: there's a timeout below.
+ time.sleep(self.ssl_retry)
+ except SSL.WantWriteError:
+ time.sleep(self.ssl_retry)
+ except SSL.SysCallError, e:
+ if is_reader and e.args == (-1, 'Unexpected EOF'):
+ return ""
+
+ errnum = e.args[0]
+ if is_reader and errnum in socket_errors_to_ignore:
+ return ""
+ raise socket.error(errnum)
+ except SSL.Error, e:
+ if is_reader and e.args == (-1, 'Unexpected EOF'):
+ return ""
+
+ thirdarg = None
+ try:
+ thirdarg = e.args[0][0][2]
+ except IndexError:
+ pass
+
+ if thirdarg == 'http request':
+ # The client is talking HTTP to an HTTPS server.
+ raise NoSSLError()
+ raise FatalSSLAlert(*e.args)
+ except:
+ raise
+
+ if time.time() - start > self.ssl_timeout:
+ raise socket.timeout("timed out")
+
+ def recv(self, *args, **kwargs):
+ buf = []
+ r = super(SSL_fileobject, self).recv
+ while True:
+ data = self._safe_call(True, r, *args, **kwargs)
+ buf.append(data)
+ p = self._sock.pending()
+ if not p:
+ return "".join(buf)
+
+ def sendall(self, *args, **kwargs):
+ return self._safe_call(False, super(SSL_fileobject, self).sendall, *args, **kwargs)
+
+ def send(self, *args, **kwargs):
+ return self._safe_call(False, super(SSL_fileobject, self).send, *args, **kwargs)
+
+
+class HTTPConnection(object):
+ """An HTTP connection (active socket).
+
+ socket: the raw socket object (usually TCP) for this connection.
+ wsgi_app: the WSGI application for this server/connection.
+ environ: a WSGI environ template. This will be copied for each request.
+
+ rfile: a fileobject for reading from the socket.
+ send: a function for writing (+ flush) to the socket.
+ """
+
+ rbufsize = -1
+ RequestHandlerClass = HTTPRequest
+ environ = {"wsgi.version": (1, 0),
+ "wsgi.url_scheme": "http",
+ "wsgi.multithread": True,
+ "wsgi.multiprocess": False,
+ "wsgi.run_once": False,
+ "wsgi.errors": sys.stderr,
+ }
+
+ def __init__(self, sock, wsgi_app, environ):
+ self.socket = sock
+ self.wsgi_app = wsgi_app
+
+ # Copy the class environ into self.
+ self.environ = self.environ.copy()
+ self.environ.update(environ)
+
+ if SSL and isinstance(sock, SSL.ConnectionType):
+ timeout = sock.gettimeout()
+ self.rfile = SSL_fileobject(sock, "rb", self.rbufsize)
+ self.rfile.ssl_timeout = timeout
+ self.wfile = SSL_fileobject(sock, "wb", -1)
+ self.wfile.ssl_timeout = timeout
+ else:
+ self.rfile = CP_fileobject(sock, "rb", self.rbufsize)
+ self.wfile = CP_fileobject(sock, "wb", -1)
+
+ # Wrap wsgi.input but not HTTPConnection.rfile itself.
+ # We're also not setting maxlen yet; we'll do that separately
+ # for headers and body for each iteration of self.communicate
+ # (if maxlen is 0 the wrapper doesn't check length).
+ self.environ["wsgi.input"] = SizeCheckWrapper(self.rfile, 0)
+
+ def communicate(self):
+ """Read each request and respond appropriately."""
+ try:
+ while True:
+ # (re)set req to None so that if something goes wrong in
+ # the RequestHandlerClass constructor, the error doesn't
+ # get written to the previous request.
+ req = None
+ req = self.RequestHandlerClass(self.wfile, self.environ,
+ self.wsgi_app)
+
+ # This order of operations should guarantee correct pipelining.
+ req.parse_request()
+ if not req.ready:
+ return
+
+ req.respond()
+ if req.close_connection:
+ return
+
+ except socket.error, e:
+ errnum = e.args[0]
+ if errnum == 'timed out':
+ if req and not req.sent_headers:
+ req.simple_response("408 Request Timeout")
+ elif errnum not in socket_errors_to_ignore:
+ if req and not req.sent_headers:
+ req.simple_response("500 Internal Server Error",
+ format_exc())
+ return
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except FatalSSLAlert, e:
+ # Close the connection.
+ return
+ except NoSSLError:
+ # Unwrap our wfile
+ req.wfile = CP_fileobject(self.socket, "wb", -1)
+ if req and not req.sent_headers:
+ req.simple_response("400 Bad Request",
+ "The client sent a plain HTTP request, but "
+ "this server only speaks HTTPS on this port.")
+ except Exception, e:
+ if req and not req.sent_headers:
+ req.simple_response("500 Internal Server Error", format_exc())
+
+ def close(self):
+ """Close the socket underlying this connection."""
+ self.rfile.close()
+
+ # Python's socket module does NOT call close on the kernel socket
+ # when you call socket.close(). We do so manually here because we
+ # want this server to send a FIN TCP segment immediately. Note this
+ # must be called *before* calling socket.close(), because the latter
+ # drops its reference to the kernel socket.
+ self.socket._sock.close()
+
+ self.socket.close()
+
+
+def format_exc(limit=None):
+ """Like print_exc() but return a string. Backport for Python 2.3."""
+ try:
+ etype, value, tb = sys.exc_info()
+ return ''.join(traceback.format_exception(etype, value, tb, limit))
+ finally:
+ etype = value = tb = None
+
+
+_SHUTDOWNREQUEST = None
+
+class WorkerThread(threading.Thread):
+ """Thread which continuously polls a Queue for Connection objects.
+
+ server: the HTTP Server which spawned this thread, and which owns the
+ Queue and is placing active connections into it.
+ ready: a simple flag for the calling server to know when this thread
+ has begun polling the Queue.
+
+ Due to the timing issues of polling a Queue, a WorkerThread does not
+ check its own 'ready' flag after it has started. To stop the thread,
+ it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
+ (one for each running WorkerThread).
+ """
+
+ conn = None
+
+ def __init__(self, server):
+ self.ready = False
+ self.server = server
+ threading.Thread.__init__(self)
+
+ def run(self):
+ try:
+ self.ready = True
+ while True:
+ conn = self.server.requests.get()
+ if conn is _SHUTDOWNREQUEST:
+ return
+
+ self.conn = conn
+ try:
+ conn.communicate()
+ finally:
+ conn.close()
+ self.conn = None
+ except (KeyboardInterrupt, SystemExit), exc:
+ self.server.interrupt = exc
+
+
+class ThreadPool(object):
+ """A Request Queue for the CherryPyWSGIServer which pools threads.
+
+ ThreadPool objects must provide min, get(), put(obj), start()
+ and stop(timeout) attributes.
+ """
+
+ def __init__(self, server, min=10, max=-1):
+ self.server = server
+ self.min = min
+ self.max = max
+ self._threads = []
+ self._queue = Queue.Queue()
+ self.get = self._queue.get
+
+ def start(self):
+ """Start the pool of threads."""
+ for i in xrange(self.min):
+ self._threads.append(WorkerThread(self.server))
+ for worker in self._threads:
+ worker.setName("CP WSGIServer " + worker.getName())
+ worker.start()
+ for worker in self._threads:
+ while not worker.ready:
+ time.sleep(.1)
+
+ def _get_idle(self):
+ """Number of worker threads which are idle. Read-only."""
+ return len([t for t in self._threads if t.conn is None])
+ idle = property(_get_idle, doc=_get_idle.__doc__)
+
+ def put(self, obj):
+ self._queue.put(obj)
+ if obj is _SHUTDOWNREQUEST:
+ return
+
+ def grow(self, amount):
+ """Spawn new worker threads (not above self.max)."""
+ for i in xrange(amount):
+ if self.max > 0 and len(self._threads) >= self.max:
+ break
+ worker = WorkerThread(self.server)
+ worker.setName("CP WSGIServer " + worker.getName())
+ self._threads.append(worker)
+ worker.start()
+
+ def shrink(self, amount):
+ """Kill off worker threads (not below self.min)."""
+ # Grow/shrink the pool if necessary.
+ # Remove any dead threads from our list
+ for t in self._threads:
+ if not t.isAlive():
+ self._threads.remove(t)
+ amount -= 1
+
+ if amount > 0:
+ for i in xrange(min(amount, len(self._threads) - self.min)):
+ # Put a number of shutdown requests on the queue equal
+ # to 'amount'. Once each of those is processed by a worker,
+ # that worker will terminate and be culled from our list
+ # in self.put.
+ self._queue.put(_SHUTDOWNREQUEST)
+
+ def stop(self, timeout=5):
+ # Must shut down threads here so the code that calls
+ # this method can know when all threads are stopped.
+ for worker in self._threads:
+ self._queue.put(_SHUTDOWNREQUEST)
+
+ # Don't join currentThread (when stop is called inside a request).
+ current = threading.currentThread()
+ while self._threads:
+ worker = self._threads.pop()
+ if worker is not current and worker.isAlive():
+ try:
+ if timeout is None or timeout < 0:
+ worker.join()
+ else:
+ worker.join(timeout)
+ if worker.isAlive():
+ # We exhausted the timeout.
+ # Forcibly shut down the socket.
+ c = worker.conn
+ if c and not c.rfile.closed:
+ if SSL and isinstance(c.socket, SSL.ConnectionType):
+ # pyOpenSSL.socket.shutdown takes no args
+ c.socket.shutdown()
+ else:
+ c.socket.shutdown(socket.SHUT_RD)
+ worker.join()
+ except (AssertionError,
+ # Ignore repeated Ctrl-C.
+ # See http://www.cherrypy.org/ticket/691.
+ KeyboardInterrupt), exc1:
+ pass
+
+
+
+class SSLConnection:
+ """A thread-safe wrapper for an SSL.Connection.
+
+ *args: the arguments to create the wrapped SSL.Connection(*args).
+ """
+
+ def __init__(self, *args):
+ self._ssl_conn = SSL.Connection(*args)
+ self._lock = threading.RLock()
+
+ for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
+ 'renegotiate', 'bind', 'listen', 'connect', 'accept',
+ 'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
+ 'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
+ 'makefile', 'get_app_data', 'set_app_data', 'state_string',
+ 'sock_shutdown', 'get_peer_certificate', 'want_read',
+ 'want_write', 'set_connect_state', 'set_accept_state',
+ 'connect_ex', 'sendall', 'settimeout'):
+ exec """def %s(self, *args):
+ self._lock.acquire()
+ try:
+ return self._ssl_conn.%s(*args)
+ finally:
+ self._lock.release()
+""" % (f, f)
+
+
+try:
+ import fcntl
+except ImportError:
+ try:
+ from ctypes import windll, WinError
+ except ImportError:
+ def prevent_socket_inheritance(sock):
+ """Dummy function, since neither fcntl nor ctypes are available."""
+ pass
+ else:
+ def prevent_socket_inheritance(sock):
+ """Mark the given socket fd as non-inheritable (Windows)."""
+ if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0):
+ raise WinError()
+else:
+ def prevent_socket_inheritance(sock):
+ """Mark the given socket fd as non-inheritable (POSIX)."""
+ fd = sock.fileno()
+ old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+ fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
+
+
+class CherryPyWSGIServer(object):
+ """An HTTP server for WSGI.
+
+ bind_addr: The interface on which to listen for connections.
+ For TCP sockets, a (host, port) tuple. Host values may be any IPv4
+ or IPv6 address, or any valid hostname. The string 'localhost' is a
+ synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
+ The string '0.0.0.0' is a special IPv4 entry meaning "any active
+ interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
+ IPv6. The empty string or None are not allowed.
+
+ For UNIX sockets, supply the filename as a string.
+ wsgi_app: the WSGI 'application callable'; multiple WSGI applications
+ may be passed as (path_prefix, app) pairs.
+ numthreads: the number of worker threads to create (default 10).
+ server_name: the string to set for WSGI's SERVER_NAME environ entry.
+ Defaults to socket.gethostname().
+ max: the maximum number of queued requests (defaults to -1 = no limit).
+ request_queue_size: the 'backlog' argument to socket.listen();
+ specifies the maximum number of queued connections (default 5).
+ timeout: the timeout in seconds for accepted connections (default 10).
+
+ nodelay: if True (the default since 3.1), sets the TCP_NODELAY socket
+ option.
+
+ protocol: the version string to write in the Status-Line of all
+ HTTP responses. For example, "HTTP/1.1" (the default). This
+ also limits the supported features used in the response.
+
+
+ SSL/HTTPS
+ ---------
+ The OpenSSL module must be importable for SSL functionality.
+ You can obtain it from http://pyopenssl.sourceforge.net/
+
+ ssl_certificate: the filename of the server SSL certificate.
+ ssl_privatekey: the filename of the server's private key file.
+
+ If either of these is None (both are None by default), this server
+ will not use SSL. If both are given and are valid, they will be read
+ on server start and used in the SSL context for the listening socket.
+ """
+
+ protocol = "HTTP/1.1"
+ _bind_addr = "127.0.0.1"
+ version = "CherryPy/3.1.1"
+ ready = False
+ _interrupt = None
+
+ nodelay = True
+
+ ConnectionClass = HTTPConnection
+ environ = {}
+
+ # Paths to certificate and private key files
+ ssl_certificate = None
+ ssl_private_key = None
+
+ def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
+ max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
+ self.requests = ThreadPool(self, min=numthreads or 1, max=max)
+
+ if callable(wsgi_app):
+ # We've been handed a single wsgi_app, in CP-2.1 style.
+ # Assume it's mounted at "".
+ self.wsgi_app = wsgi_app
+ else:
+ # We've been handed a list of (path_prefix, wsgi_app) tuples,
+ # so that the server can call different wsgi_apps, and also
+ # correctly set SCRIPT_NAME.
+ warnings.warn("The ability to pass multiple apps is deprecated "
+ "and will be removed in 3.2. You should explicitly "
+ "include a WSGIPathInfoDispatcher instead.",
+ DeprecationWarning)
+ self.wsgi_app = WSGIPathInfoDispatcher(wsgi_app)
+
+ self.bind_addr = bind_addr
+ if not server_name:
+ server_name = socket.gethostname()
+ self.server_name = server_name
+ self.request_queue_size = request_queue_size
+
+ self.timeout = timeout
+ self.shutdown_timeout = shutdown_timeout
+
+ def _get_numthreads(self):
+ return self.requests.min
+ def _set_numthreads(self, value):
+ self.requests.min = value
+ numthreads = property(_get_numthreads, _set_numthreads)
+
+ def __str__(self):
+ return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
+ self.bind_addr)
+
+ def _get_bind_addr(self):
+ return self._bind_addr
+ def _set_bind_addr(self, value):
+ if isinstance(value, tuple) and value[0] in ('', None):
+ # Despite the socket module docs, using '' does not
+ # allow AI_PASSIVE to work. Passing None instead
+ # returns '0.0.0.0' like we want. In other words:
+ # host AI_PASSIVE result
+ # '' Y 192.168.x.y
+ # '' N 192.168.x.y
+ # None Y 0.0.0.0
+ # None N 127.0.0.1
+ # But since you can get the same effect with an explicit
+ # '0.0.0.0', we deny both the empty string and None as values.
+ raise ValueError("Host values of '' or None are not allowed. "
+ "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead "
+ "to listen on all active interfaces.")
+ self._bind_addr = value
+ bind_addr = property(_get_bind_addr, _set_bind_addr,
+ doc="""The interface on which to listen for connections.
+
+ For TCP sockets, a (host, port) tuple. Host values may be any IPv4
+ or IPv6 address, or any valid hostname. The string 'localhost' is a
+ synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
+ The string '0.0.0.0' is a special IPv4 entry meaning "any active
+ interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
+ IPv6. The empty string or None are not allowed.
+
+ For UNIX sockets, supply the filename as a string.""")
+
+ def start(self):
+ """Run the server forever."""
+ # We don't have to trap KeyboardInterrupt or SystemExit here,
+ # because cherrpy.server already does so, calling self.stop() for us.
+ # If you're using this server with another framework, you should
+ # trap those exceptions in whatever code block calls start().
+ self._interrupt = None
+
+ # Select the appropriate socket
+ if isinstance(self.bind_addr, basestring):
+ # AF_UNIX socket
+
+ # So we can reuse the socket...
+ try: os.unlink(self.bind_addr)
+ except: pass
+
+ # So everyone can access the socket...
+ try: os.chmod(self.bind_addr, 0777)
+ except: pass
+
+ info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
+ else:
+ # AF_INET or AF_INET6 socket
+ # Get the correct address family for our host (allows IPv6 addresses)
+ host, port = self.bind_addr
+ try:
+ info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
+ socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
+ except socket.gaierror:
+ # Probably a DNS issue. Assume IPv4.
+ info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", self.bind_addr)]
+
+ self.socket = None
+ msg = "No socket could be created"
+ for res in info:
+ af, socktype, proto, canonname, sa = res
+ try:
+ self.bind(af, socktype, proto)
+ except socket.error, msg:
+ if self.socket:
+ self.socket.close()
+ self.socket = None
+ continue
+ break
+ if not self.socket:
+ raise socket.error, msg
+
+ # Timeout so KeyboardInterrupt can be caught on Win32
+ self.socket.settimeout(1)
+ self.socket.listen(self.request_queue_size)
+
+ # Create worker threads
+ self.requests.start()
+
+ self.ready = True
+ while self.ready:
+ self.tick()
+ if self.interrupt:
+ while self.interrupt is True:
+ # Wait for self.stop() to complete. See _set_interrupt.
+ time.sleep(0.1)
+ if self.interrupt:
+ raise self.interrupt
+
+ def bind(self, family, type, proto=0):
+ """Create (or recreate) the actual socket object."""
+ self.socket = socket.socket(family, type, proto)
+ prevent_socket_inheritance(self.socket)
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ if self.nodelay:
+ self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ if self.ssl_certificate and self.ssl_private_key:
+ if SSL is None:
+ raise ImportError("You must install pyOpenSSL to use HTTPS.")
+
+ # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
+ ctx = SSL.Context(SSL.SSLv23_METHOD)
+ ctx.use_privatekey_file(self.ssl_private_key)
+ ctx.use_certificate_file(self.ssl_certificate)
+ self.socket = SSLConnection(ctx, self.socket)
+ self.populate_ssl_environ()
+
+ # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
+ # activate dual-stack. See http://www.cherrypy.org/ticket/871.
+ if (not isinstance(self.bind_addr, basestring)
+ and self.bind_addr[0] == '::' and family == socket.AF_INET6):
+ try:
+ self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
+ except (AttributeError, socket.error):
+ # Apparently, the socket option is not available in
+ # this machine's TCP stack
+ pass
+
+ self.socket.bind(self.bind_addr)
+
+ def tick(self):
+ """Accept a new connection and put it on the Queue."""
+ try:
+ s, addr = self.socket.accept()
+ prevent_socket_inheritance(s)
+ if not self.ready:
+ return
+ if hasattr(s, 'settimeout'):
+ s.settimeout(self.timeout)
+
+ environ = self.environ.copy()
+ # SERVER_SOFTWARE is common for IIS. It's also helpful for
+ # us to pass a default value for the "Server" response header.
+ if environ.get("SERVER_SOFTWARE") is None:
+ environ["SERVER_SOFTWARE"] = "%s WSGI Server" % self.version
+ # set a non-standard environ entry so the WSGI app can know what
+ # the *real* server protocol is (and what features to support).
+ # See http://www.faqs.org/rfcs/rfc2145.html.
+ environ["ACTUAL_SERVER_PROTOCOL"] = self.protocol
+ environ["SERVER_NAME"] = self.server_name
+
+ if isinstance(self.bind_addr, basestring):
+ # AF_UNIX. This isn't really allowed by WSGI, which doesn't
+ # address unix domain sockets. But it's better than nothing.
+ environ["SERVER_PORT"] = ""
+ else:
+ environ["SERVER_PORT"] = str(self.bind_addr[1])
+ # optional values
+ # Until we do DNS lookups, omit REMOTE_HOST
+ environ["REMOTE_ADDR"] = addr[0]
+ environ["REMOTE_PORT"] = str(addr[1])
+
+ conn = self.ConnectionClass(s, self.wsgi_app, environ)
+ self.requests.put(conn)
+ except socket.timeout:
+ # The only reason for the timeout in start() is so we can
+ # notice keyboard interrupts on Win32, which don't interrupt
+ # accept() by default
+ return
+ except socket.error, x:
+ if x.args[0] in socket_error_eintr:
+ # I *think* this is right. EINTR should occur when a signal
+ # is received during the accept() call; all docs say retry
+ # the call, and I *think* I'm reading it right that Python
+ # will then go ahead and poll for and handle the signal
+ # elsewhere. See http://www.cherrypy.org/ticket/707.
+ return
+ if x.args[0] in socket_errors_nonblocking:
+ # Just try again. See http://www.cherrypy.org/ticket/479.
+ return
+ if x.args[0] in socket_errors_to_ignore:
+ # Our socket was closed.
+ # See http://www.cherrypy.org/ticket/686.
+ return
+ raise
+
+ def _get_interrupt(self):
+ return self._interrupt
+ def _set_interrupt(self, interrupt):
+ self._interrupt = True
+ self.stop()
+ self._interrupt = interrupt
+ interrupt = property(_get_interrupt, _set_interrupt,
+ doc="Set this to an Exception instance to "
+ "interrupt the server.")
+
+ def stop(self):
+ """Gracefully shutdown a server that is serving forever."""
+ self.ready = False
+
+ sock = getattr(self, "socket", None)
+ if sock:
+ if not isinstance(self.bind_addr, basestring):
+ # Touch our own socket to make accept() return immediately.
+ try:
+ host, port = sock.getsockname()[:2]
+ except socket.error, x:
+ if x.args[1] != "Bad file descriptor":
+ raise
+ else:
+ # Note that we're explicitly NOT using AI_PASSIVE,
+ # here, because we want an actual IP to touch.
+ # localhost won't work if we've bound to a public IP,
+ # but it will if we bound to '0.0.0.0' (INADDR_ANY).
+ for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
+ socket.SOCK_STREAM):
+ af, socktype, proto, canonname, sa = res
+ s = None
+ try:
+ s = socket.socket(af, socktype, proto)
+ # See http://groups.google.com/group/cherrypy-users/
+ # browse_frm/thread/bbfe5eb39c904fe0
+ s.settimeout(1.0)
+ s.connect((host, port))
+ s.close()
+ except socket.error:
+ if s:
+ s.close()
+ if hasattr(sock, "close"):
+ sock.close()
+ self.socket = None
+
+ self.requests.stop(self.shutdown_timeout)
+
+ def populate_ssl_environ(self):
+ """Create WSGI environ entries to be merged into each request."""
+ cert = open(self.ssl_certificate, 'rb').read()
+ cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
+ ssl_environ = {
+ "wsgi.url_scheme": "https",
+ "HTTPS": "on",
+ # pyOpenSSL doesn't provide access to any of these AFAICT
+## 'SSL_PROTOCOL': 'SSLv2',
+## SSL_CIPHER string The cipher specification name
+## SSL_VERSION_INTERFACE string The mod_ssl program version
+## SSL_VERSION_LIBRARY string The OpenSSL program version
+ }
+
+ # Server certificate attributes
+ ssl_environ.update({
+ 'SSL_SERVER_M_VERSION': cert.get_version(),
+ 'SSL_SERVER_M_SERIAL': cert.get_serial_number(),
+## 'SSL_SERVER_V_START': Validity of server's certificate (start time),
+## 'SSL_SERVER_V_END': Validity of server's certificate (end time),
+ })
+
+ for prefix, dn in [("I", cert.get_issuer()),
+ ("S", cert.get_subject())]:
+ # X509Name objects don't seem to have a way to get the
+ # complete DN string. Use str() and slice it instead,
+ # because str(dn) == "<X509Name object '/C=US/ST=...'>"
+ dnstr = str(dn)[18:-2]
+
+ wsgikey = 'SSL_SERVER_%s_DN' % prefix
+ ssl_environ[wsgikey] = dnstr
+
+ # The DN should be of the form: /k1=v1/k2=v2, but we must allow
+ # for any value to contain slashes itself (in a URL).
+ while dnstr:
+ pos = dnstr.rfind("=")
+ dnstr, value = dnstr[:pos], dnstr[pos + 1:]
+ pos = dnstr.rfind("/")
+ dnstr, key = dnstr[:pos], dnstr[pos + 1:]
+ if key and value:
+ wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
+ ssl_environ[wsgikey] = value
+
+ self.environ.update(ssl_environ)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiutils_server.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiutils_server.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiutils_server.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,19 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+from paste.script.serve import ensure_port_cleanup
+from paste.translogger import TransLogger
+
+def run_server(wsgi_app, global_conf, host='localhost',
+ port=8080):
+ from wsgiutils import wsgiServer
+ import logging
+ logged_app = TransLogger(wsgi_app)
+ port = int(port)
+ # For some reason this is problematic on this server:
+ ensure_port_cleanup([(host, port)], maxtries=2, sleeptime=0.5)
+ app_map = {'': logged_app}
+ server = wsgiServer.WSGIServer((host, port), app_map)
+ logged_app.logger.info('Starting HTTP server on http://%s:%s',
+ host, port)
+ server.serve_forever()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1119 @@
+Metadata-Version: 1.0
+Name: ZopeSkel
+Version: 2.19
+Summary: A collection of skeletons for quickstarting Zope projects.
+Home-page: http://svn.plone.org/svn/collective/ZopeSkel/trunk
+Author: Cris Ewing
+Author-email: cewing at uw.edu
+License: MIT
+Description: .. contents ::
+
+ Introduction
+ ============
+
+ ZopeSkel provides a collection of project templates for Plone
+ and Zope development projects.
+
+ ZopeSkel uses the `paster <http://pythonpaste.org/script/>`_ Python library
+ internally.
+
+ Installing ZopeSkel
+ ===================
+
+ ZopeSkel can be installed in one of two ways: with `buildout
+ <http://www.buildout.org/>`_ or with `virtualenv
+ <http://virtualenv.openplans.org/>`_. Despite existing documentation to the
+ contrary, it is not recommended to install ZopeSkel in your system python.
+
+ Buildout installation
+ ---------------------------
+
+ Add to your ``buildout.cfg``::
+
+ parts =
+ ...
+ zopeskel
+
+
+ [zopeskel]
+ recipe = zc.recipe.egg
+ eggs =
+ ZopeSkel
+ ${instance:eggs}
+
+ After building your buildout, this will leave ``zopeskel`` and ``paster``
+ commands in the ``bin`` directory of your buildout.
+
+ Virtualenv installation
+ -----------------------------
+
+ First, install virtualenv into your system::
+
+ easy_install virtualenv
+
+ Next, create a virtual environment with the new ``virtualenv`` command::
+
+ virtualenv --no-site-packages --distribute zopeskelenv
+
+ Once virtualenv is finished, you can install zopeskel to your new virtual
+ environment::
+
+ zopeskelenv/bin/easy_install zopeskel
+
+ Once this is complete, you will be left with ``zopeskel`` and ``paster``
+ commands in the ``bin`` directory inside your virtualenv.
+
+
+ Available Templates
+ ===================
+
+ To see details of the available templates::
+
+ zopeskel --list
+
+ ... or more info about how zopekskel works::
+
+ zopeskel --help
+
+ Using Templates
+ ===============
+
+ Creating a Plone 4 buildout using virtualenv ZopeSkel installation::
+
+ source zopeskelenv/bin/activate
+ zopeskel plone4_buildout yourfoldername
+
+ The folder created, ``yourfoldername``, can be checked into the versioning
+ system of your choice. It is now a portable, self-contained, ready-to-build
+ Plone site. You can build the system at any time using the following::
+
+ cd yourfoldername
+ python bootstrap.py
+ bin/buildout
+
+ The ``plone4_buildout`` recipe results in a self-contained version of ZopeSkel
+ installed via the buildout method described above. It thus provides the
+ ``zopeskel`` and ``paster`` commands inside its ``bin`` folder. You can use these
+ commands inside the buildout to create packages for your new Plone site::
+
+ bin/zopeskel plone3_theme src/plonetheme.yourcompanyid
+
+ The command will ask a few questions such as desired package name and a
+ description and output a complete package you can immediately start using.
+ Interactive help is available by entering "?" as a response to any question.
+
+ .. note ::
+
+ Because ZopeSkel is built on paster you can do anything we describe here
+ using the ``paster`` command directly. If you do so, you can gain access to
+ certain features of ``paster`` that have been disabled for ``zopeskel``, but
+ you also will lose access to many of the nicer features of ``zopeskel``,
+ including validation and in-line help.
+
+ Local Commands
+ ==============
+
+ In addition to project templates, the ZopeSkel system provides local commands.
+ Local commands are context aware commands that help you to add more
+ functionality to an existing ZopeSkel generated project.
+
+ .. note ::
+
+ Local commands require using the ``paster`` command directly - the
+ ``zopeskel`` command does not support them yet.
+
+ .. note ::
+
+ Not all ZopeSkel templates provide local commands. In general, if local
+ commands are available, you will be informed of the fact as your new
+ package is generated.
+
+ Using local commands to create a content type package
+ -----------------------------------------------------
+
+ Starting inside your Plone buildout, first create an archetypes package::
+
+ cd src
+ ../bin/zopeskel archetype mycompanyid.mycustomcontenttypes
+
+ Next, change directories into your new package and invoke ``paster`` to add a
+ content type::
+
+ cd mycompanyid.mycustomcontenttypes
+ ../../bin/paster
+
+ Usage: ../../bin/paster COMMAND
+ usage: paster [paster_options] COMMAND [command_options]
+
+ ...
+
+ Commands:
+ ...
+
+ ZopeSkel local commands:
+ addcontent Adds plone content types to your project
+
+
+ As you can see from the ``paster`` command output, your new package supports a
+ local command called ``addcontent``. Tou can use ``addcontent`` command to add
+ new code to your package. As with both ``zopskel`` and ``paster``, you can use
+ the ``--list`` option to see what local commands are available in the context of
+ the package you've created.
+
+ ../../bin/paster addcontent --list
+
+ Available templates:
+ atschema: A handy AT schema builder
+ browserlayer: A Plone browserlayer
+ contenttype: A content type skeleton
+ form: A form skeleton
+ formfield: Schema field for a form
+ i18nlocale: An i18n locale directory structure
+ portlet: A Plone 3 portlet
+ view: A browser view skeleton
+ zcmlmeta: A ZCML meta directive skeleton
+
+ You can add an archetypes content type for managing lectures::
+
+ ../../bin/paster addcontent -t contenttype LectureInfo
+
+ Then you can add schema fields to that content type::
+
+ ../../bin/paster addcontent -t atschema
+
+ local commands can be run as many times as needed to create your package. You
+ can iteratively develop your content type, other content types, and more.
+
+ .. note ::
+
+ When changing the your package code local commands will often change
+ GenericSetup XML files (found in the in ``profiles/default`` folder of your
+ package). These changes will not appear in Plone/Zope simply by restarting your
+ instance. You will usually need to re-install your package in your development
+ Plone site if you run any local commands in a package you've already installed.
+
+ More info
+
+ * http://collective-docs.plone.org/tutorials/paste.html
+
+ Testing
+ =======
+
+ Since version 1.5, ZopeSkel has tests. It's required to run these
+ before you check in any changes you make. They can be run like so::
+
+ python setup.py test
+
+ More info
+ =========
+
+ Issue tracker
+
+ * http://plone.org/products/zopeskel/issues
+
+ Source code
+
+ * http://svn.plone.org/svn/collective/ZopeSkel/trunk
+
+ Mailing List
+
+ * https://lists.plone.org/mailman/listinfo/zopeskel
+
+ Please contribute by submitting patches for what you consider 'best of
+ breed' file layouts for starting Zope projects.
+
+ Changelog
+ =========
+
+ 2.19 - January 21, 2011
+ --------------------------
+
+ * In every setup.py, replace '%3A' with ':', making list_classifier url an url
+ which can actually be used.
+ [thet]
+
+ * Added plone4_buildout [miohtama]
+
+ * Improvements to README [miohtama]
+
+ 2.18 - September 30, 2010
+ -------------------------
+
+ * Add bin/zopeskel --version flag. Reports current version of zopeskel
+ (http://plone.org/products/zopeskel/issues/48)
+ [cewing]
+
+ * plone3_buildout: use Plone 3.3.5 by default.
+ [maurits]
+
+ * Fixed a problem with the generic setup profile in plone templates in which a
+ profile was registered in zcml, but no profiles directory was created.
+ (http://plone.org/products/zopeskel/issues/46)
+ [cewing]
+
+ * use i18n:domain plone for portlet title so it need not be translated twice
+ (http://plone.org/products/zopeskel/issues/44)
+ [fRiSi]
+
+ * use the correct name of package, so it can be used in package with 2 dots or
+ 1 dots in package name
+ [lucmult]
+
+ 2.17 - June 14, 2010
+ --------------------
+
+ * Added a pin for PasteScript>=1.7.2. This solves an issue where using zopeskel
+ with an early version of PasteScript resulted in a method signature mismatch
+ on the paster command 'challenge' method. Fixes issue #42
+ (http://plone.org/products/zopeskel/issues/42)
+ [cewing]
+
+ * Fixed lingering problem in Archetypes template with registering a 'locales'
+ directory before one is created. Users now need to add an i18nlocale via
+ addcontent in order to get this directory and have it registered via zcml.
+ [cewing]
+
+ * Fixed dependency in Archetypes template doctests on the presence of the log-in
+ portlet. Tests now open the 'login_form' instead. Resolves issue #40
+ (http://plone.org/products/zopeskel/issues/40)
+ [cewing]
+
+ * Added new browserlayer localcommand for plone and archetype templates.
+ [marcosfromero]
+
+ * Added stub locales directory for plone3_theme template, resolving issue #33
+ (http://plone.org/products/zopeskel/issues/33)
+ [cewing]
+
+ * Set the GenericSetup profile version number in the generated
+ metadata.xml to 1000, which is better for the alphabetical ordering
+ that GS does.
+ [maurits]
+
+ * Added "environment-vars = zope_i18n_compile_mo_files true" to
+ plone3_buildout template. This is enabled only for Plone 4 (eggifiedzope is
+ true).
+ [vincentfretin]
+
+ 2.16 - March 22, 2010
+ ---------------------
+
+ * Fixed syntax error in generated portlet constructor code
+ [ajung]
+
+ * Added a new 'BoundedIntVar' variable type. It validates that the provided
+ argument is both an integer and between provided min and max values (inclusive
+ on both ends).
+ [cewing]
+
+ * Updated archetype and plone3_portlet templates to comply with pep8 and
+ pyflakes validation at all stages of a skeleton build process. Resolves the
+ issue here: (http://plone.org/products/zopeskel/issues/24)
+ [cewing]
+
+ * Added explanatory text to the plone_hosting template regarding the fact that
+ it is unsuitable for use with plone versions later than 3.1.7, fixed
+ http://plone.org/products/zopeskel/issues/25
+ [cewing]
+
+ * Fixed the problem with generated archetypes content type meta_type names
+ documented here:
+ (http://plone.org/products/zopeskel/issues/22)
+ [cewing]
+
+ * Updated tests for the plone template to include tests for the fixes to message
+ factory, zcml sub-package include and i18n translation registration problems
+ below
+ [cewing]
+
+ * Cleaned up a number of issues with defining and importing a package-wide
+ MessageFactory in plone template local commands:
+ (http://plone.org/products/zopeskel/issues/29)
+ [cewing]
+
+ * Cleaned up a number of issues with importing sub-package zcml files after
+ using local commands in the plone template:
+ (http://plone.org/products/zopeskel/issues/28)
+ [cewing]
+
+ * Fixed an issue with the plone template zcmlmeta local command to ensure that
+ the proper directive was inserted into the top-level configure.zcml
+ [cewing]
+
+ * Fixed the bug in the plone template that caused zcml errors when the
+ i18nlocale local command had not been run:
+ (http://plone.org/products/zopeskel/issues/26)
+ [cewing]
+
+ * Improved i18n for portlets
+ (http://plone.org/products/zopeskel/issues/31)
+ [fRiSi]
+
+ * Improved test coverage of the zopeskel script
+ [cewing]
+
+ * Disallowed use of the paster --svn-repository command due to some basic
+ incompatibilities with the way zopeskel is used. The argument is still
+ allowed for users via 'paster create'.
+ (http://plone.org/products/zopeskel/issues/34
+ http://plone.org/products/zopeskel/issues/35)
+ [cewing]
+
+ * Added a 'Register Profile' question to the plone template so that users can
+ have a Generic Setup profile registered in the case that they plan on adding
+ things (like portlets) that require a GS Profile to install. Adapted
+ downstream templates archetype, plone25_theme and plone3_theme to use the new
+ question
+ [cewing]
+
+ 2.15 - January 22, 2010
+ -----------------------
+
+ * Backed out a few changes from jaroel in favor of retaining working templates
+ OOTB
+ [cewing]
+
+ * Made archetype, plone3_theme and plone3_portlet pass the PEP8 validator and
+ pyflakes.
+ [jaroel]
+
+ * Template summaries (one-line descriptions) were improved.
+ [pupq]
+
+ * Templates now have an optional help attribute, which is a rich description of
+ the template and its purpose. Help has been provided for all the ZopeSkel
+ templates.
+ [pupq/cewing]
+
+ * Variables (questions in templates) now have a human-facing "title" attribute
+ which can be shown instead of the (uglier + more opaque) actual variable
+ name. Titles have been written for questions.
+ [pupq]
+
+ * Variables now have optional help attribute, which is a rich description of
+ the variable. This can be shown in pastescript UIs.
+ [pupq]
+
+ * Interactive help has been added, so that you can enter "?" at any question to
+ receive the rich help for that question.
+ [cewing]
+
+ * "Modes" have been implemented--easy, expert, and all--to reduce the number of
+ questions posed to beginning users. For example, technical questions (like
+ "namespace package 2") are now shown only in expert mode.
+ [cewing/pupq]
+
+ * The project name (eg, "plone.app.example") is now split into pieces to become
+ the default values for namespace packages names ("plone", "app", "example").
+ [pupq]
+
+ * Templates can provide an ndot attribute that signals how many namespaces
+ ("dots") are expected in the project name. When invoked through new zopeskel
+ front-end script, names that don't support that pattern are rejected with
+ help (eg, creating a plone_app with "plone.example" would be rejected, as a
+ 2-namespaced-name, "plone.foo.example", is expected)
+ [pupq]
+
+ * Rather than having to use the checkvar() and post() methods, templates can
+ now support messages that appear pre-questions and post-generation.
+ Appropriate warnings and where-to-go help has been added.
+ [cewing]
+
+ * Abstract classes for zope2 products and buildouts have been added; this
+ simplifies inheritance of common attrs, and provides appropriate places for
+ future common logic.
+ [pupq]
+
+ * A front-end script, 'zopeskel', has been added. This has high-level, friendly
+ help, and an improved command line interface for the task of template usage.
+ It can provide a friendly list of templates and a verbosely-detailed list of
+ templates.
+ [pupq/cewing/chrisrossi]
+
+ * Users can have a "$HOME/.zopeskel" script with default values for questions,
+ either on a all-template or template-by-template basis.
+ [pupq]
+
+ * The "zopeskel" script can emit a sample ".zopeskel" file, for editing.
+ [pupq/cbc]
+
+ * A simple HTML help generator can produce a listing of templates, fields, and
+ subtemplates. This will be useful for maintaining an HTML "reference guide"
+ to the ZopeSkel templates. Find this in the zopeskel.doctools package.
+ [pupq/cbc]
+
+ * Currently-failing unit tests were fixed.
+ [pupq/cewing]
+
+ * New unit tests were written for new features.
+ [cewing]
+
+ * New and repaired unit tests were added into the default test suite
+ [cewing]
+
+ * Rather than using a generic var() class for all variables ("questions"),
+ subclasses for different types of variables--string, boolean, choices,
+ etc.--were added. These normalize their own values and provide validation.
+ Therefore, users will get earlier/better feedback on inappropriate values.
+ [pupq/cewing]
+
+ * A proposal for splitting the project into zopeskel.* packages was added.
+ [pupq/cbc]
+
+ * Where questions were duplicated across different templates, they were
+ consolidated for consistency into one place, and referred to from other
+ places.
+ [pupq]
+
+ * A real-time tool for generating graphs of dependencies and template
+ inheritance was written, suitable for including in high-level documentation.
+ Find this in the zopeskel.doctools package.
+ [cbc]
+
+ * Use the eggified Zope 2.12.3 for buildouts targeting Plone 4.x.
+ Use 2.9.12 for buildouts targeting Plone 2.x.
+ [maurits]
+
+ * Remove unnecessary 'title' argument from jsregistry.xml example.
+ This fixes http://plone.org/products/zopeskel/issues/18.
+ [dukebody]
+
+ 2.14.2 - December 8th, 2009
+ ---------------------------
+
+ * Back out untested, undocumented changes from paris sprint that broke some
+ templates
+ [MatthewWilkes]
+
+ 2.14.1 - November 19th, 2009
+ ----------------------------
+
+ * Fix packaging error
+ [MatthewWilkes]
+
+ 2.14 - November 19th, 2009
+ --------------------------
+
+ * Use the eggified Zope 2.12.1 for buildouts targeting Plone 4.x. Bump 3.x
+ default version to 3.3.2.
+ [MatthewWilkes]
+
+ * Use distribute for Plone buildouts
+ [MatthewWilkes]
+
+ * Remove extra quotes in a plone_pas template file, which were
+ generating a syntax error.
+ [dukebody]
+
+
+ 2.13 - October 3rd, 2009
+ ------------------------
+
+ * Pinned Cheetah to <= 2.2.1 and eliminated install_requires for elementtree
+ (markdown not a requirement for Cheetah 2.2.1). Allows zopeskel to easy_install
+ with python 2.4. Can remove pinning when markdown is fixed.
+ [cbcunc]
+
+ * plone3_buildout: added 'fake-zope-eggs = true' to the zope2 part, as
+ otherwise you get e.g. 'ImportError: No module named ImplPython'
+ when using a plone.recipe.zope2install < 3.0, like pinned by Plone
+ 3.2 versions.cfg.
+ [maurits]
+
+ * Make the Plone 3 buildout template default to Plone 3.3.1.
+ [dukebody]
+
+ * Modify HISTORY.txt convention in basic_namespace and nested_namespace
+ templates. Use now "1.0dev (unreleased)" and '-' for changelog items.
+ [vincentfretin]
+
+ * Fix trove classifiers list url in all setup.py_tmpl
+ [vincentfretin]
+
+ * Remove old import_steps.xml from profiles/default/ in plone3_theme template,
+ the various import step in registered in profile.zcml now.
+ [vincentfretin]
+
+ * For plone3_theme, plone3_portlet an archetype templates,
+ start profile version at 1 to follow current convention.
+ [vincentfretin]
+
+ * Remove http://download.zope.org/ppix/,
+ http://download.zope.org/distribution/, and
+ http://effbot.org/downloads from find-links in the plone3_buildout template.
+ Only Pypi or http://dist.plone.org/release/${plone_version}
+ is really needed.
+ Add http://dist.plone.org/thirdparty for alternative location for
+ elementree, PILwoTk, markdown, python-ldap.
+ [vincentfretin]
+
+
+ 2.12 - September 23rd, 2009
+ ---------------------------
+
+ * Remove the options fake-zope-eggs=true and
+ additional-fake-eggs=ZODB3 in the plone3_buildout template since
+ fake-zope-eggs is enabled by default in
+ plone.recipe.zope2install>=3.0, with ZODB3 among the default "fake
+ zope eggs". [dukebody]
+
+ * Declare a dependency on elementtree. It's not a direct dependency
+ of ZopeSkel, but ZopeSkel depends on Cheetah which depends on
+ Markdown, which has an install-time dependency on elementtree but
+ doesn't declare that.
+ [davisagli]
+
+ * remove the custom `egg_info.writer` and keywords for `paster_plugins`
+ since this has been an entry point of PasteScript since 1.6.3, using
+ the `setup_requires` as per the change log found here:
+ http://pythonpaste.org/script/news.html#id4
+
+ This solves an issue where the distutils would go into an infinite
+ loop when you add a new `install_requires` package
+ [claytron]
+
+ * plone3_theme: made the generated viewlet.pt not crash when the
+ accompanying view has not been changed so has no computed_value.
+ Added some inline documentation there and fixed example
+ registration. [maurits]
+
+ * In the plone3_theme say that we are creating a theme for Plone 3,
+ not specifically for 3.0.
+ [maurits]
+
+ * In the plone template fix the generated INSTALL.txt: when telling
+ users to add $project to the eggs, the example snippet should indeed
+ add $project and not the $full_package_name.
+ [maurits]
+
+ * In the plone_app and plone3_portlet templates use the full package
+ name instead of the project name in zcml lines in the generated
+ INSTALL.txt. The project/package/egg name may be 'silly' when the
+ package structure is far/better/name, which means the zcml needs to
+ be 'far.better.name'. Thanks to Espen Moe-Nilssen for spotting this.
+ [maurits]
+
+ * Make the Plone 3 buildout default to Plone 3.2.2.
+ [maurits]
+
+ * Removed the setup.cfg from all templates. It makes the common operation of
+ tagging and releasing packages harder with little benefit. It can be easily
+ added by those who know about this particular feature.
+ [hannosch]
+
+ * Removed the useless `Python Modules` trove classifier from all templates.
+ [hannosch]
+
+ 2.11 - February 5th, 2009
+ -------------------------
+
+ * Make the Plone 3 buildout default to Plone 3.2.1, and pick up
+ ${versions:zope2-url} for Plone > 3.1
+ [MatthewWilkes]
+
+ * added a version requirement for Cheetah (>1.0)
+ [tarek]
+
+ * fix zopeskel/docs/localcommands.txt
+ [yboussard]
+
+ * Modify zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl
+ to init egg as product if it is a Zope2 product.
+ [yboussard]
+
+ * Modify plone3_buildout template to ask for a Plone version. If the version
+ is 3.0 or 3.1 it uses the plone install recipe, otherwise it uses the Plone
+ egg from the cheeseshop.
+ [MatthewWilkes]
+
+ * Link to appropriate PyPI pages for recipes used.
+ [MatthewWilkes]
+
+ * Add a Zope 2 without Plone buildout template.
+ [evilbungle]
+
+ * Reconciling HISTORY.txt to mirror what can be found at the following:
+ http://pypi.python.org/pypi/ZopeSkel/2.10. Release of 2.10 was clobbered
+ due to what looks like a merge at r74790.
+ [andrewb]
+
+ * Update plone2.5_template's buildout.cfg_tmpl to use Zope 2.9.10. This
+ release incorporates Hotfix-2008-08-12. Defaulting to a known insecure
+ Zope seems unwise for people that may be updating legacy environments into
+ buildout, since they're likely to forget to include the hotfix. Url to
+ 2.9.10 hard-coded (as opposed to the more elegantly self-aware
+ plone.recipe.plone approach) per the practice of a plone.recipe.distros
+ plone part.
+ [andrewb]
+
+ * Nearly at the end of the creation of a ZopeSkel template, the local
+ commands available for that template are displayed.
+ [jaraco, markvl]
+
+ * The Plone template now has local commands. (Basically moved them
+ from the archetype templates to plone templates and made them
+ available for both.
+ [markvl]
+
+ * Added base test setup to the archetype template. Added wiring code that
+ runs README.txt as a doctest.
+ [esartor]
+
+ * Added tests to the addcontent contenttype command. These ammend the
+ README.txt file for each content type providing basic tests for creating,
+ editing and removing instances of the added content type.
+ [esartor]
+
+
+ 2.10 - September 17th, 2008
+ ---------------------------
+
+ * Fixed a small bug that made most templates create a package that was
+ * showing twice in the Plone quick
+ installer is the top level namespace package was called 'Products'. Bug
+ was fixed in the 'plone' template (since version 1.5), now in other ones
+ where needed too.
+ [davconvent]
+
+
+ 2.9 - September 1st, 2008
+ -------------------------
+
+ * Update silva buildout to reflect changes in Silva 2.1 as stable
+ version, and 2.2 as development: SilvaLayout is not shipped anymore
+ as an extra distribution but integrated in Silva all. Remove
+ question, and update buildout.cfg template.
+ [thefunny]
+
+
+ 2.8 - July 31, 2008
+ -------------------
+
+ * Generate logrotate configuration file using collective.recipe.template
+ so it does not need to contain absolute paths. This makes it possible
+ to move the generated buildout around, or install it on other machines
+ with different filesystem layouts.
+ [wichert]
+
+ * Also rotate instance1-Z2.log.
+ [wichert]
+
+ * Update documentation for hosting template to note that logrotate needs
+ to be told where to put its status file.
+ [wichert]
+
+
+ 2.7 - July 25, 2008
+ -------------------
+
+ * Hosting template:
+
+ - Switch default Plone version to 3.1.4.
+ [wichert]
+
+ - Corrected a typo in the logrotate template, which prevented the zeo log
+ to be rotated.
+ [hannosch]
+
+
+ 2.6.2 - July 16, 2008
+ ---------------------
+
+ * Hosting template:
+
+ - Corrected even more references of instance to instance1 in proxy support
+ and logrotate handling.
+ [hannosch]
+
+
+ 2.6.1 - July 16, 2008
+ ---------------------
+
+ * Hosting template:
+
+ - Changed the http_port to start at base_port + 10, to make room for
+ additional services.
+ [hannosch]
+
+ - Corrected hide_summary option, to not show the summary twice.
+ [hannosch]
+
+ 2.6 - July 15, 2008
+ -------------------
+
+ * Hosting template:
+
+ - Corrected one last reference of instance to instance1 in the zopepy eggs
+ option of the plone_hosting template.
+ [hannosch]
+
+ 2.5 - July 15, 2008
+ -------------------
+
+ * Hosting template:
+
+ - fix test for Varnish-support in the supervisord configuration.
+ [wichert]
+
+ - Rename the instance part to instance1 and add an instances group. This
+ makes it possible to upgrade to multiple instances later on without
+ having to break invocations.
+ [wichert]
+
+ 2.4 - July 9, 2008
+ ------------------
+
+ * Restore the cwd after running buildout in the hosting recipe so further
+ processing works correctly.
+ [wichert]
+
+ * Add a hook in the hosting template to not show the summary. This
+ can be used by derived templates that want to show their own summary
+ or show it at a later point.
+ [wichert]
+
+ * Set default Plone version to 3.1.3.
+ [wichert]
+
+ * Added kss plugin template
+ [gotcha, jfroche, adrien01]
+
+ * Silva layout have been merged with Silva all in the development
+ buildout.
+ [thefunny]
+
+ 2.3 - June 24, 2008
+ -------------------
+
+ * Fix problem in the hosting template: varnish was always enabled
+ even if not desired.
+ [wichert]
+
+ * Added ZopeSkel test layer with the apropriate testSetup and testTearDown.
+ The steps in the top of each test file is not anymore needed: delete
+ tempdir/plone.example and then cd to tempdir.
+ [mustapha]
+
+ * Make the zope2product option in the archetype template default to true.
+ [mustapha]
+
+ * Modified buildout.cf to only test zopeskel.
+ [mustapha]
+
+ * Fixed the paster test function: overwrite option should default to True for
+ the create command.
+ [mustapha]
+
+ * Added ``use_local_commands`` attribute (a la use_cheetah). A zopeskel
+ template that wants to use local commands has to set it to True .
+ [mustapha]
+
+ * Get rid of zopeskel.txt and use setup.cfg to store the parent template name.
+ [mustapha]
+
+ * Sub-templates may define a parent_template attribute with the list of
+ templates that can use it.
+ [mustapha]
+
+ * Fixed tests and updated docs.
+ [mustapha]
+
+ Version 2.2
+ -----------
+
+ * Install Plone 3.1.2 by default.
+ [wichert]
+
+ * Remove useless spans from the portlet template.
+ [wichert]
+
+ * Add supervisorctl configuration.
+ [wichert]
+
+
+ Version 2.1
+ -----------
+
+ * Revert BaseTemplate usage from the hosting template (changeset
+ 57368 from Tarek). It was not used and broke the buildout. This fixes
+ http://plone.org/products/zopeskel/issues/8
+ [wichert]
+
+ * Replace the generic README in the plone_hosting template with documentation
+ that is important for deployments.
+ [wichert]
+
+ * Add log rotation support to the hosting buildout. Merged from Jarn's
+ bones package.
+ [wichert]
+
+
+ Version 2.0
+ -----------
+
+ * Switch plone_hosting template to using supervisord to manage processes.
+ Merged from Jarn's bones package.
+ [wichert]
+
+ * Reduced the number of questions to generate an atschema and used
+ the MessageFactory instead of declaring an i18n_domain attribute
+ [mustapha]
+
+ * Fixed missing imports in plone2_theme
+ [mustapha]
+
+ * Removed unused imports in plone_pas
+ [mustapha]
+
+ * In plone2.5_theme: when the skinname is empty, replace it with a
+ default text, otherwise adding a Plone Site will throw an error when
+ displaying the extension profiles.
+ [maurits]
+
+ * Added note to profiles.zcml of plone2.5_theme that
+ five.registerPackage needs Five version 1.4.
+ [maurits]
+
+ * Added a BUILDBOT.txt file.
+ [tarek]
+
+ * plone3_portlet: added commented out alternative AddForm for when
+ there are no configurable parameters. That was shorter than listing
+ all the changes (where we forgot one).
+ [maurits]
+
+ * Fixed typos in archetyps and plone3 portlets: 'portletBotomLeft'
+ should have been 'portletBottomLeft' with two 't's.
+ [maurits]
+
+ * Made plone3_portlet respect pep8 (and pyflakes).
+ [maurits]
+
+ * Use 1.0 as default version number for all templates. This is a more sensible
+ default than 0.1 since we start of with dev-versions anyway.
+ [wichert]
+
+ * sub-templates per ZopeSkel template: Only sub-templates related to the parent
+ template is visible with the -l option
+ [mustapha]
+
+ * added -a (--list-all) option to show all subtemplates regardless of the
+ current project. Subtemplates that are not for the type of the current
+ project are prefixed with N
+ [mustapha]
+
+ * Fixed the recreation of the paster_plugins.txt metadata file for archetype.
+ For now we have to run 2 times the egg_info command to get the paster_plugins
+ file recreated (setuptools problem: nice task to fix)
+ [mustapha]
+
+ * fixed the case of many inner packages: ask the user to choose a packe to
+ inject content into if the command is run outside of an inner package
+ [mustapha]
+
+ * make all ZopeSkel templates that inherits from BaseTemplate addcontent aware
+ [mustapha]
+
+ * Added plone_pas template for PlonePas projects and many subtemplates
+ [mustapha]
+
+ * regrouped archetype subtemplates in templates/archetype
+ [mustapha]
+
+ * added and fixed tests
+ [mustapha]
+
+
+ Version 1.10
+ ------------
+
+ * Install Plone 3.1.1 as default option.
+ [wichert]
+
+ * Fixed a problem with ZopeSkel localcommands when we have multiple
+ projects, it was getting the first directory always and sometimes
+ the package dir was not the first directory, so when running the
+ addcontent in the package it was creating the contents in the wrong
+ dir. Thanks to wichert for pointing me this file.
+ [dsa]
+
+ * Update the hosting template to make running of buildout optional.
+ [wichert]
+
+ * Update the hosting template to test if a port is already in use and
+ abort if so.
+ [wichert]
+
+ * Update the hosting template to only ask for a single base port number.
+ [wichert]
+
+ * Fix broken creation of Plone 3.1(.x) sites.
+ [wichert]
+
+
+ Version 1.9
+ -----------
+
+ * Install Plone 3.1 as default option.
+ [wichert]
+
+ * Fixed a missing 'import os' in the plone2_theme template. [davisagli]
+
+ * Fix an ambiguous question in the silva_buildout template, and update
+ the generated README file. [thefunny]
+
+
+ Version 1.8
+ -----------
+
+ * fixed the recipe template buildout.cfg generation, thanks Kai ;)
+ [tarek]
+
+ Version 1.7
+ -----------
+
+ * Update the templates to have README.txt and HISTORY.txt in valid
+ restructured format and use those as the package's long description.
+ This automatically gives packages a more readable page on PyPI
+ (and PSC with Tarek's excellent changes).
+ [wichert]
+
+ * Adjust the trove classifiers on the packages to not claim incorrect
+ frameworks: we should only claim frameworks on which the package
+ can run directly. So, for example, do not claim Zope2 of we also need
+ Plone on top of Zope2.
+ [wichert]
+
+
+ Version 1.6
+ -----------
+
+ * Add templates for a Silva buildout.
+ [thefunny]
+
+ * Add a metadata.xml to all generated GenericSetup profiles. This is
+ required by new versions of GenericSetup.
+ [wichert]
+
+ * For nested namespace packages we need to declare both namespace
+ levels as namespace packages. This is a requirement for current
+ versions of setuptools.
+ [wichert]
+
+ * Use Plone 3.0.6 as default version for new Plone hosting buildouts
+ [wichert]
+
+
+ Version 1.5.1
+ -------------
+
+ * Fix #2 (missing import in 'hosting.py') at
+ http://plone.org/products/zopeskel/issues/2
+ [nouri]
+
+ Version 1.5
+ -----------
+
+ * added a new local command into archetype template to inject
+ new content types [spanky]
+
+ * added a doctest for each template, and refactored the package
+ so we have one python module per template [tarek]
+
+ * Refactored the zc.buildout recipe to provide structured documention
+ that will render nicely on PyPI, added comments for recipe authors
+ to help writing documentation and tests and added a working doctest
+ skeleton. Implemented automatic license classifiers for common
+ licenses in the generated setup.py. The mapping is in zopeskel.base
+ and can be used for other templates also.
+ [dokai]
+
+ * The 'five:registerPackage' ZCML directive is added in a project based on the
+ 'plone' template only if the top level namespace package is not
+ called 'Products'. This avoids having the product loaded twice in Zope.
+ [davconvent]
+
+ * Added paragraph about old style Zope 2 Product installation in the
+ INSTALL.txt_tmpl file of the plone template.
+ The paragraph will be added to the installation instructions if the top
+ level namespace package is called 'Products'.
+ [davconvent]
+
+ Version 1.4
+ -----------
+
+ * Set the version number for plone.recipe.plone in a new versions part in
+ buildout.cfg. That works around a buildout bug: buildout breaks if you change
+ the revision pin for a recipe.
+ [wichert]
+
+ * Fixed bug: when running 'paster create' with --no-interactive option,
+ the package variable given in the command line is ignored.
+ [Mustapha]
+
+ Version 1.3.4
+ -------------
+
+ * Added MANIFEST.in to prevent bad releases from svn exports.
+ [fschulze]
+
+ Version 1.3.3
+ -------------
+
+ * Move to the newly released Varnish 1.1.2.
+ [wichert]
+
+ * Remove bad import which broke localcommand support.
+ [deo]
+
+ * Remove unneeded imports and whitespace cleanup.
+ [deo]
+
+ Version 1.3.2
+ -------------
+
+ * Small fix in plone3_theme that did not install correctly with easy_install
+ because of some files missing the the egg informations (added MANIFEST.in).
+ [davconvent]
+
+ Version 1.3.1
+ -------------
+
+ * Added 'addcontent' local command to make possible injecting content types
+ in ZopeSkel projects and make the Archetype template 'addcontent' aware.
+ [mustapha]
+
+ * Updated to Plone 3.0.4.
+ [fschulze]
+
+ * Rerelease because of a bad egg.
+ [fschulze]
+
+ Version 1.3
+ -----------
+
+ * added the `recipe` template
+ [tarek]
+
+ * Add Plone 2.5.5.
+ [wichert]
+
+ Version 1.2
+ -----------
+
+ * Merge a slightly stripped down version of the Jarn Plone hosting template.
+ This provides a convenient way to create a buildout for all Plone 2.5 and
+ 3.0 versions with ZEO and optional Varnish based caching.
+ [wichert]
+
+Keywords: web zope command-line skeleton project
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Framework :: Zope2
+Classifier: Framework :: Zope3
+Classifier: Framework :: Plone
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,417 @@
+BUILDBOT.txt
+CONTRIBUTORS.txt
+HISTORY.txt
+LICENSE
+MANIFEST.in
+README.txt
+setup.cfg
+setup.py
+ZopeSkel.egg-info/PKG-INFO
+ZopeSkel.egg-info/SOURCES.txt
+ZopeSkel.egg-info/dependency_links.txt
+ZopeSkel.egg-info/entry_points.txt
+ZopeSkel.egg-info/not-zip-safe
+ZopeSkel.egg-info/requires.txt
+ZopeSkel.egg-info/top_level.txt
+ez_setup/README.txt
+ez_setup/__init__.py
+zopeskel/__init__.py
+zopeskel/abstract_buildout.py
+zopeskel/abstract_zope.py
+zopeskel/archetype.py
+zopeskel/base.py
+zopeskel/basic_namespace.py
+zopeskel/basic_zope.py
+zopeskel/hosting.py
+zopeskel/interfaces.py
+zopeskel/kss_plugin.py
+zopeskel/nested_namespace.py
+zopeskel/plone.py
+zopeskel/plone25_buildout.py
+zopeskel/plone25_theme.py
+zopeskel/plone2_theme.py
+zopeskel/plone3_buildout.py
+zopeskel/plone3_portlet.py
+zopeskel/plone3_theme.py
+zopeskel/plone4_buildout.py
+zopeskel/plone_app.py
+zopeskel/plone_pas.py
+zopeskel/recipe.py
+zopeskel/silva_buildout.py
+zopeskel/ui.py
+zopeskel/vars.py
+zopeskel/zope2_buildout.py
+zopeskel/zopeskel_script.py
+zopeskel/docs/archetypes.txt
+zopeskel/docs/atschema.txt
+zopeskel/docs/basic_namespace.txt
+zopeskel/docs/basic_zope.txt
+zopeskel/docs/kss_plugin.txt
+zopeskel/docs/localcommands.txt
+zopeskel/docs/nested_namespace.txt
+zopeskel/docs/plone.txt
+zopeskel/docs/plone25_buildout.txt
+zopeskel/docs/plone25_theme.txt
+zopeskel/docs/plone2_theme.txt
+zopeskel/docs/plone3_buildout.txt
+zopeskel/docs/plone3_portlet.txt
+zopeskel/docs/plone3_theme.txt
+zopeskel/docs/plone4_buildout.txt
+zopeskel/docs/plone_app.txt
+zopeskel/docs/plone_pas.txt
+zopeskel/docs/recipe.txt
+zopeskel/docs/silva_buildout.txt
+zopeskel/localcommands/README.txt
+zopeskel/localcommands/__init__.py
+zopeskel/localcommands/archetype.py
+zopeskel/localcommands/plone.py
+zopeskel/localcommands/plone_pas.py
+zopeskel/localcommands/templates/archetype/atschema/content/+content_class_filename+.py_insert
+zopeskel/localcommands/templates/archetype/atschema/content/messagefactory_insert.txt_insert
+zopeskel/localcommands/templates/archetype/atschema/content/schema_field_bridge.txt_insert
+zopeskel/localcommands/templates/archetype/atschema/interfaces/+interface_name+.py_insert
+zopeskel/localcommands/templates/archetype/atschema/interfaces/__init__.py_insert
+zopeskel/localcommands/templates/archetype/atschema/interfaces/additional_imports.txt_insert
+zopeskel/localcommands/templates/archetype/contenttype/README.txt_insert
+zopeskel/localcommands/templates/archetype/contenttype/config.py_insert
+zopeskel/localcommands/templates/archetype/contenttype/content/+content_class_filename+.py_tmpl
+zopeskel/localcommands/templates/archetype/contenttype/content/configure.zcml_insert
+zopeskel/localcommands/templates/archetype/contenttype/interfaces/+content_class_filename+.py_tmpl
+zopeskel/localcommands/templates/archetype/contenttype/interfaces/__init__.py_insert
+zopeskel/localcommands/templates/archetype/contenttype/profiles/default/factorytool.xml_insert
+zopeskel/localcommands/templates/archetype/contenttype/profiles/default/rolemap.xml_insert
+zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types.xml_insert
+zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/+types_xml_filename+.xml_tmpl
+zopeskel/localcommands/templates/plone/browserlayer/browser/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/browserlayer/browser/configure.zcml_insert
+zopeskel/localcommands/templates/plone/browserlayer/interfaces/+interface_filename+.py_tmpl
+zopeskel/localcommands/templates/plone/browserlayer/interfaces/__init__.py_insert
+zopeskel/localcommands/templates/plone/browserlayer/profiles/default/browserlayer.xml_insert
+zopeskel/localcommands/templates/plone/form/__init__.py_insert
+zopeskel/localcommands/templates/plone/form/configure.zcml_insert
+zopeskel/localcommands/templates/plone/form/form.py
+zopeskel/localcommands/templates/plone/form/browser/+form_filename+.py_tmpl
+zopeskel/localcommands/templates/plone/form/browser/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/form/browser/configure.zcml_insert
+zopeskel/localcommands/templates/plone/formfield/browser/+form_filename+.py_insert
+zopeskel/localcommands/templates/plone/i18nlocales/configure.zcml_insert
+zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/README.txt
+zopeskel/localcommands/templates/plone/portlet/__init__.py_insert
+zopeskel/localcommands/templates/plone/portlet/configure.zcml_insert
+zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.pt_tmpl
+zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.py_tmpl
+zopeskel/localcommands/templates/plone/portlet/portlets/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/portlet/portlets/configure.zcml_insert
+zopeskel/localcommands/templates/plone/portlet/profiles/default/metadata.xml_tmpl
+zopeskel/localcommands/templates/plone/portlet/profiles/default/portlets.xml_insert
+zopeskel/localcommands/templates/plone/portlet/tests/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/portlet/tests/base_+portlet_filename+.py_tmpl
+zopeskel/localcommands/templates/plone/portlet/tests/test_+portlet_filename+.py_tmpl
+zopeskel/localcommands/templates/plone/view/__init__.py_insert
+zopeskel/localcommands/templates/plone/view/configure.zcml_insert
+zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.pt_tmpl
+zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.py_tmpl
+zopeskel/localcommands/templates/plone/view/browser/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/view/browser/configure.zcml_insert
+zopeskel/localcommands/templates/plone/zcmlmeta/configure.zcml_insert
+zopeskel/localcommands/templates/plone/zcmlmeta/meta/__init__.py_tmpl
+zopeskel/localcommands/templates/plone/zcmlmeta/meta/meta.zcml_insert
+zopeskel/localcommands/templates/plone/zcmlmeta/meta/metaconfigure.py_insert
+zopeskel/localcommands/templates/plone/zcmlmeta/meta/metadirectives.py_insert
+zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/anonymous_user_factory.py_tmpl
+zopeskel/localcommands/templates/plone_pas/authentication/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/authentication/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/authentication/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/authentication/plugins/authentication.py_tmpl
+zopeskel/localcommands/templates/plone_pas/challenge/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/challenge/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/challenge/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/challenge/plugins/challenge.py_tmpl
+zopeskel/localcommands/templates/plone_pas/credentials_reset/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_reset/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/credentials_reset.py_tmpl
+zopeskel/localcommands/templates/plone_pas/credentials_update/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_update/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/credentials_update.py_tmpl
+zopeskel/localcommands/templates/plone_pas/extraction/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/extraction/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/extraction/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/extraction/plugins/extraction.py_tmpl
+zopeskel/localcommands/templates/plone_pas/group_enumeration/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/group_enumeration/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/group_enumeration.py_tmpl
+zopeskel/localcommands/templates/plone_pas/groups/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/groups/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/groups/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/groups/plugins/groups.py_tmpl
+zopeskel/localcommands/templates/plone_pas/properties/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/properties/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/properties/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/properties/plugins/properties.py_tmpl
+zopeskel/localcommands/templates/plone_pas/role_assigner/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/role_assigner/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/role_assigner.py_tmpl
+zopeskel/localcommands/templates/plone_pas/role_enumeration/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/role_enumeration/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/role_enumeration.py_tmpl
+zopeskel/localcommands/templates/plone_pas/roles/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/roles/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/roles/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/roles/plugins/roles.py_tmpl
+zopeskel/localcommands/templates/plone_pas/update/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/update/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/update/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/update/plugins/update.py_tmpl
+zopeskel/localcommands/templates/plone_pas/user_adder/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/user_adder/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/user_adder/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/user_adder/plugins/user_adder.py_tmpl
+zopeskel/localcommands/templates/plone_pas/user_enumeration/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/user_enumeration/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/user_enumeration.py_tmpl
+zopeskel/localcommands/templates/plone_pas/user_factory/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/user_factory/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/user_factory/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/user_factory/plugins/user_factory.py_tmpl
+zopeskel/localcommands/templates/plone_pas/validation/interface.py_insert
+zopeskel/localcommands/templates/plone_pas/validation/plugin.py_insert
+zopeskel/localcommands/templates/plone_pas/validation/plugins/__init__.py_insert
+zopeskel/localcommands/templates/plone_pas/validation/plugins/validation.py_tmpl
+zopeskel/templates/archetype/CHANGES.txt_tmpl
+zopeskel/templates/archetype/CONTRIBUTORS.txt_tmpl
+zopeskel/templates/archetype/MANIFEST.in_tmpl
+zopeskel/templates/archetype/README.txt_tmpl
+zopeskel/templates/archetype/setup.py_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/README.txt_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/__init__.py_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/config.py_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/configure.zcml_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/browser/__init__.py
+zopeskel/templates/archetype/+namespace_package+/+package+/browser/configure.zcml_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/content/__init__.py
+zopeskel/templates/archetype/+namespace_package+/+package+/content/configure.zcml_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/__init__.py
+zopeskel/templates/archetype/+namespace_package+/+package+/portlets/__init__.py
+zopeskel/templates/archetype/+namespace_package+/+package+/portlets/configure.zcml_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/factorytool.xml
+zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/portlets.xml
+zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/types.xml
+zopeskel/templates/archetype/+namespace_package+/+package+/tests/__init__.py
+zopeskel/templates/archetype/+namespace_package+/+package+/tests/base.py_tmpl
+zopeskel/templates/archetype/+namespace_package+/+package+/tests/test_doctest.py_tmpl
+zopeskel/templates/basic_namespace/README.txt_tmpl
+zopeskel/templates/basic_namespace/setup.py_tmpl
+zopeskel/templates/basic_namespace/+namespace_package+/__init__.py_tmpl
+zopeskel/templates/basic_namespace/+namespace_package+/+package+/__init__.py_tmpl
+zopeskel/templates/basic_namespace/docs/HISTORY.txt_tmpl
+zopeskel/templates/basic_zope/+project+-configure.zcml_tmpl
+zopeskel/templates/basic_zope/+namespace_package+/__init__.py
+zopeskel/templates/basic_zope/+namespace_package+/+package+/README.txt_tmpl
+zopeskel/templates/basic_zope/+namespace_package+/+package+/__init__.py
+zopeskel/templates/basic_zope/+namespace_package+/+package+/configure.zcml_tmpl
+zopeskel/templates/basic_zope/+namespace_package+/+package+/tests.py_tmpl
+zopeskel/templates/basic_zope/+namespace_package+/+package+/zope2.py_tmpl
+zopeskel/templates/kss_plugin/README.txt
+zopeskel/templates/kss_plugin/setup.py_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/__init__.py
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/__init__.py
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/+namespace_package+.+namespace_package2+.+package+-configure.zcml_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/__init__.py
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.kss
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.pt_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/__init__.py
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/configure.zcml_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/zopeconfig.py_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/+package+.js_tmpl
+zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py
+zopeskel/templates/kss_plugin/docs/HISTORY.txt
+zopeskel/templates/nested_namespace/README.txt_tmpl
+zopeskel/templates/nested_namespace/setup.py_tmpl
+zopeskel/templates/nested_namespace/+namespace_package+/__init__.py_tmpl
+zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/__init__.py_tmpl
+zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
+zopeskel/templates/nested_namespace/docs/HISTORY.txt_tmpl
+zopeskel/templates/plone/setup.py_tmpl
+zopeskel/templates/plone/+namespace_package+/+package+/__init__.py_tmpl
+zopeskel/templates/plone/+namespace_package+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl
+zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
+zopeskel/templates/plone/docs/INSTALL.txt_tmpl
+zopeskel/templates/plone/docs/LICENSE.GPL
+zopeskel/templates/plone/docs/LICENSE.txt_tmpl
+zopeskel/templates/plone2.5_buildout/README.txt
+zopeskel/templates/plone2.5_theme/MANIFEST.in_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/__init__.py_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/config.py_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles.zcml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/setuphandlers.py
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/version.txt_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/Install.py_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/__init__.py
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/import_steps.xml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/CONTENT.txt_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/CONTENT.txt_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base.css.dtml
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base_properties.props_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/generated.css.dtml
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/portlets.css.dtml
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/public.css.dtml
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/CONTENT.txt_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/CONTENT.txt
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/+package+.css.dtml_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/CONTENT.txt_tmpl
+zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/CONTENT.txt
+zopeskel/templates/plone2_theme/HISTORY.txt_tmpl
+zopeskel/templates/plone2_theme/README.txt_tmpl
+zopeskel/templates/plone2_theme/__init__.py_tmpl
+zopeskel/templates/plone2_theme/config.py_tmpl
+zopeskel/templates/plone2_theme/version.txt_tmpl
+zopeskel/templates/plone2_theme/Extensions/Install.py_tmpl
+zopeskel/templates/plone2_theme/Extensions/__init__.py
+zopeskel/templates/plone2_theme/Extensions/utils.py
+zopeskel/templates/plone2_theme/skins/+package+_styles/+package+.css.dtml_tmpl
+zopeskel/templates/plone2_theme/skins/+package+_styles/base.css.dtml
+zopeskel/templates/plone2_theme/skins/+package+_styles/base_properties.props_tmpl
+zopeskel/templates/plone2_theme/skins/+package+_styles/generated.css.dtml
+zopeskel/templates/plone2_theme/skins/+package+_styles/portlets.css.dtml
+zopeskel/templates/plone2_theme/skins/+package+_styles/public.css.dtml
+zopeskel/templates/plone2_theme/tests/__init__.py
+zopeskel/templates/plone2_theme/tests/framework.py
+zopeskel/templates/plone2_theme/tests/runalltests.py
+zopeskel/templates/plone2_theme/tests/testSkeleton.py_tmpl
+zopeskel/templates/plone2_theme/tests/testStyleInstallation.py_tmpl
+zopeskel/templates/plone3_buildout/README.txt
+zopeskel/templates/plone3_buildout/bootstrap.py
+zopeskel/templates/plone3_buildout/buildout.cfg_tmpl
+zopeskel/templates/plone3_buildout/products/README.txt
+zopeskel/templates/plone3_buildout/src/README.txt
+zopeskel/templates/plone3_buildout/var/README.txt
+zopeskel/templates/plone3_portlet/setup.py_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.pt_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.py_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/metadata.xml_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/portlets.xml_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/base.py_tmpl
+zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/test_portlet.py_tmpl
+zopeskel/templates/plone3_portlet/docs/INSTALL.txt_tmpl
+zopeskel/templates/plone3_portlet/docs/LICENSE.GPL
+zopeskel/templates/plone3_portlet/docs/LICENSE.txt_tmpl
+zopeskel/templates/plone3_theme/+project+-configure.zcml_tmpl
+zopeskel/templates/plone3_theme/MANIFEST.in_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles.zcml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/setuphandlers.py_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins.zcml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/version.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/__init__.py
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/configure.zcml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/interfaces.py_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlet.pt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlets.py_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/README.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/README.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/main.css_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/README.txt
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/+namespace_package+.+package+_various.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/viewlets.xml_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/CONTENT.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/CONTENT.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/CONTENT.txt_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base.css.dtml
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base_properties.props_tmpl
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/portlets.css.dtml
+zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/public.css.dtml
+zopeskel/templates/plone4_buildout/README.txt
+zopeskel/templates/plone4_buildout/bootstrap.py
+zopeskel/templates/plone4_buildout/buildout.cfg_tmpl
+zopeskel/templates/plone4_buildout/src/README.txt
+zopeskel/templates/plone4_buildout/var/README.txt
+zopeskel/templates/plone_app/setup.py_tmpl
+zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
+zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
+zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
+zopeskel/templates/plone_app/docs/INSTALL.txt_tmpl
+zopeskel/templates/plone_app/docs/LICENSE.GPL
+zopeskel/templates/plone_app/docs/LICENSE.txt_tmpl
+zopeskel/templates/plone_hosting/README.txt
+zopeskel/templates/plone_hosting/base.cfg_tmpl
+zopeskel/templates/plone_hosting/bootstrap.py
+zopeskel/templates/plone_hosting/buildout.cfg_tmpl
+zopeskel/templates/plone_hosting/etc/supervisord.conf_tmpl
+zopeskel/templates/plone_hosting/products/README.txt
+zopeskel/templates/plone_hosting/src/README.txt
+zopeskel/templates/plone_hosting/templates/logrotate.conf
+zopeskel/templates/plone_hosting/var/README.txt
+zopeskel/templates/plone_pas/setup.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/install.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/interface.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugin.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/__init__.py
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/add_plugin.zpt_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/configure.zcml_tmpl
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/icon.gif
+zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/__init__.py_tmpl
+zopeskel/templates/plone_pas/docs/CHANGES.txt_tmpl
+zopeskel/templates/plone_pas/docs/CONTRIBUTORS.txt_tmpl
+zopeskel/templates/plone_pas/docs/INSTALL.txt_tmpl
+zopeskel/templates/plone_pas/docs/LICENSE.GPL
+zopeskel/templates/plone_pas/docs/LICENSE.txt_tmpl
+zopeskel/templates/plone_pas/docs/README.txt_tmpl
+zopeskel/templates/recipe/CHANGES.txt_tmpl
+zopeskel/templates/recipe/CONTRIBUTORS.txt_tmpl
+zopeskel/templates/recipe/README.txt_tmpl
+zopeskel/templates/recipe/bootstrap.py
+zopeskel/templates/recipe/buildout.cfg_tmpl
+zopeskel/templates/recipe/setup.py_tmpl
+zopeskel/templates/recipe/+namespace_package+/__init__.py_tmpl
+zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/__init__.py_tmpl
+zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
+zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
+zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py_tmpl
+zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/test_docs.py_tmpl
+zopeskel/templates/silva_buildout/README.txt
+zopeskel/templates/silva_buildout/bootstrap.py
+zopeskel/templates/silva_buildout/buildout.cfg_tmpl
+zopeskel/templates/silva_buildout/products/README.txt
+zopeskel/templates/silva_buildout/src/README.txt
+zopeskel/templates/silva_buildout/var/README.txt
+zopeskel/templates/zope2_buildout/README.txt
+zopeskel/templates/zope2_buildout/bootstrap.py
+zopeskel/templates/zope2_buildout/buildout.cfg_tmpl
+zopeskel/templates/zope2_buildout/products/README.txt
+zopeskel/templates/zope2_buildout/src/README.txt
+zopeskel/templates/zope2_buildout/var/README.txt
+zopeskel/tests/__init__.py
+zopeskel/tests/test_all.py
+zopeskel/tests/test_base.py
+zopeskel/tests/test_vars.py
+zopeskel/tests/test_zopeskel_script.py
+zopeskel/tests/test_zopeskeldocs.py
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/entry_points.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/entry_points.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/entry_points.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,56 @@
+
+ [paste.paster_create_template]
+ basic_namespace = zopeskel:BasicNamespace
+ nested_namespace = zopeskel:NestedNamespace
+ basic_zope = zopeskel:BasicZope
+ plone = zopeskel:Plone
+ plone_app = zopeskel:PloneApp
+ plone2_theme = zopeskel:Plone2Theme
+ plone2.5_theme = zopeskel:Plone25Theme
+ plone3_theme = zopeskel:Plone3Theme
+ plone2.5_buildout = zopeskel:Plone25Buildout
+ plone3_buildout = zopeskel:Plone3Buildout
+ plone4_buildout = zopeskel:Plone4Buildout
+ archetype = zopeskel:Archetype
+ plone3_portlet = zopeskel:Plone3Portlet
+ plone_hosting = zopeskel.hosting:StandardHosting
+ recipe = zopeskel:Recipe
+ silva_buildout = zopeskel:SilvaBuildout
+ plone_pas = zopeskel:PlonePas
+ kss_plugin = zopeskel:KssPlugin
+
+ [paste.paster_command]
+ addcontent = zopeskel.localcommands:ZopeSkelLocalCommand
+
+ [zopeskel.zopeskel_sub_template]
+ portlet = zopeskel.localcommands.plone:Portlet
+ view = zopeskel.localcommands.plone:View
+ zcmlmeta = zopeskel.localcommands.plone:ZCMLMetaDirective
+ i18nlocale = zopeskel.localcommands.plone:I18nLocale
+
+ contenttype = zopeskel.localcommands.archetype:ContentType
+ atschema = zopeskel.localcommands.archetype:ATSchemaField
+ form = zopeskel.localcommands.plone:Form
+ formfield = zopeskel.localcommands.plone:FormField
+ browserlayer = zopeskel.localcommands.plone:BrowserLayer
+
+ extraction_plugin = zopeskel.localcommands.plone_pas:ExtractionPlugin
+ authentication_plugin = zopeskel.localcommands.plone_pas:AuthenticationPlugin
+ challenge_plugin = zopeskel.localcommands.plone_pas:ChallengePlugin
+ credentials_reset_plugin = zopeskel.localcommands.plone_pas:CredentialsResetPlugin
+ user_adder_plugin = zopeskel.localcommands.plone_pas:UserAdderPlugin
+ role_assigner_plugin = zopeskel.localcommands.plone_pas:RoleAssignerPlugin
+ user_factory_plugin = zopeskel.localcommands.plone_pas:UserFactoryPlugin
+ anonymous_user_factory_plugin = zopeskel.localcommands.plone_pas:AnonymousUserFactoryPlugin
+ properties_plugin = zopeskel.localcommands.plone_pas:PropertiesPlugin
+ groups_plugin = zopeskel.localcommands.plone_pas:GroupsPlugin
+ roles_plugin = zopeskel.localcommands.plone_pas:RolesPlugin
+ update_plugin = zopeskel.localcommands.plone_pas:UpdatePlugin
+ validation_plugin = zopeskel.localcommands.plone_pas:ValidationPlugin
+ user_enumeration_plugin = zopeskel.localcommands.plone_pas:UserEnumerationPlugin
+ group_enumeration_plugin = zopeskel.localcommands.plone_pas:GroupEnumerationPlugin
+ role_enumeration_plugin = zopeskel.localcommands.plone_pas:RoleEnumerationPlugin
+
+ [console_scripts]
+ zopeskel = zopeskel.zopeskel_script:run
+
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/requires.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/requires.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/requires.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+PasteScript>=1.7.2
+Cheetah>1.0,<=2.2.1
+
+[test]
+zope.testing
+zc.buildout
+Cheetah
+PasteScript
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+zopeskel
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,19 @@
+# package
+from zopeskel.basic_namespace import BasicNamespace
+from zopeskel.plone2_theme import Plone2Theme
+from zopeskel.plone25_theme import Plone25Theme
+from zopeskel.plone_app import PloneApp
+from zopeskel.basic_zope import BasicZope
+from zopeskel.nested_namespace import NestedNamespace
+from zopeskel.plone3_buildout import Plone3Buildout
+from zopeskel.plone4_buildout import Plone4Buildout
+from zopeskel.recipe import Recipe
+from zopeskel.archetype import Archetype
+from zopeskel.plone import Plone
+from zopeskel.plone3_portlet import Plone3Portlet
+from zopeskel.plone25_buildout import Plone25Buildout
+from zopeskel.plone3_theme import Plone3Theme
+from zopeskel.silva_buildout import SilvaBuildout
+from zopeskel.plone_pas import PlonePas
+from zopeskel.kss_plugin import KssPlugin
+from zopeskel.zope2_buildout import Zope2Buildout
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,144 @@
+import copy
+
+from zopeskel.base import BaseTemplate
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import StringVar, BooleanVar, IntVar, OnOffVar, BoundedIntVar
+
+VAR_PLONEVER = StringVar(
+ 'plone_version',
+ title='Plone Version',
+ description='Plone version # to install',
+ default='3.3.5',
+ modes=(EASY,EXPERT),
+ page='Main',
+ help="""
+This is the version of Plone that will be used for this buildout.
+You should enter the version number you wish to use.
+"""
+ )
+
+VAR_Z2_INSTALL = StringVar(
+ 'zope2_install',
+ title='Zope2 Install Path',
+ description='Path to Zope2 installation; leave blank to fetch one!',
+ default='',
+ modes=(EASY,EXPERT),
+ page='Main',
+ help="""
+This is the file path to the Zope 2 installation. You can enter this
+path to use a pre-existing installation, or you can leave it blank, and
+the current Zope 2 will be downloaded and installed in your new
+buildout.
+"""
+ )
+
+VAR_PLONE_PRODUCTS = StringVar(
+ 'plone_products_install',
+ title='Plone Products Directory',
+ description='Path to Plone products; leave blank to fetch [Plone 3.0/3.1 only]',
+ modes=(EASY, EXPERT),
+ page='Main',
+ default='',
+ help="""
+Prior to Plone 3.2, Plone shipped as individual Zope products. If you
+are installing a version prior to 3.2, and you have these Plone products
+already downloaded, you can specify the path to them here. If you leave
+this blank, they will be downloaded.
+
+For Plone 3.2 and later, this option is ignored.
+"""
+ )
+
+VAR_ZOPE_USER = StringVar(
+ 'zope_user',
+ title='Initial Zope Username',
+ description='Username for Zope root admin user',
+ modes=(EASY, EXPERT),
+ page='Main',
+ default='admin',
+ help="""
+Your buildout will have a single user, with manager privileges, defined
+at the root. This option lets you select the name for this user.
+"""
+ )
+
+VAR_ZOPE_PASSWD = StringVar(
+ 'zope_password',
+ title='Initial User Password',
+ description='Password for Zope root admin user',
+ modes=(EASY, EXPERT),
+ page='Main',
+ default='',
+ help="""
+Your buildout will have a single user, "%(zope_user)s", with manager
+privileges, defined at the root. This option lets you select the initial
+password for this user. If left blank, the password will be randomly
+generated.
+"""
+ )
+
+VAR_HTTP = BoundedIntVar(
+ 'http_port',
+ title='HTTP Port',
+ description='Port that Zope will use for serving HTTP',
+ default='8080',
+ modes=(EXPERT,EASY),
+ page='Main',
+ help="""
+This options lets you select the port # that Zope will use for serving
+HTTP.
+""",
+ min=1024,
+ max=65535,
+ )
+
+VAR_DEBUG_MODE = OnOffVar(
+ 'debug_mode',
+ title='Debug Mode',
+ description='Should debug mode be "on" or "off"?',
+ default='off',
+ modes=(EXPERT,EASY),
+ page='Main',
+ help="""
+Debug mode (sometimes called "Debug/Development Mode") is the correct
+setting for running a site under development--it ensures that on-disk
+changes to templates and skin scripts are immediately visible, and
+allows use of certain add-on debugging/profiling products. Running your
+Zope in the foreground (with "bin/plonectl fg" or similar commands)
+always puts you in debug mode; this setting controls whether you are
+in debug mode even when running in the background.
+
+You should set this to "on" during development; once you are ready to
+deploy your site, you change this to "off" in your buildout.cfg.
+"""
+ )
+
+VAR_VERBOSE_SEC = OnOffVar(
+ 'verbose_security',
+ title='Verbose Security?',
+ description='Should verbose security be "on" or "off"?',
+ default='off',
+ modes=(EASY, EXPERT),
+ page='Main',
+ help="""
+Security error messages (such as "Unauthorized" errors) in Plone are
+intentionally vague--the system doesn't want to reveal too much about
+the security configuration in error messages, given that those error
+messages may be inappropriately printed out/shared/email and intercepted
+by others.
+
+"Verbose security" is a buildout setting that enables significantly more
+helpful, detailed unauthorized error messages.
+
+There may be a small security risk in leaving this enabled on a site in
+deployment; if you turn it on, you should consider turning it off.
+"""
+ )
+
+class AbstractBuildout(BaseTemplate):
+ """Abstract class for all templates that produce buildouts."""
+
+ category = "Buildout"
+
+ vars = copy.deepcopy(BaseTemplate.vars)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_zope.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_zope.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/abstract_zope.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,37 @@
+import copy
+from zopeskel.basic_namespace import BasicNamespace
+from zopeskel.nested_namespace import NestedNamespace
+from zopeskel.vars import BooleanVar
+
+VAR_ZOPE2 = BooleanVar(
+ 'zope2product',
+ title='Zope2 Product?',
+ description='Are you creating a product for Zope2/Plone or an Archetypes Product?',
+ default=True,
+ modes=(),
+ help="""
+Zope2 products will have a registration hook in their __init__.py,
+used by the Zope2 machinery to handle any required processes during
+server startup. Archetypes projects will require this, and all
+projects for Zope2/Plone will benefit from it (even if not strictly
+required, this allows the project to appear in places like the
+Zope2 Control Panel list of products).
+
+An appropriate time to choose False here would be if you are creating
+a completely Zope3-only or non-Zope project.
+"""
+ )
+
+class AbstractZope(BasicNamespace):
+ """Abstract class for Zope-based packages in a namespace."""
+ vars = copy.deepcopy(BasicNamespace.vars)
+ vars.append(VAR_ZOPE2)
+ category = "Zope Development"
+
+class AbstractNestedZope(NestedNamespace):
+ """Abstract class for Zope-based packages in a nested namespace."""
+ vars = copy.deepcopy(NestedNamespace.vars)
+ vars.append(VAR_ZOPE2)
+ category = "Zope Development"
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/archetype.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/archetype.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/archetype.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,55 @@
+import os
+import copy
+
+from zopeskel.plone import Plone
+from zopeskel.base import get_var
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import StringVar
+
+class Archetype(Plone):
+ _template_dir = 'templates/archetype'
+ summary = 'A Plone project that uses Archetypes content types'
+ help = """
+This creates a Plone project that uses Archetypes content types.
+It has local commands that will allow you to add content types
+and to add fields to your new content types.
+"""
+ post_run_msg = """
+There is a local command to add individual Archetype content types
+and to add fields to those content types. See the instructions above
+on how to use this command.
+"""
+
+ required_templates = ['plone']
+ use_cheetah = True
+ use_local_commands = True
+
+ vars = copy.deepcopy(Plone.vars)
+ vars.insert(1, StringVar(
+ 'title',
+ title='Project Title',
+ description='Title of the project',
+ modes=(EASY, EXPERT),
+ default='Example Name',
+ help="""
+This becomes the title of the project. It is used in the
+GenericSetup registration for the project and, as such, appears
+in Plone's Add/Remove products form.
+"""
+ )
+ )
+ #zope2product should always defaults to True
+ get_var(vars, 'zope2product').default = True
+ #add_profile should always default to True for archetype packages
+ get_var(vars, 'add_profile').default = True
+ #add_profile need not appear as a question for archetype packages
+ get_var(vars, 'add_profile').modes = (EXPERT,)
+
+ def post(self, command, output_dir, vars):
+ # Remove tests.py -- we already have a tests/ package
+ path = os.path.join(output_dir,
+ vars['namespace_package'],
+ vars['package'])
+ os.remove(os.path.join(path, 'tests.py'))
+
+ super(Archetype, self).post(command, output_dir, vars)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/base.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/base.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/base.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,367 @@
+import os
+from textwrap import TextWrapper
+import ConfigParser
+from ConfigParser import SafeConfigParser
+from paste.script import command
+from paste.script import pluginlib
+from paste.script import templates
+from paste.script.templates import var as base_var
+from paste.script.command import BadCommand
+from paste.script.templates import BasicPackage
+from zopeskel.vars import var, BooleanVar, StringChoiceVar
+from zopeskel.vars import EASY, EXPERT, ALL
+from zopeskel.vars import ValidationException
+
+
+LICENSE_CATEGORIES = {
+ 'DFSG' : 'License :: DFSG approved',
+ 'EFS' : 'License :: Eiffel Forum License (EFL)',
+ 'NPL' : 'License :: Netscape Public License (NPL)',
+ 'ASL' : 'License :: OSI Approved :: Apache Software License',
+ 'BSD' : 'License :: OSI Approved :: BSD License',
+ 'FDL' : 'License :: OSI Approved :: GNU Free Documentation License (FDL)',
+ 'GPL' : 'License :: OSI Approved :: GNU General Public License (GPL)',
+ 'LGPL' : 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+ 'MIT' : 'License :: OSI Approved :: MIT License',
+ 'MPL' : 'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)',
+ 'MPL11' : 'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)',
+ 'QPL' : 'License :: OSI Approved :: Qt Public License (QPL)',
+ 'ZPL' : 'License :: OSI Approved :: Zope Public License',
+ }
+
+
+def wrap_help_paras(wrapper, text):
+ """Given a string containing embedded paras, output wrapped"""
+
+ for idx, para in enumerate(text.split("\n\n")):
+ if idx:
+ print
+ print wrapper.fill(para)
+
+def get_zopeskel_prefs():
+ # http://snipplr.com/view/7354/get-home-directory-path--in-python-win-lin-other/
+ try:
+ from win32com.shell import shellcon, shell
+ homedir = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)
+ except ImportError: # quick semi-nasty fallback for non-windows/win32com case
+ homedir = os.path.expanduser("~")
+
+ # Get defaults from .zopeskel
+ config = SafeConfigParser()
+ config.read('%s/.zopeskel' % homedir)
+ return config
+
+def get_var(vars, name):
+ for var in vars:
+ if var.name == name:
+ return var
+ else:
+ raise ValueError("No such var: %r" % name)
+
+
+def update_setup_cfg(path, section, option, value):
+
+ parser = ConfigParser.ConfigParser()
+ if os.path.exists(path):
+ parser.read(path)
+
+ if not parser.has_section(section):
+ parser.add_section(section)
+
+ parser.set(section, option, value)
+ parser.write(open(path, 'w'))
+
+
+class BaseTemplate(templates.Template):
+ """Base template for all ZopeSkel templates"""
+
+ #a zopeskel template has to set this to True if it wants to use
+ #localcommand
+ use_local_commands = False
+ null_value_marker = []
+ pre_run_msg = None
+ post_run_msg = None
+
+ vars = [
+ StringChoiceVar(
+ 'expert_mode',
+ title='Expert Mode?',
+ description='What question mode would you like? (easy/expert/all)?',
+ page='Begin',
+ default='easy',
+ choices=('easy','expert','all'),
+ help="""
+In easy mode, you will be asked fewer, more common questions.
+
+In expert mode, you will be asked to answer more advanced,
+technical questions.
+
+In all mode, no questions will be skipped--even things like
+author_email, which would normally be a default set in a
+$HOME/.zopeskel file.
+"""),
+ ]
+
+ #this is just to be able to add ZopeSkel to the list of paster_plugins if
+ #the use_local_commands is set to true and to write a zopeskel section in
+ #setup.cfg file containing the name of the parent template.
+ #it will be used by addcontent command to list the apropriate subtemplates
+ #for the generated project. the post method is not a candidate because
+ #many templates override it
+ def run(self, command, output_dir, vars):
+
+ if self.use_local_commands and 'ZopeSkel' not in self.egg_plugins:
+ self.egg_plugins.append('ZopeSkel')
+
+ templates.Template.run(self, command, output_dir, vars)
+
+ setup_cfg = os.path.join(output_dir, 'setup.cfg')
+ if self.use_local_commands:
+ update_setup_cfg(setup_cfg, 'zopeskel', 'template', self.name)
+
+ def print_subtemplate_notice(self, output_dir=None):
+ """Print a notice about local commands being availabe (if this is
+ indeed the case).
+
+ Unfortunately for us, at this stage in the process, the
+ egg_info directory has not yet been created (and won't be
+ within the scope of this template running [see
+ paste.script.create_distro.py]), so we cannot show which
+ subtemplates are available.
+ """
+ plugins = pluginlib.resolve_plugins(['ZopeSkel'])
+ commands = pluginlib.load_commands_from_plugins(plugins)
+ if not commands:
+ return
+ commands = commands.items()
+ commands.sort()
+ longest = max([len(n) for n, c in commands])
+ print_commands = []
+ for name, command in commands:
+ name = name + ' ' * (longest - len(name))
+ print_commands.append(' %s %s' % (name,
+ command.load().summary))
+ print_commands = '\n'.join(print_commands)
+ print '-' * 78
+ print """\
+The project you just created has local commands. These can be used from within
+the product.
+
+usage: paster COMMAND
+
+Commands:
+%s
+
+For more information: paster help COMMAND""" % print_commands
+ print '-' * 78
+
+ def print_zopeskel_message(self, msg_name):
+ """ print a message stored as an attribute of the template
+ """
+ msg = getattr(self, msg_name, None)
+ if msg:
+ textwrapper = TextWrapper(
+ initial_indent="** ",
+ subsequent_indent="** ",
+ )
+ print "\n" + '*'*74
+ wrap_help_paras(textwrapper, msg)
+ print '*'*74 + "\n"
+
+ def pre(self, *args, **kwargs):
+ templates.Template.pre(self, *args, **kwargs)
+
+ def get_template_stack(self, command):
+ """ return a list of the template objects being run through in the given command
+ """
+ asked_tmpls = command.options.templates or ['basic_package']
+ templates = []
+ for tmpl_name in asked_tmpls:
+ command.extend_templates(templates, tmpl_name)
+ return [tmpl_obj for tmpl_name, tmpl_obj in templates]
+
+ def get_position_in_stack(self, stack):
+ """ return the index of the currently running template in the overall stack
+ """
+ class_stack = [t.__class__ for t in stack]
+
+ return class_stack.index(self.__class__)
+
+ def should_print_subcommands(self, command):
+ """ return true or false
+
+ if this template has subcommands _and_ is the last template
+ to be run through that does, go ahead and return true, otherwise
+ return false
+ """
+ if not getattr(self, 'use_local_commands', False):
+ return False
+ # we have local commands for this template, is it the last one for
+ # which this is true?
+ stack = self.get_template_stack(command)
+ index = self.get_position_in_stack(stack)
+ remaining_stack = stack[index+1:]
+ have_subcommands_left = [getattr(t, 'use_local_commands', False)
+ for t in remaining_stack]
+ if True in have_subcommands_left:
+ return False
+
+ return True
+
+ def post(self, command, output_dir, vars):
+ if self.should_print_subcommands(command):
+ self.print_subtemplate_notice()
+ templates.Template.post(self, command, output_dir, vars)
+ # at the very end of it all, print the post_run_msg so we can
+ # inform users of important information.
+ self.print_zopeskel_message('post_run_msg')
+
+ def _filter_for_modes(self, mode, expected_vars):
+ """Filter questions down according to our mode.
+
+ ALL = show all questions
+ EASY, EXPERT = show just those
+ """
+
+ if mode == ALL: return {}
+
+ hidden = {}
+
+ for var in expected_vars:
+ # if in expert mode, hide vars not for expert mode
+ if mode not in var.modes:
+ hidden[var.name] = var.default
+
+ return hidden
+
+ def override_package_names_defaults(self, vars, expect_vars):
+ """Override package names defaults using project title.
+
+ Override the default for namespace_package, namespace_package2,
+ and package from splitting the project title--if ndots is
+ specified by this template.
+
+ This is helpful for new users, who find it confusing to provide
+ a package name like "mycompany.theme.blue" and then have to
+ (slightly-redundantly) specify namespace_package=mycompany,
+ namespace_package2=theme, package=blue.
+ """
+
+ ndots = getattr(self, 'ndots', None)
+ if ndots:
+ parts = vars['project'].split(".")
+ if ndots >= 1 and len(parts) >= 1:
+ get_var(expect_vars, 'namespace_package').default = parts[0]
+ if ndots >= 2 and len(parts) >= 2:
+ get_var(expect_vars, 'namespace_package2').default = parts[1]
+ package_name = parts[-1]
+ get_var(expect_vars, 'package').default = package_name
+
+ def check_vars(self, vars, cmd):
+ # if we need to notify users of anything before they start this
+ # whole process, we can do it here.
+ self.print_zopeskel_message('pre_run_msg')
+
+ # Copied and modified from PasteScript's check_vars--
+ # the method there wasn't hookable for the things
+ # we need -- question posing, validation, etc.
+ #
+ # Admittedly, this could be merged into PasteScript,
+ # but it was decided it was easier to limit scope of
+ # these changes to ZopeSkel, as other projects may
+ # use PasteScript in very different ways.
+
+
+ cmd._deleted_once = 1 # don't re-del package
+
+ textwrapper = TextWrapper(
+ initial_indent="| ",
+ subsequent_indent="| ",
+ )
+
+ # now, mostly copied direct from paster
+ expect_vars = self.read_vars(cmd)
+ if not expect_vars:
+ # Assume that variables aren't defined
+ return vars
+ converted_vars = {}
+ errors = []
+
+ config = get_zopeskel_prefs()
+ # pastescript allows one to request more than one template (multiple
+ # -t options at the command line) so we will get a list of templates
+ # from the cmd's options property
+ requested_templates = cmd.options.templates
+ for var in expect_vars:
+ for template in requested_templates:
+ if config.has_option(template, var.name):
+ var.default = config.get(template, var.name)
+ break
+ else:
+ # Not found in template section, now look explicitly
+ # in DEFAULT section
+ if config.has_option('DEFAULT', var.name):
+ var.default = config.get('DEFAULT', var.name)
+
+ self.override_package_names_defaults(vars, expect_vars)
+
+ unused_vars = vars.copy()
+
+ for var in expect_vars:
+ if var.name not in unused_vars:
+ if cmd.interactive:
+ prompt = var.pretty_description()
+ response = self.null_value_marker
+ while response is self.null_value_marker:
+ response = cmd.challenge(prompt, var.default, var.should_echo)
+ if response == '?':
+ help = var.further_help().strip() % converted_vars
+ print
+ wrap_help_paras(textwrapper, help)
+ print
+ response = self.null_value_marker;
+ if response is not self.null_value_marker:
+ try:
+ response = var.validate(response)
+ except ValidationException, e:
+ print e
+ response = self.null_value_marker;
+ converted_vars[var.name] = response
+ elif var.default is command.NoDefault:
+ errors.append('Required variable missing: %s'
+ % var.full_description())
+ else:
+ converted_vars[var.name] = var.default
+ else:
+ converted_vars[var.name] = unused_vars.pop(var.name)
+
+ # filter the vars for mode.
+ if var.name == 'expert_mode':
+ expert_mode = converted_vars['expert_mode']
+ hidden = self._filter_for_modes(expert_mode, expect_vars)
+ unused_vars.update(hidden)
+
+ if errors:
+ raise command.BadCommand(
+ 'Errors in variables:\n%s' % '\n'.join(errors))
+ converted_vars.update(unused_vars)
+ vars.update(converted_vars)
+
+ result = converted_vars
+
+ return result
+
+ @property
+ def pages(self):
+ pages = []
+ page_map = {}
+ for question in self.vars:
+ name = question.page
+ if name in page_map:
+ page = page_map[name]
+ page['vars'].append(question)
+ else:
+ page = {'name': name, 'vars': [question]}
+ pages.append(page)
+ page_map[name] = page
+ return pages
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_namespace.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_namespace.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_namespace.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,191 @@
+import copy
+from zopeskel.vars import var, DottedVar, StringVar, BooleanVar, TextVar
+from zopeskel.base import BaseTemplate
+from zopeskel.base import EASY, EXPERT
+
+class BasicNamespace(BaseTemplate):
+ _template_dir = 'templates/basic_namespace'
+ summary = "A basic Python project with a namespace package"
+ ndots = 1
+ help = """
+This creates a Python project without any Zope or Plone features.
+"""
+ category = "Core Python"
+
+ required_templates = []
+ use_cheetah = True
+ vars = copy.deepcopy(BaseTemplate.vars)
+ vars += [
+ DottedVar(
+ 'namespace_package',
+ title='Namespace Package Name',
+ description='Name of outer namespace package',
+ default='plone',
+ modes=(EXPERT,),
+ page='Namespaces',
+ help="""
+This is the name of the outer package (Python folder) for this project.
+For example, in 'Products.PloneFormGen', this would be 'Products'.
+This will often be (for Plone products) 'Products'; it may also be
+the name of your company/project, or a common-style name like
+(for Plone products) 'collective'.
+
+Note that, for some templates, there may be two namespaces, rather
+than one (to create eggs with names like 'plone.app.blog')--in this
+case, this would be 'plone', the first of the enclosing namespaces.
+ """
+ ),
+
+ DottedVar(
+ 'package',
+ title='Package Name',
+ description='Name of the inner namespace package',
+ default='example',
+ modes=(EXPERT,),
+ page='Namespaces',
+ help="""
+This is the name of the innermost package (Python folder) for this project.
+For example, in 'Products.PloneFormGen', this would be 'PloneFormGen'.
+
+Note that, for some templates, there may be only a package name without
+a namespace package around it--in this case, this would be just the name
+of the package.
+"""
+ ),
+
+ StringVar(
+ 'version',
+ title='Version',
+ description='Version number for project',
+ default='1.0',
+ modes=(EASY, EXPERT),
+ page='Metadata',
+ help="""
+This becomes the version number of the created package. It will be set
+in the egg's setup.py, and may be referred to in other places in the
+generated project.
+"""
+ ),
+
+ StringVar(
+ 'description',
+ title='Description',
+ description='One-line description of the project',
+ default='',
+ modes=(EASY, EXPERT),
+ page='Metadata',
+ help="""
+This should be a single-line description of your project. It will be
+used in the egg's setup.py, and, for Zope/Plone projects, may be used
+in the GenericSetup profile description.
+"""
+ ),
+
+ TextVar(
+ 'long_description',
+ title='Long Description',
+ description='Multi-line description (in ReST)',
+ default='',
+ modes=(),
+ page='Metadata',
+ help="""
+This should be a full description for your project. It will be
+used in the egg's setup.py.
+
+It should be entered in 'restructured text' format; for information,
+see http://docutils.sourceforge.net/rst.html).
+"""
+ ),
+
+ StringVar(
+ 'author',
+ title='Author',
+ description='Name of author for project',
+ modes=(),
+ page='Metadata',
+ help="""
+This should be the name of the author of this project. It will be used
+in the egg's setup.py, and, for some templates, in the generated
+documentation/README files.
+"""
+ ),
+
+ StringVar(
+ 'author_email',
+ title='Author Email',
+ description='Email of author for project',
+ modes=(),
+ page='Metadata',
+ help="""
+This should be the name of the author of this project. It will be used
+in the egg's setup.py, and, for some templates, in the generated
+documentation/README files.
+"""
+ ),
+
+ StringVar('keywords',
+ title='Keywords',
+ description='List of keywords, space-separated',
+ modes=(),
+ page='Metadata',
+ help="""
+This should be the list of keywords for this project. This will be
+used in the egg's setup.py (and, if this egg is later published on
+PyPI, will be used to categorize the project).
+"""
+ ),
+
+ StringVar(
+ 'url',
+ title='Project URL',
+ description='URL of the homepage for this project',
+ modes=(),
+ page='Metadata',
+ default='http://svn.plone.org/svn/collective/',
+ help="""
+This should be a URL for the homepage for this project (if applicable).
+It will be used in the egg's setup.py.
+"""
+ ),
+
+ StringVar(
+ 'license_name',
+ title='Project License',
+ description='Name of license for the project',
+ default='GPL',
+ modes=(),
+ page='Metadata',
+ help="""
+The license that this project is issued under. It will be used in the
+egg's setup.py.
+
+Common choices here are 'GPL' (for the GNU General Public License),
+'ZPL' (for the Zope Public License', and 'BSD' (for the BSD license).
+"""
+ ),
+
+ BooleanVar(
+ 'zip_safe',
+ title='Zip-Safe?',
+ description='Can this project be used as a zipped egg? (true/false)',
+ default=False,
+ modes=(),
+ page='Metadata',
+ help="""
+Some eggs can be used directly by Python in zipped format; others must
+be unzipped so that their contents can be properly used. Zipped eggs
+are smaller and may be easier to redistribute.
+
+Most Zope/Plone projects cannot be used in zipped format; if unsure,
+the safest answer is False.
+ """
+ ),
+ ]
+
+ def check_vars(self, vars, command):
+ if not command.options.no_interactive and \
+ not hasattr(command, '_deleted_once'):
+ del vars['package']
+ command._deleted_once = True
+ return super(BasicNamespace, self).check_vars(vars, command)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_zope.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_zope.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/basic_zope.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+import copy
+from zopeskel.base import get_var
+from zopeskel.vars import var, BooleanVar
+from zopeskel import abstract_zope
+
+
+class BasicZope(abstract_zope.AbstractZope):
+ _template_dir = 'templates/basic_zope'
+ summary = "A Zope project"
+ help = """
+This creates a Zope project without any specific Plone features.
+"""
+ required_templates = ['basic_namespace']
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_zope.AbstractZope.vars)
+ get_var(vars, 'namespace_package').default = 'myzopelib'
+ get_var(vars, 'package').default = 'example'
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/archetypes.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/archetypes.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/archetypes.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,40 @@
+==================
+archetype template
+==================
+
+Use paster::
+
+ >>> paster('create -t archetype plone.example --no-interactive')
+ paster create -t archetype plone.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.example',
+ ... 'plone', 'example')
+ >>> ls(package_dir)
+ README.txt
+ __init__.py
+ browser
+ config.py
+ configure.zcml
+ content
+ interfaces
+ portlets
+ profiles
+ tests
+
+Let's check the 'content' folder content::
+
+ >>> content_dir = os.path.join(package_dir, 'content')
+ >>> ls(content_dir)
+ __init__.py
+ configure.zcml
+
+Let's check the 'tests' folder content::
+
+ >>> tests_dir = os.path.join(package_dir, 'tests')
+ >>> ls(tests_dir)
+ __init__.py
+ base.py
+ test_doctest.py
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/atschema.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/atschema.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/atschema.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,68 @@
+================
+atschema builder
+================
+
+Build an archetype from scratch, and use paster to add a contenttype::
+
+ >>> paster('create -t archetype plone.example --no-interactive')
+ paster create -t archetype plone.example --no-interactive
+ ...
+ >>> cd('plone.example')
+ >>> paster('addcontent contenttype --no-interactive') # doctest: +ELLIPSIS
+ paster addcontent contenttype --no-interactive
+ ...
+ Inserting from types.xml_insert into...
+ ...
+ >>> content_dir = os.path.join('plone', 'example', 'content')
+ >>> interfaces_dir = os.path.join('plone', 'example', 'interfaces')
+
+Check for the file::
+
+ >>> ls(content_dir)
+ __init__.py
+ configure.zcml
+ exampletype.py
+
+Check to see that atschema is available::
+
+ >>> paster('addcontent --list')
+ paster addcontent --list
+ ...
+ atschema: A handy AT schema builder
+ ...
+ <BLANKLINE>
+
+Now add a schema field via paster::
+
+ >>> paster('addcontent atschema --no-interactive')
+ paster addcontent atschema --no-interactive
+ ...
+
+Check that the schema and was inserted and that related imports were inserted::
+
+ >>> cat(os.path.join(content_dir, 'exampletype.py'))
+ """Definition of the Example Type content type
+ """
+ ...
+ from plone.example import exampleMessageFactory as _
+ ...
+ atapi.StringField(...
+ ...
+ atapi.registerType(ExampleType, PROJECTNAME)
+ <BLANKLINE>
+
+Check that appropriate imports and a schema field were added to the interface file::
+
+ >>> cat(os.path.join(interfaces_dir, 'exampletype.py'))
+ from zope.interface import Interface
+ ...
+ from zope import schema
+ <BLANKLINE>
+ from plone.example import exampleMessageFactory as _
+ ...
+ newfield = schema.TextLine(
+ ...
+ <BLANKLINE>
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_namespace.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_namespace.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_namespace.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+========================
+basic_namespace template
+========================
+
+Use paster::
+
+ >>> paster('create -t basic_namespace plone.example --no-interactive')
+ paster create -t basic_namespace plone.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.example',
+ ... 'plone', 'example')
+ >>> ls(package_dir)
+ __init__.py
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_zope.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_zope.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/basic_zope.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,23 @@
+========================
+basic_namespace template
+========================
+
+Use paster::
+
+ >>> paster('create -t basic_zope basiczope.example --no-interactive')
+ paster create -t basic_zope basiczope.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('basiczope.example',
+ ... 'basiczope', 'example')
+ >>> ls(package_dir)
+ README.txt
+ __init__.py
+ configure.zcml
+ tests.py
+ zope2.py
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/kss_plugin.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/kss_plugin.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/kss_plugin.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,43 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t kss_plugin kss.plugin.example --no-interactive')
+ paster create -t kss_plugin kss.plugin.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> ls('kss.plugin.example')
+ README.txt
+ docs
+ kss
+ kss.plugin.example.egg-info
+ setup.py
+
+ >>> ls('kss.plugin.example', 'kss')
+ __init__.py
+ plugin
+
+ >>> ls('kss.plugin.example', 'kss', 'plugin')
+ __init__.py
+ example
+
+ >>> ls('kss.plugin.example', 'kss', 'plugin', 'example')
+ 3rd_party
+ __init__.py
+ configure.zcml
+ demo
+ javascript
+ kss.plugin.example-configure.zcml
+ tests
+
+ >>> ls('kss.plugin.example', 'kss', 'plugin', 'example', 'demo')
+ __init__.py
+ configure.zcml
+ example.kss
+ example.pt
+ zopeconfig.py
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/localcommands.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/localcommands.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/localcommands.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,235 @@
+Local commands:
+==============
+
+PasteScript supports the notion of local commands. These are commands
+that can be executed from within a project. See the ``localcommands``
+directory in ZopeSkel for more information.
+
+
+Plone
+-----
+
+Check that the `addcontent` command is not globaly available::
+
+ >>> help_text = read_sh('paster help')
+ >>> help_text.find('addcontent') == -1
+ True
+
+`addcontent` is active for all ZopeSkel templates that have ``use_local_commands``
+attribute set to true.
+
+Let's for example take the plone template::
+
+ >>> paster('create -t plone plone.example --no-interactive')
+ paster create -t plone plone.example --no-interactive
+ ...
+ >>> cd('plone.example')
+ >>> paster('help')
+ paster help
+ ...
+ <BLANKLINE>
+ ZopeSkel local commands:
+ addcontent Adds plone content types to your project
+ <BLANKLINE>
+ <BLANKLINE>
+
+What sub-templates are available for a plone based project ?::
+
+ >>> paster('addcontent --list')
+ paster addcontent --list
+ Available templates:
+ browserlayer: A Plone browserlayer
+ form: A form skeleton
+ formfield: Schema field for a form
+ i18nlocale: An i18n locale directory structure
+ portlet: A Plone 3 portlet
+ view: A browser view skeleton
+ zcmlmeta: A ZCML meta directive skeleton
+
+
+Now we can add a portlet to our project::
+
+ >>> paster('addcontent --no-interactive portlet')
+ paster addcontent --no-interactive portlet
+ Inserting from __init__.py_insert into ...
+ Inserting from configure.zcml_insert into ...
+ Recursing into portlets
+ ...
+
+Test if we have the new files::
+
+ >>> ls('plone', 'example', 'portlets')
+ __init__.py
+ configure.zcml
+ exampleportlet.pt
+ exampleportlet.py
+ >>> ls('plone', 'example', 'tests')
+ __init__.py
+ base_exampleportlet.py
+ test_exampleportlet.py
+
+Check that the existing files like profile/portlets are updated::
+
+ >>> cat('plone', 'example', 'profiles', 'default', 'portlets.xml')
+ <?xml version="1.0"?>
+ ...
+ <portlet
+ addview="plone.example.portlets.ExamplePortlet"
+ title="Example portlet"
+ description=""
+ i18n:attributes="title; description"
+ />
+ ...
+
+Adding a portlet via localcommand should update __init__.py to include
+MessageFactory as well as defining a message factory for this project:
+
+ >>> cat('plone', 'example', '__init__.py')
+ # -*- extra stuff goes here -*-
+ from zope.i18nmessageid import MessageFactory
+ <BLANKLINE>
+ exampleMessageFactory = MessageFactory('plone.example')
+ ...
+
+The portlet localcommand should also update the root-level configure.zcml to insert an include package directive. Make sure it has:
+
+ >>> cat('plone', 'example', 'configure.zcml')
+ <configure
+ ...
+ <BLANKLINE>
+ <include package=".portlets" />
+ <BLANKLINE>
+ ...
+
+
+Now add a new i18n locales directory structure to the project::
+
+ >>> paster('addcontent --no-interactive i18nlocale')
+ paster addcontent --no-interactive i18nlocale
+ Inserting from configure.zcml_insert into ...
+ Recursing into locales
+ ...
+
+Test if we have the new files::
+
+ >>> ls('plone', 'example', 'locales')
+ nl
+
+The i18nlocale localcommand should also update the root-level configure.zcml to register the locales directory translations. Make sure it has:
+
+ >>> cat('plone', 'example', 'configure.zcml')
+ <configure
+ ...
+ <BLANKLINE>
+ <i18n:registerTranslations directory="locales" />
+ <BLANKLINE>
+ ...
+
+Let's try to add a form to our project::
+
+ >>> paster('addcontent --no-interactive form')
+ paster addcontent --no-interactive form
+ Inserting from __init__.py_insert into ...
+ ...
+ Recursing into browser
+ ...
+
+Test if we have the new files::
+
+ >>> ls('plone', 'example', 'browser')
+ __init__.py
+ configure.zcml
+ exampleform.py
+
+The form localcommand should also update the root-level configure.zcml to insert an include package directive. Make sure it has:
+
+ >>> cat('plone', 'example', 'configure.zcml')
+ <configure
+ ...
+ <BLANKLINE>
+ <include package=".browser" />
+ <BLANKLINE>
+ ...
+
+
+Let's try to add a browserlayer to our project::
+ >>> paster('addcontent --no-interactive browserlayer')
+ paster addcontent --no-interactive browserlayer
+ A BrowserLayer is generally used in packages to be installed in a Plone Site.
+ If you didn't choose Register Profile option when creating this package
+ you should probably add a <genericsetup:registerProfile /> directive in
+ the main configure.zcml.
+ <BLANKLINE>
+ Recursing into browser
+ ...
+ Inserting from configure.zcml_insert into ...
+ Recursing into interfaces
+ ...
+ Recursing into profiles
+ Recursing into default
+ ...
+
+Test if we have the new files::
+ >> ls('plone', 'example', 'browser')
+ __init__.py
+ configure.zcml
+
+ >> ls('plone', 'example', 'interfaces')
+ __init__.py
+ ploneexample.py
+
+Check that the existing files like profile/browserlayer are updated::
+ >>> cat('plone', 'example', 'profiles', 'default', 'browserlayer.xml')
+ <?xml version="1.0"?>
+ ...
+ <layer name="PloneExample"
+ interface="plone.example.interfaces.ploneexamplelayer.IPloneExampleLayer" />
+ ...
+
+ >>> cat('plone', 'example', 'browser', 'configure.zcml')
+ <configure
+ ...
+ <include package="plone.browserlayer" />
+ ...
+
+ >> cat('plone', 'example', 'interfaces', 'packagenamelayer.py')
+ ...
+ class IPloneExampleLayer(Interface):
+ ...
+
+Go back to the top level directory to have a more or less clean slate
+for the following tests.
+ >>> cd('..')
+
+Archetype
+---------
+
+An archetype based project has other localcommands available::
+
+ >>> paster('create -t archetype archetype.example --no-interactive')
+ paster create -t archetype archetype.example --no-interactive
+ ...
+ >>> cd('archetype.example')
+ >>> paster('help')
+ paster help
+ ...
+ <BLANKLINE>
+ ZopeSkel local commands:
+ addcontent Adds plone content types to your project
+ <BLANKLINE>
+ <BLANKLINE>
+
+What sub-templates are available for an archetype based project ?::
+
+ >>> paster('addcontent --list')
+ paster addcontent --list
+ Available templates:
+ atschema: A handy AT schema builder
+ browserlayer: A Plone browserlayer
+ contenttype: A content type skeleton
+ form: A form skeleton
+ formfield: Schema field for a form
+ i18nlocale: An i18n locale directory structure
+ portlet: A Plone 3 portlet
+ view: A browser view skeleton
+ zcmlmeta: A ZCML meta directive skeleton
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/nested_namespace.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/nested_namespace.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/nested_namespace.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+=========================
+nested_namespace template
+=========================
+
+Use paster::
+
+ >>> paster('create -t nested_namespace plone.app.example --no-interactive')
+ paster create -t nested_namespace plone.app.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.app.example',
+ ... 'plone', 'app', 'example')
+ >>> ls(package_dir)
+ __init__.py
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,63 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone plone.example --no-interactive')
+ paster create -t plone plone.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.example',
+ ... 'plone', 'example')
+ >>> ls(package_dir)
+ __init__.py
+ configure.zcml
+ tests.py
+
+If we state that we want a GS profile, the template should create that for us::
+
+ >>> paster('create -t plone plone.example --no-interactive add_profile=True')
+ paster create -t plone plone.example --no-interactive add_profile=True
+ ...
+
+Check to ensure that the package structure is correct::
+
+ >>> package_dir = os.path.join('plone.example',
+ ... 'plone', 'example')
+ >>> ls(package_dir)
+ __init__.py
+ configure.zcml
+ profiles
+ tests.py
+
+The profiles directory should contain only a 'default' folder with a metadata.xml file inside::
+
+ >>> ls(package_dir, 'profiles')
+ default
+ >>> ls(package_dir, 'profiles', 'default')
+ metadata.xml
+
+We need to verify that the metadata.xml file looks correct and that the configure.zcml file now contains a profile registration::
+
+ >>> cat(package_dir, 'profiles', 'default', 'metadata.xml')
+ <?xml version="1.0"?>
+ <metadata>
+ <version>1000</version>
+ </metadata>
+ <BLANKLINE>
+ >>> cat(package_dir, 'configure.zcml')
+ <configure
+ ...
+ <genericsetup:registerProfile
+ name="default"
+ title="plone.example"
+ directory="profiles/default"
+ description="Installs the plone.example package"
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+ ...
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_buildout.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_buildout.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_buildout.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone2.5_buildout buildout --no-interactive')
+ paster create -t plone2.5_buildout buildout --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'buildout'
+ >>> ls(package_dir)
+ README.txt
+ bootstrap.py
+ buildout.cfg
+ products
+ src
+ var
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_theme.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_theme.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone25_theme.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,37 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone2.5_theme Products.ploneexample --no-interactive')
+ paster create -t plone2.5_theme Products.ploneexample --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'Products.ploneexample'
+ >>> ls(package_dir)
+ MANIFEST.in
+ Products
+ Products.ploneexample.egg-info
+ README.txt
+ docs
+ setup.cfg
+ setup.py
+
+And inside the package::
+
+ >>> package_dir = os.path.join('Products.ploneexample',
+ ... 'Products', 'ploneexample')
+ >>> ls(package_dir)
+ Extensions
+ __init__.py
+ config.py
+ configure.zcml
+ profiles
+ profiles.zcml
+ setuphandlers.py
+ skins
+ tests.py
+ version.txt
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone2_theme.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone2_theme.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone2_theme.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone2_theme ExampleTheme --no-interactive')
+ paster create -t plone2_theme ExampleTheme --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'ExampleTheme'
+ >>> ls(package_dir)
+ Extensions
+ HISTORY.txt
+ README.txt
+ __init__.py
+ config.py
+ skins
+ tests
+ version.txt
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_buildout.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_buildout.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_buildout.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone3_buildout buildout --no-interactive')
+ paster create -t plone3_buildout buildout --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'buildout'
+ >>> ls(package_dir)
+ README.txt
+ bootstrap.py
+ buildout.cfg
+ products
+ src
+ var
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_portlet.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_portlet.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_portlet.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,19 @@
+========================
+plone template
+=======================
+
+Use paster::
+
+ >>> paster('create -t plone3_portlet collective.portlet.example --no-interactive')
+ paster create -t plone3_portlet collective.portlet.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'collective.portlet.example'
+ >>> ls(package_dir)
+ README.txt
+ collective
+ collective.portlet.example.egg-info
+ docs
+ setup.py
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_theme.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_theme.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone3_theme.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,39 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone3_theme plonetheme.example --no-interactive')
+ paster create -t plone3_theme plonetheme.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'plonetheme.example'
+ >>> ls(package_dir)
+ MANIFEST.in
+ README.txt
+ docs
+ plonetheme
+ plonetheme.example-configure.zcml
+ plonetheme.example.egg-info
+ setup.cfg
+ setup.py
+
+And the actual content of the theme::
+
+ >>> package_dir = os.path.join('plonetheme.example',
+ ... 'plonetheme', 'example')
+ >>> ls(package_dir)
+ __init__.py
+ browser
+ configure.zcml
+ locales
+ profiles
+ profiles.zcml
+ setuphandlers.py
+ skins
+ skins.zcml
+ tests.py
+ version.txt
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone4_buildout.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone4_buildout.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone4_buildout.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t plone4_buildout buildout --no-interactive')
+ paster create -t plone4_buildout buildout --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'buildout'
+ >>> ls(package_dir)
+ README.txt
+ bootstrap.py
+ buildout.cfg
+ src
+ var
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_app.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_app.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_app.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+========================
+plone_app template
+=======================
+
+Use paster::
+
+ >>> paster('create -t plone_app plone.app.example --no-interactive')
+ paster create -t plone_app plone.app.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.app.example',
+ ... 'plone', 'app', 'example')
+ >>> ls(package_dir)
+ __init__.py
+ configure.zcml
+ tests.py
+ version.txt
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_pas.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_pas.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/plone_pas.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,25 @@
+==================
+plone_pas template
+==================
+
+Use paster::
+
+ >>> paster('create -t plone_pas plone.pas.example --no-interactive')
+ paster create -t plone_pas plone.pas.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.pas.example',
+ ... 'plone', 'pas', 'example')
+ >>> ls(package_dir)
+ README.txt
+ __init__.py
+ browser
+ configure.zcml
+ install.py
+ interface.py
+ plugin.py
+ plugins
+ tests.py
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/recipe.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/recipe.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/recipe.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,67 @@
+===============
+recipe template
+===============
+
+Use paster::
+
+ >>> paster('create -t recipe plone.recipe.example --no-interactive')
+ paster create -t recipe plone.recipe.example --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = os.path.join('plone.recipe.example',
+ ... 'plone', 'recipe', 'example')
+ >>> ls(package_dir)
+ README.txt
+ __init__.py
+ tests
+
+Let's check how the recipe looks like::
+
+ >>> recipe = open(os.path.join(package_dir, '__init__.py')).read()
+ >>> print recipe
+ # -*- coding: utf-8 -*-
+ """Recipe example"""
+ <BLANKLINE>
+ class Recipe(object):
+ """zc.buildout recipe"""
+ <BLANKLINE>
+ def __init__(self, buildout, name, options):
+ self.buildout, self.name, self.options = buildout, name, options
+ <BLANKLINE>
+ def install(self):
+ """Installer"""
+ # XXX Implement recipe functionality here
+ <BLANKLINE>
+ # Return files that were created by the recipe. The buildout
+ # will remove all returned files upon reinstall.
+ return tuple()
+ <BLANKLINE>
+ def update(self):
+ """Updater"""
+ pass
+
+Now let's try to run the recipe own tests::
+
+ >>> recipe_dir = 'plone.recipe.example'
+ >>> cd(recipe_dir)
+ >>> import sys
+ >>> python_ = sys.executable
+ >>> res = read_sh('%s setup.py test' % python_).strip().lower()
+ >>> 'doctest: readme.txt' in res
+ True
+ >>> 'ran 1 test' in res
+ True
+ >>> 'ok' in res[:-10]
+ True
+
+And the dedicated buildout `test` script (to be fixed)::
+
+ >> null = os.chdir(recipe_dir)
+ >> null = read_sh('%s bootstrap.py' % python_)
+ >> null = read_sh(os.path.join('bin', 'buildout'))
+ >> res = read_sh(os.path.join('bin', 'test'))
+ >> print res
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/silva_buildout.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/silva_buildout.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/docs/silva_buildout.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+==============
+plone template
+==============
+
+Use paster::
+
+ >>> paster('create -t silva_buildout buildout --no-interactive')
+ paster create -t silva_buildout buildout --no-interactive
+ ...
+
+Let's check the content::
+
+ >>> package_dir = 'buildout'
+ >>> ls(package_dir)
+ README.txt
+ bootstrap.py
+ buildout.cfg
+ products
+ src
+ var
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/hosting.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/hosting.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/hosting.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,203 @@
+import errno
+import os
+import socket
+import subprocess
+import sys
+import copy
+
+from paste.script import templates
+from zopeskel.base import BadCommand
+from zopeskel.base import BaseTemplate, EASY, EXPERT
+from zopeskel.vars import var, IntVar, BooleanVar, StringVar
+from zopeskel import abstract_buildout
+
+plone25s = {
+ "2.5.5": "https://launchpad.net/plone/2.5/2.5.5/+download/Plone-2.5.5.tar.gz",
+ "2.5.4": "https://launchpad.net/plone/2.5/2.5.4/+download/Plone-2.5.4-2.tar.gz",
+ "2.5.3": "https://launchpad.net/plone/2.5/2.5.3/+download/Plone-2.5.3-final.tar.gz",
+ "2.5.2": "http://plone.googlecode.com/files/Plone-2.5.2-1.tar.gz",
+ "2.5.1": "http://heanet.dl.sourceforge.net/sourceforge/plone/Plone-2.5.1-final.tar.gz",
+ "2.5" : "http://heanet.dl.sourceforge.net/sourceforge/plone/Plone-2.5.tar.gz",
+ }
+
+class StandardHosting(abstract_buildout.AbstractBuildout):
+ _template_dir = "templates/plone_hosting"
+ use_cheetah = True
+ summary = "Plone hosting: buildout with ZEO and Plone versions below 3.2"
+ required_templates = []
+ help = """
+This template helps you to create an entire zope hosting setup, including
+ZEO and a single Zope client instance. If you desire, it can also install
+and set up the Varnish Caching/Proxy Server.
+
+Please Note:
+Due to changes in the packaging of Plone, this template is not suitable
+for versions of Plone beyond 3.1.7. If you are trying to use a later
+version of plone, you will need to edit the buildout resulting from this
+template in order to have it work correctly. Information related to these
+issues may be found here:
+
+http://plone.org/documentation/kb/repair-a-plone-3.1-buildout
+
+and here:
+
+http://plone.org/products/zopeskel/issues/25
+"""
+
+ vars = copy.deepcopy(abstract_buildout.AbstractBuildout.vars);
+ vars = [
+
+ abstract_buildout.VAR_ZOPE_USER,
+ abstract_buildout.VAR_ZOPE_PASSWD,
+
+ IntVar(
+ "base_port",
+ title="Base Port #",
+ description="# to use as base for Zope/ZEO/proxy ports",
+ modes=(EASY, EXPERT),
+ page="Main",
+ default=8000,
+ help="""
+For standardization, rather than selecting ports for Zope, ZEO, and
+a proxy individually, these are tied together numerically.
+
+ZEO port = Base + 0 | Proxy port = Base + 1 | HTTP port = Base + 10
+
+If the ports specified by any of these numbers are already in use or
+otherwise unavailable, this template will inform you of the problem and
+exit with an error. If this happens, please try another number for
+'Base Port #'
+""",
+ ),
+
+ BooleanVar(
+ "proxy",
+ title="Install proxy server?",
+ description="Should a proxy server be installed?",
+ default=False,
+ help="""
+If you ask for a proxy server to be installed, this template will include
+the Varnish Caching/Proxy server. If you wish to use a different proxy
+server, please answer False and install your own.
+""",
+ ),
+
+ StringVar(
+ "plone",
+ title="Plone Version",
+ description="Version to install (2.5, 2.5.1, 3.0, 3.0.1, etc)",
+ default="3.1.7",
+ help="""
+You can use this template to install any version of Plone from 2.5 on.
+Versions of Plone more recent than 3.1.7 will require some editing of the
+generated configuration files. Please see the long description of this
+template (run 'zopskel --list') for more details. In general it is
+advisable to use the most recent version of Plone. You can find a list of
+stable Plone releases at
+
+http://plone.org/products/plone/releases/
+
+""",
+ ),
+
+ BooleanVar(
+ "buildout",
+ title="Run Buildout?",
+ description="Should bin/buildout command be executed?",
+ default=True,
+ help="""
+Would you like this template to automatically run the buildut command as soon
+as it finishes creating the required files? Please note that if you've chosen
+to build a version of Plone more recent than 3.1.7 running buildout will fail
+unless you make changes to the generated configuration files. Please see the
+long description of this package (run 'zopeskel --list') for more details.
+
+If you intend on adding any specific third-party products or modifying the
+buildout in any way, you should answer 'False'. Then make your modifications
+and run `python bootstrap.py` followed by `bin/buildout`.
+""",
+ ),
+
+ ]
+
+ def _buildout(self, output_dir):
+ olddir=os.getcwd()
+ try:
+ os.chdir(output_dir)
+ print "Bootstrapping the buildout"
+ subprocess.call([sys.executable, "bootstrap.py"])
+ print "Configuring the buildout"
+ subprocess.call(["bin/buildout", "-n"])
+ finally:
+ os.chdir(olddir)
+
+ def _checkPortAvailable(self, port):
+ s=socket.socket()
+ try:
+ s.connect(("127.0.0.1", port))
+ except socket.error, e:
+ s.close()
+
+ if e.args[0]==errno.ECONNREFUSED:
+ return
+
+ raise BadCommand("Error checking port availability: %s" % e.args[1])
+
+ s.close()
+ raise BadCommand("Port %s is already in use" % port)
+
+
+ def check_vars(self, vars, cmd):
+ result=super(StandardHosting, self).check_vars(vars, cmd)
+
+ base_port=result["base_port"]
+ result["zeo_port"]=base_port
+ result["proxy_port"]=base_port+1
+ result["http_port"]=base_port+10
+
+ self._checkPortAvailable(result["zeo_port"])
+ self._checkPortAvailable(result["http_port"])
+ if result["proxy"]:
+ self._checkPortAvailable(result["proxy_port"])
+
+ if vars["plone"] not in plone25s and not vars["plone"].startswith("3."):
+ raise BadCommand("Unknown plone version: %s" % vars["plone"])
+
+ return result
+
+ def pre(self, command, output_dir, vars):
+ vars["output_dir"]=os.path.abspath(output_dir)
+ plone=vars["plone"]
+ if plone.startswith("3."):
+ vars["plone_recipe"]="plone.recipe.plone"
+ vars["plone_recipe_version"]=plone
+ else:
+ vars["plone_recipe"]="plone.recipe.plone25install"
+ vars["plone_url"]=plone25s[plone]
+ super(StandardHosting, self).pre(command, output_dir, vars)
+
+ def show_summary(self, vars):
+ print
+ print "Finished creation of standard hosting buildout."
+ print
+ print "Configuration summary:"
+ print " Plone : %s" % vars["plone"]
+ print
+ print " HTTP port : %s" % vars["http_port"]
+ print " ZEO port : %s" % vars["zeo_port"]
+ if vars["proxy"]:
+ print " Proxy port: %s" % vars["proxy_port"]
+ else:
+ print " Proxy port: disabled"
+ print
+ print " Zope admin user : %s" % vars["zope_user"]
+ print " Zope admin password: %s" % vars["zope_password"]
+
+
+ def post(self, command, output_dir, vars):
+ output_dir=vars["output_dir"]
+ if vars["buildout"]:
+ self._buildout(output_dir)
+ if not vars.get("hide_summary", False):
+ self.show_summary(vars)
+ super(StandardHosting, self).post(command, output_dir, vars)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/interfaces.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/interfaces.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/interfaces.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,55 @@
+class IVar:
+ """Variables in a ZopeSkel template.
+ """
+
+ # actual variable name, eg "description"
+ name = ""
+
+ # human-facing variable name, eg "Product Description"
+ title = ""
+
+ # Short, 1-sentence description
+ # e.g., "Short description of this product."
+ description = ""
+
+ # Longer, potentially multi-paragraph help for users
+ # to explain this option
+ #
+ # e.g., "Products in Plone have a description that is used for ..."
+ help = ""
+
+ # Default value
+ default = None
+
+ # Should Echo # wtf? is this used?
+ should_echo = True
+
+ # Modes that question should appear in
+ # 'easy', 'intermediate', 'advanced'
+ modes = ()
+
+ # Widget hint?
+ # XXX Todo
+ # strawman: ('text','multitext','tf','int')
+
+ def full_description():
+ """Returns variable name and description."""
+
+ def print_vars():
+ """ wtf? """
+
+ def validate(value):
+ """Check validity of entered value; exception on error.
+
+ Check validity of entered data and raise exception if
+ value is invalid.
+
+ If this value is valid, this method will return a
+ normalized version of it (eg, "yes" -> True, for boolean
+ questions).
+ """
+
+
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/kss_plugin.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/kss_plugin.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/kss_plugin.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+import copy
+
+from zopeskel.base import get_var
+from zopeskel.base import var
+from zopeskel import abstract_zope
+
+
+class KssPlugin(abstract_zope.AbstractNestedZope):
+ _template_dir = 'templates/kss_plugin'
+ summary = "A project for a KSS plugin"
+ ndots = 2
+ help = """
+This creates a project for a KSS plugins ('Kinetic Style Sheets', a
+Plone 3 framwork for JavaScript/AJAX).
+"""
+ category = "Plone Development"
+
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_zope.AbstractNestedZope.vars)
+ get_var(vars, 'namespace_package').default = 'kss'
+ get_var(vars, 'namespace_package2').default = 'plugin'
+ get_var(vars, 'keywords').default = 'kss plugin'
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,354 @@
+.. contents::
+
+ZopeSkel with local commands
+============================
+
+ZopeSkel is a great tool for generating plone projects structure from paste
+templates. You can install it with::
+
+ $ easy_install \
+ http://svn.plone.org/svn/collective/ZopeSkel/trunk#egg=ZopeSkel-dev
+
+You can list the available templates::
+
+ $ paster create --list-templates
+ Available templates:
+ archetype: A Plone project that uses Archetypes
+ asic_namespace: A project with a namespace package
+ basic_package: A basic setuptools-enabled package
+ basic_zope: A Zope project
+ nested_namespace: A project with two nested namespaces.
+ paste_deploy: A web application deployed through paste.deploy
+ plone: A Plone project
+ plone2.5_buildout: A buildout for Plone 2.5 projects
+ plone2.5_theme: A Theme for Plone 2.5
+ plone2_theme: A Theme Product for Plone 2.1 & Plone 2.5
+ plone3_buildout: A buildout for Plone 3 projects
+ plone3_portlet: A Plone 3 portlet
+ plone3_theme: A Theme for Plone 3.0
+ plone_app: A Plone App project
+
+You can start a new project::
+
+ $ paster create -t archetype myproject
+
+You have to answer many questions and in the end you will get an archetype
+based skeleton to start your project.
+
+Now what will you do to add a new plone content type, Zope 3 utility, ...etc ?
+You have to create the new files by hand and copy/paste code from other
+projects. This is not the best approach to the problem. Martin Aspeli comes
+with the idea of implementing a paster local commands/templates so one can
+just add plone content types by running paster local commands inside
+the project directory.
+
+zopeskel.localcommands is one implementation of such idea.
+
+
+How to use zopeskel.localcommands
+=================================
+
+List the available paster commands::
+
+ $ paster --help
+ ...
+ Commands:
+ create Create the file layout for a Python distribution
+ help Display help
+ make-config Install a package and create a fresh config file/directory
+ points Show information about entry points
+ serve Serve the described application
+ setup-app Setup an application, given a config file
+
+Now create an archetype project as described above, cd to the project folder
+and check the available commands::
+
+ $ cd myproject
+ myproject$ paster --help
+ ...
+ Commands:
+ create Create the file layout for a Python distribution
+ grep Search project for symbol
+ help Display help
+ make-config Install a package and create a fresh config file/directory
+ points Show information about entry points
+ serve Serve the described application
+ setup-app Setup an application, given a config file
+
+ ZopeSkel local commands:
+ addcontent Add plone content types to your project
+
+You get a new section called ``ZopeSkel local commands`` with one command
+called ``addcontent``. This new section is only available if paster detects
+that your project is ``addcontent`` aware (more about this later) .
+
+To see the list of available templates for a zopeskel template, create
+a project based on that template and run ``paster addcontent -l``::
+
+ $ paster create -t archetype myproject
+ $ cd myproject
+ myproject$ paster addcontent -l
+ Available templates:
+ atschema: A handy AT schema builder
+ contenttype: A content type skeleton
+ form: A form skeleton
+ formfields: Schema fields for a form
+ i18nlocale: An i18n locale directory structure
+ portlet: A Plone 3 portlet
+ view: A browser view skeleton
+ zcmlmeta: A ZCML meta directive skeleton
+
+You get only the templates related to the type of your project. If you want
+to see all templates even those that are not related to the type of your
+project::
+
+ myproject$ paster addcontent -a
+ Available templates:
+ N anonymous_user_factory_plugin: A Plone PAS AnonymousUserFactory Plugin
+ atschema: A handy AT schema builder
+ N authentication_plugin: A Plone PAS Authentication Plugin
+ N challenge_plugin: A Plone PAS Challenge Plugin
+ contenttype: A content type skeleton
+ N credentials_reset_plugin: A Plone PAS CredentialsReset Plugin
+ N extraction_plugin: A Plone PAS Extraction Plugin
+ form: A form skeleton
+ formfields: Schema fields for a form
+ N group_enumeration_plugin: A Plone PAS GroupEnumeration Plugin
+ N groups_plugin: A Plone PAS Groups Plugin
+ i18nlocale: An i18n locale directory structure
+ portlet: A Plone 3 portlet
+ N properties_plugin: A Plone PAS Properties Plugin
+ N role_assigner_plugin: A Plone PAS RoleAssigner Plugin
+ N role_enumeration_plugin: A Plone PAS RoleEnumeration Plugin
+ N roles_plugin: A Plone PAS Roles Plugin
+ N update_plugin: A Plone PAS Update Plugin
+ N user_adder_plugin: A Plone PAS UserAdder Plugin
+ N user_enumeration_plugin: A Plone PAS UserEnumeration Plugin
+ N user_factory_plugin: A Plone PAS UserFactory Plugin
+ N validation_plugin: A Plone PAS Validation Plugin
+ view: A browser view skeleton
+ zcmlmeta: A ZCML meta directive skeleton
+
+``N`` means: not related to the type of your project.
+
+To add a portlet to your project, run the following command from anywhere
+inside your project (you don't need to be in the project's root folder)::
+
+ myproject$ paster addcontent portlet
+ Enter portlet_name (Portlet name (human readable)) ['Example portlet']: My Portlet
+ Enter portlet_type_name (Portlet type name (should not contain spaces)) ['ExamplePortlet']: MyPortlet
+ Enter description (Portlet description) )['']: My Portlet
+ Recursing into portlets
+ Copying +portlet_filename+.pt_tmpl to /home/mustapha/Projects/pylonsenv/test/plone/example/portlets/myportlet.pt
+ Copying +portlet_filename+.py_tmpl to /home/mustapha/Projects/pylonsenv/test/plone/example/portlets/myportlet.py
+ Recursing into profiles
+ Recursing into default
+ Recursing into tests
+ Copying +portlet_filename+_base.py_tmpl to /home/mustapha/Projects/pylonsenv/test/plone/example/tests/myportlet_base.py
+ Copying test_+portlet_filename+.py_tmpl to /home/mustapha/Projects/pylonsenv/test/plone/example/tests/test_myportlet.py
+
+You get new files and if you check the ``configure.zcml`` in the portlets
+folder and the ``portlet.xml`` in the profiles/default folder, you will see
+that they are updated too.
+
+
+How to add new templates ?
+==========================
+
+The python part is very similar to what you know from ZopeSkel. The only
+difference is that your template class must inherit from
+``ZopeSkelLocalTemplate``.
+
+The template structure on the file system is the same as what you know from
+ZopeSkel with one difference: if your project has a file with the same name
+as a template file or the template filename ends with ``_insert``,
+the ``addcontent`` command will operate in insert-mode.
+
+To make things easy, let's take Martin's plone 3 portlet template and
+transform it to ``zopeskel.localcommands`` template so you can add as many
+portlets as you want to your project. Here is the files and the structure
+we use::
+
+ portlets/
+ +portlet_filename+.pt_tmpl
+ +portlet_filename+.py_tmpl
+ configure.zcml_insert
+ profiles/
+ default/
+ portlets.xml_insert
+ tests/
+ base_+portlet_filename+.py_tmpl
+ test_+portlet_filename+portlet.py_tmpl
+
+The files that end with ``_tmpl`` will be handled as normal ZopeSkel templates.
+But the new thing here is the files that end with ``_insert``.
+The content of these files will be inserted in the correspondent files of
+the destination project. As example here is the content of the file
+``portlet.xml_insert``::
+
+ #<?xml version="1.0"?>
+ # <!-- This file is used to register new types of portlets. It can also
+ # be used to register completely new column types. See CMFPlone's
+ # version of this file for more information.
+ # -->
+ # <portlets>
+ # <!-- -*- extra stuff goes here -*- -->
+
+ <portlet
+ addview="${dotted_name}.${portlet_type_name}"
+ title="${portlet_name}"
+ description="${description}"
+ />
+
+ #</portlets>
+
+Here, some notes are needed:
+
+1. If your project contains a file named ``profile/default/portlets.xml``,
+ only the lines not starting with ``#`` will be inserted
+
+2. If your project doesn't contain the file ``profile/default/portlets.xml``,
+ the ``#``'s in the beginning of lines will be removed and a
+ ``profile/default/portlets.xml`` file will be created with the hole
+ content.
+ So it is a good idea when creating a new local template to think
+ about how the file will look like if it has to be created from scratch.
+ Look at the zcmlmeta template as example.
+
+Now, if you are asking how ``zopeskel.localcommands`` knows where (in the
+destination file) to insert the content of the source file, keep reading.
+
+
+NOTE:
+-----
+
+The '_insert' in the end of the name of the template file is required for .py
+files and optional for other kind of files. For zopeskel.localcommands there is
+no difference between `configure.zcml_insert` and `configure.zcml`. Both will be
+treated in insert-mode. In the case of .py files if you don't add '_insert' in
+the end of their name, setuptools will fail with 'SyntaxError' when installing
+ZopeSkel. That's normal because of the template variables in the file.
+For readability I recommand using the '_insert' syntax in all cases.
+
+Now, take a look to the python part. Here is the Portlet class::
+
+ from zopeskel import var
+ from zopeskel.localcommands import ZopeSkelLocalTemplate
+
+ class Portlet(ZopeSkelLocalTemplate):
+ """
+ A plone 3 portlet skeleton
+ """
+ _template_dir = 'templates/portlet'
+ summary = "A Plone 3 portlet"
+ use_cheetah = True
+ parent_templates = ['archetype']
+
+ vars = []
+ vars.append(var('portlet_name',
+ 'Portlet name (human readable)',
+ default="Example portlet"))
+
+ vars.append(var('portlet_type_name',
+ 'Portlet type name (should not contain spaces)',
+ default="ExamplePortlet"))
+
+ vars.append(var('description',
+ 'Portlet description',
+ default=""))
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['portlet_filename'] = vars['portlet_type_name'].lower()
+
+ vars['dotted_name'] = "%s.portlets" % vars['package_dotted_name']
+
+Notes:
+
+1. Your template class has to inherit from ``ZopeSkelLocalTemplate``
+
+2. You template class may define a ``parent_templates`` attribute with
+ the list of zopeskel templates that can use this sub-template. This
+ attribute will be used for selection when you run ``addcontent -l``
+ or ``addcontent -a``
+
+3. You get the package_namespace, package_namespace2, package and
+ package_dotted_name of the parent package for free in the vars argument
+ of the "pre" method.
+
+4. The ZopeSkelLocalTemplate class defines an attribute named ``marker_name``
+ like this::
+
+ marker_name = "extra stuff goes here"
+
+ Your can override it in your template class if you want. The purpose of this
+ marker_name is to tell ``addcontent`` command where to insert the content if
+ it has to insert something in a file. The correspondent file must include
+ a line containing ``-*- marker_name -*-`` in our case::
+
+ -*- extra stuff goes here -*-
+
+ if you look in portlet.xml of your project you will find a line containing::
+
+ <!-- -*- extra stuff goes here -*- -->
+
+ If you want to know more about marker_name look at insert_into_file method
+ of paste.script.command.Command.
+
+OK, now we have the file system structure and the template class. We need just
+one more thing: add an egg entry point for our template class to make it
+available for the ``addcontent`` command. As I said before it is very similar
+to how you add a normal ZopeSkel template. The difference is that for normal
+ZopeSkel templates the entry point is added under
+``[paste.paste_create_template]`` section, but ``zopeskel.localcommands``
+adds a new kind of entry points named ``[zopeskel.zopeskel_sub_template]``
+and our templates have to be added under that section. If you look in the
+setup.py file of ZopeSkel to the entry_points argument, you will find::
+
+ [zopeskel.zopeskel_sub_template]
+ portlet = zopeskel.localcommands.plone:Portlet
+
+
+Enable ``addcontent`` in other ZopeSkel templates
+-------------------------------------------------
+
+To enable ``addcontent`` command in your current project add a line with
+``ZopeSkel`` to your ``paster_plugins.txt`` file of your egg-info directory
+and edit your setup.cfg file and add a new section called ``zopeskel`` with
+a ``template`` option containing the name of the template you used to generate
+your current projet::
+
+ [zopeskel]
+ template = archetype
+
+For the moment the ``addcontent`` command is only enabled for the
+archetype, plone and plone_pas templates. You can enable
+``addcontent`` command for other ZopeSkel templates by addinng a
+``use_local_commands`` attribute to the template class and set it to
+'True'::
+
+ use_local_commands = True
+
+Forthermore, you need to make sure the ZopeSkel template's name is in
+the ``parent_templates`` list of the command(s) you went to enable. To
+enable the portlet template for the plone template::
+
+ from zopeskel import var
+ from zopeskel.localcommands import ZopeSkelLocalTemplate
+
+ class Portlet(ZopeSkelLocalTemplate):
+ """
+ A plone 3 portlet skeleton
+ """
+ ...
+ parent_templates = ['archetype', 'plone']
+ ...
+
+
+/Mustapha
+url: http://www.mustap.com
+email: mustap_at_gamail_com
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,399 @@
+"""
+ ZopeSkel local command/template. Most of the code is a copy/paste from
+ paste.script module
+"""
+
+import os
+import subprocess
+import ConfigParser
+import pkg_resources
+from paste.script import command, pluginlib
+from paste.script import templates
+from paste.script import copydir
+
+
+class ZopeSkelLocalCommand(command.Command):
+ """paster command to add content skeleton to plone project"""
+
+ max_args = 2
+ usage = "[template name]"
+ summary = "Adds plone content types to your project"
+ group_name = "ZopeSkel local commands"
+
+ parser = command.Command.standard_parser(verbose=True)
+ parser.add_option('-l', '--list',
+ action='store_true',
+ dest='listcontents',
+ help="List available templates for the current project")
+
+ parser.add_option('-a', '--list-all',
+ action='store_true',
+ dest='listallcontents',
+ help="List all templates regardless of the current project")
+
+ parser.add_option('-q', '--no-interactive',
+ action="count",
+ dest="no_interactive",
+ default=0)
+
+ template_vars = {}
+
+ def command(self):
+ """
+ command method
+ """
+ self.interactive = 1
+ options, args = self.options, self.args
+
+ if options.listcontents:
+ self._list_sub_templates()
+ return
+
+ if options.listallcontents:
+ self._list_sub_templates(show_all=True)
+ return
+
+ if options.no_interactive:
+ self.interactive = False
+
+ if len(args) < 1:
+ print "\n\tError: Need a template name\n"
+ return
+
+ (self.template_vars['namespace_package'],
+ self.template_vars['namespace_package2'],
+ self.template_vars['package']) = self.get_parent_namespace_packages()
+
+ dest_dir = self.dest_dir()
+
+ templates = []
+ self._extend_templates(templates, args[0])
+
+ templates = [tmpl for name, tmpl in templates]
+ for tmpl in templates[::-1]:
+ self.template_vars = tmpl.check_vars(self.template_vars, self)
+
+ for tmpl in templates[::-1]:
+ if self.verbose:
+ print 'Creating template %s' % tmpl.name
+ tmpl.run(self, dest_dir, self.template_vars)
+
+
+ def dest_dir(self):
+ dest_dir = os.path.join(
+ os.path.dirname(
+ pluginlib.find_egg_info_dir(os.getcwd())),
+ self.template_vars['namespace_package'],
+ self.template_vars['namespace_package2'],
+ self.template_vars['package'])
+ return dest_dir
+
+ def get_parent_namespace_packages(self):
+ """
+ return the project namespaces and package name.
+ This method can be a function
+ """
+ egg_info = pluginlib.find_egg_info_dir(os.getcwd())
+
+ hfile = open(os.path.join(egg_info, 'namespace_packages.txt'))
+ packages = [l.strip() for l in hfile.readlines()
+ if l.strip() and not l.strip().startswith('#')]
+ hfile.close()
+
+ packages.sort(lambda x, y: -cmp(len(x), len(y)))
+ packages = packages[0].split('.')
+
+ namespace_package = packages[0]
+ namespace_package2 = ''
+ if len(packages) == 2:
+ namespace_package2 = packages[1]
+ ( dirpath, dirnames, filenames) = os.walk(os.path.join(
+ os.path.dirname(egg_info),
+ namespace_package,
+ namespace_package2)).next()
+ # Get the package dir because we usually want to issue the
+ # localcommand in the package dir.
+ package = os.path.basename(os.path.abspath(os.path.curdir))
+
+ # If the package dir is not in the list of inner_packages,
+ # then:
+ # if there is only one package in the list, we take it
+ # else ask the user to pick a package from the list
+ inner_packages = [d for d in dirnames if d != '.svn']
+ if package not in inner_packages:
+ package = inner_packages[0]
+ if len(inner_packages) > 1:
+ package = self.challenge('Please choose one package to inject content into %s' % inner_packages)
+
+ return namespace_package, namespace_package2, package
+
+ def _list_sub_templates(self, show_all=False):
+ """
+ lists available templates
+ """
+ templates = []
+ parent_template = None
+
+ egg_info_dir = pluginlib.find_egg_info_dir(os.getcwd())
+ setup_cfg = os.path.join(os.path.dirname(egg_info_dir), 'setup.cfg')
+
+ parent_template = None
+ if os.path.exists(setup_cfg):
+ parser = ConfigParser.ConfigParser()
+ parser.read(setup_cfg)
+ try:
+ parent_template = parser.get('zopeskel', 'template') or None
+ except:
+ pass
+
+ for entry in self._all_entry_points():
+ try:
+ entry_point = entry.load()
+ t = entry_point(entry.name)
+ if show_all or \
+ parent_template is None or \
+ parent_template in t.parent_templates:
+ templates.append(t)
+ except Exception, e:
+ # We will not be stopped!
+ print 'Warning: could not load entry point %s (%s: %s)' % (
+ entry.name, e.__class__.__name__, e)
+
+ print 'Available templates:'
+ if not templates:
+ print ' No template'
+ return
+
+ max_name = max([len(t.name) for t in templates])
+ templates.sort(lambda a, b: cmp(a.name, b.name))
+
+ for template in templates:
+ _marker = " "
+ if not template.parent_templates:
+ _marker = '?'
+ elif parent_template not in template.parent_templates:
+ _marker = 'N'
+
+ # @@: Wrap description
+ print ' %s %s:%s %s' % (
+ _marker,
+ template.name,
+ ' '*(max_name-len(template.name)),
+ template.summary)
+
+ def _all_entry_points(self):
+ """
+ Return all entry points under zopeskel_sub_templates
+ """
+ if not hasattr(self, '_entry_points'):
+ self._entry_points = list(pkg_resources.iter_entry_points(
+ 'zopeskel.zopeskel_sub_template'))
+ return self._entry_points
+
+ def _extend_templates(self, templates, tmpl_name):
+ """
+ Return ...
+ """
+ if '#' in tmpl_name:
+ dist_name, tmpl_name = tmpl_name.split('#', 1)
+ else:
+ dist_name, tmpl_name = None, tmpl_name
+ if dist_name is None:
+ for entry in self._all_entry_points():
+ if entry.name == tmpl_name:
+ tmpl = entry.load()(entry.name)
+ dist_name = entry.dist.project_name
+ break
+ else:
+ raise LookupError(
+ 'Template by name %r not found' % tmpl_name)
+ else:
+ dist = pkg_resources.get_distribution(dist_name)
+ entry = dist.get_entry_info(
+ 'paste.paster_create_template', tmpl_name)
+ tmpl = entry.load()(entry.name)
+ full_name = '%s#%s' % (dist_name, tmpl_name)
+ for item_full_name, in templates:
+ if item_full_name == full_name:
+ # Already loaded
+ return
+ for req_name in tmpl.required_templates:
+ self._extend_templates(templates, req_name)
+ templates.append((full_name, tmpl))
+
+
+class ZopeSkelLocalTemplate(templates.Template):
+ """
+ Base template class
+ """
+
+ marker_name = "extra stuff goes here"
+ #list of templates this subtemplate is related to
+ parent_templates = []
+
+ def run(self, command, output_dir, vars):
+ """
+ the run method
+ """
+ (vars['namespace_package'],
+ vars['namespace_package2'],
+ vars['package']) = command.get_parent_namespace_packages()
+
+ if vars['namespace_package2']:
+ vars['package_dotted_name'] = "%s.%s.%s" % \
+ (vars['namespace_package'],
+ vars['namespace_package2'],
+ vars['package'])
+ else:
+ vars['package_dotted_name'] = "%s.%s" % \
+ (vars['namespace_package'],
+ vars['package'])
+
+ self.pre(command, output_dir, vars)
+ self.write_files(command, output_dir, vars)
+ self.post(command, output_dir, vars)
+
+ def write_files(self, command, output_dir, vars):
+ """
+ method
+ """
+ self._command = command
+ template_dir = self.template_dir()
+ if not os.path.exists(output_dir):
+ print "Creating directory %s" % output_dir
+ if not command.simulate:
+ # Don't let copydir create this top-level directory,
+ # since copydir will svn add it sometimes:
+ os.makedirs(output_dir)
+ self.copy_dir(template_dir, output_dir,
+ vars,
+ verbosity=1,
+ simulate=0,
+ interactive=1,
+ overwrite=0,
+ indent=1,
+ use_cheetah=self.use_cheetah,
+ template_renderer=self.template_renderer)
+
+ def copy_dir(self, source, dest, vars, verbosity, simulate, indent=0,
+ use_cheetah=False, sub_vars=True, interactive=False,
+ svn_add=True, overwrite=True, template_renderer=None):
+ """
+ This method is a modified copie of paste.script.copy_dir
+ """
+ # This allows you to use a leading +dot+ in filenames which would
+ # otherwise be skipped because leading dots make the file hidden:
+ vars.setdefault('dot', '.')
+ vars.setdefault('plus', '+')
+ names = os.listdir(source)
+ names.sort()
+ pad = ' '*(indent*2)
+ if not os.path.exists(dest):
+ if verbosity >= 1:
+ print '%sCreating %s/' % (pad, dest)
+ if not simulate:
+ copydir.svn_makedirs(dest, svn_add=svn_add, verbosity=verbosity,
+ pad=pad)
+ elif verbosity >= 2:
+ print '%sDirectory %s exists' % (pad, dest)
+ for name in names:
+ full = os.path.join(source, name)
+ reason = copydir.should_skip_file(name)
+ if reason:
+ if verbosity >= 2:
+ reason = pad + reason % {'filename': full}
+ print reason
+ continue
+
+ if sub_vars:
+ dest_full = os.path.join(
+ dest, copydir.substitute_filename(name, vars))
+ sub_file = False
+ if dest_full.endswith('_tmpl'):
+ dest_full = dest_full[:-5]
+ sub_file = sub_vars
+ if os.path.isdir(full):
+ if verbosity:
+ print '%sRecursing into %s' % (pad, os.path.basename(full))
+ self.copy_dir(full, dest_full, vars, verbosity, simulate,
+ indent=indent+1, use_cheetah=use_cheetah,
+ sub_vars=sub_vars, interactive=interactive,
+ svn_add=svn_add, template_renderer=template_renderer)
+ continue
+ f = open(full, 'rb')
+ content = f.read()
+ f.close()
+ try:
+ content = copydir.substitute_content(
+ content,
+ vars, filename=full,
+ use_cheetah=use_cheetah,
+ template_renderer=template_renderer)
+ except copydir.SkipTemplate:
+ continue
+
+ if dest_full.endswith('_insert'):
+ dest_full = dest_full[:-7]
+
+ already_exists = os.path.exists(dest_full)
+ if already_exists:
+ if sub_file and verbosity:
+ print "File '%s' already exists: skipped" % \
+ os.path.basename(dest_full)
+ continue
+ f = open(dest_full, 'rb')
+ old_content = f.read()
+ f.close()
+ if old_content == content:
+ if verbosity:
+ print '%s%s already exists (same content)' % \
+ (pad, dest_full)
+ continue
+
+ if verbosity:
+ print "%sInserting from %s into %s" % \
+ (pad, os.path.basename(full), dest_full)
+
+ if not content.endswith('\n'):
+ content += '\n'
+ # remove lines starting with '#'
+ content = '\n'.join([l for l in content.split('\n') \
+ if not l.startswith('#')])
+ self._command.insert_into_file(dest_full,
+ self.marker_name,
+ content)
+ continue
+
+ if verbosity:
+ print '%sCopying %s to %s' % (pad,
+ os.path.basename(full),
+ dest_full)
+ # remove '#' from the start of lines
+ if not sub_file:
+ content = content.replace('\n#','\n')
+ if content[0] == '#': content = content[1:]
+
+ if not simulate:
+ f = open(dest_full, 'wb')
+ f.write(content)
+ f.close()
+ if svn_add and not already_exists:
+ if not os.path.exists(
+ os.path.join(
+ os.path.dirname(
+ os.path.abspath(dest_full)), '.svn')):
+ if verbosity > 1:
+ print '%s.svn/ does not exist; cannot add file' % pad
+ else:
+ cmd = ['svn', 'add', dest_full]
+ if verbosity > 1:
+ print '%sRunning: %s' % (pad, ' '.join(cmd))
+ if not simulate:
+ # @@: Should
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ if verbosity > 1 and stdout:
+ print 'Script output:'
+ print stdout
+ elif svn_add and already_exists and verbosity > 1:
+ print '%sFile already exists (not doing svn add)' % pad
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/archetype.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/archetype.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/archetype.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,238 @@
+"""
+Local templates for the archetype zopeskel project
+"""
+import os
+from zopeskel.base import var
+from zopeskel.localcommands import ZopeSkelLocalTemplate
+
+from Cheetah.Template import Template as cheetah_template
+
+
+class ArchetypeSubTemplate(ZopeSkelLocalTemplate):
+ use_cheetah = True
+ parent_templates = ['archetype']
+
+
+class ContentType(ArchetypeSubTemplate):
+ """
+ A Content Type skeleton
+ """
+
+ _template_dir = 'templates/archetype/contenttype'
+ summary = "A content type skeleton"
+
+ vars = [
+ var('contenttype_name', 'Content type name ', default='Example Type'),
+ var('contenttype_description', 'Content type description ',
+ default='Description of the Example Type'),
+ var('folderish', 'True/False: Content type is Folderish ',
+ default=False),
+ var('global_allow', 'True/False: Globally addable ',
+ default=True),
+ var('allow_discussion', 'True/False: Allow discussion ',
+ default=False),
+ ]
+
+ def pre(self, command, output_dir, vars):
+
+ vars['contenttype_classname'] = vars['contenttype_name'].replace(" ", "")
+ vars['schema_name'] = vars['contenttype_classname'] + "Schema"
+ vars['content_class_filename'] = vars['contenttype_classname'].lower()
+ vars['types_xml_filename'] = vars['contenttype_name'].replace(" ", "_")
+ vars['interface_name'] = "I" + vars['contenttype_name'].replace(" ", "")
+ vars['add_permission_name'] = vars['package_dotted_name'] + ': Add ' + vars['contenttype_name']
+
+
+class ATSchemaField(ArchetypeSubTemplate):
+ """
+ A handy AT schema builder
+ """
+
+ _template_dir = 'templates/archetype/atschema'
+ summary = "A handy AT schema builder"
+ marker_name = "Your Archetypes field definitions here ..."
+
+ # mapping of ATSchema types to zope.schema types
+ typemap = {'boolean': 'Bool',
+ 'computed': 'TextLine',
+ 'cmfobject': 'TextLine',
+ 'datetime': 'Date',
+ 'file': 'Bytes',
+ 'fixedpoint': 'Float',
+ 'float': 'Float',
+ 'image': 'Bytes',
+ 'integer': 'Int',
+ 'lines': 'List',
+ 'reference': 'Object',
+ 'string': 'TextLine',
+ 'text': 'Text',
+ 'unknown': 'TextLine'}
+
+ # fieldtypes-map to (widget, validator)
+ fieldtypes = {
+ 'boolean': ('boolean', None),
+ 'computed': ('computed', None),
+ 'cmfobject': ('file', None),
+ 'datetime': ('calendar', 'isValidDate'),
+ 'file': ('file', 'isNonEmptyFile'),
+ 'fixedpoint': ('decimal', 'isDecimal'),
+ 'float': ('decimal', 'isDecimal'),
+ 'image': ('image', 'isNonEmptyFile'),
+ 'integer': ('integer', 'isInt'),
+ 'lines': ('lines', None),
+ 'reference': ('reference', None),
+ 'string': ('string', None),
+ 'text': ('textarea', None),
+ }
+
+ vars = [
+ var('content_class_filename',
+ 'What is the module (file)name of your content class?',
+ default='exampletype'),
+ var('field_name',
+ 'What would you like to name this field?',
+ default='newfield'),
+ var('field_type',
+ 'What kind of field should I make for you?\nSome examples: ['+','.join(fieldtypes.keys())+']\n',
+ default='string'),
+ var('widget_type',
+ 'What kind of widget do you want to use (example: Password)?',
+ default='default'),
+ var('field_label',
+ 'What should be the label of this field (title)?',
+ default='New Field'),
+ var('field_desc',
+ 'What should be the description of this field (help text)?',
+ default='Field description'),
+ var('required',
+ 'Is this field required?',
+ default='False'),
+ var('default',
+ "If you'd like a default type it here, otherwise leave it blank",
+ default=''),
+ var('validator',
+ "Enter a validator (isEmail), or None, or get a default validator for your specified field type.",
+ default='use default validator'),
+ ]
+
+ def check_vars(self, *args, **kwargs):
+ """
+ Overloading check_vars to print welcome message
+ """
+
+ print "Welcome to the ATSchema Builder. Field names/widgets can be specified in lowercase or upper case."
+ print "NOTE: No need to add 'widget' or 'field' to the names. atschema does the work for you!"
+ print "See "
+ print " http://plone.org/documentation/manual/archetypes-developer-manual/fields/fields-reference/"
+ print "and "
+ print " http://plone.org/documentation/manual/archetypes-developer-manual/fields/widgets-reference"
+ print "for field and widget details"
+
+ return super(ATSchemaField, self).check_vars(*args, **kwargs)
+
+ def run(self, command, output_dir, vars):
+ """
+ By-passing the base run so I can do multiple inserts
+ with different marker names
+ """
+
+ (vars['namespace_package'],
+ vars['namespace_package2'],
+ vars['package']) = command.get_parent_namespace_packages()
+
+ if vars['namespace_package2']:
+ vars['package_dotted_name'] = "%s.%s.%s" % \
+ (vars['namespace_package'],
+ vars['namespace_package2'],
+ vars['package'])
+ else:
+ vars['package_dotted_name'] = "%s.%s" % \
+ (vars['namespace_package'],
+ vars['package'])
+
+ vars['a_validator'] = ''
+ if vars['validator'] == 'use default validator':
+ ## take default Validator...
+ val = ATSchemaField.fieldtypes[vars['field_type'].lower()][1]
+ if val is not None:
+ vars['a_validator'] = """'%s'""" % val
+ elif vars['validator'] != 'None': ## user providing 'aValidator'
+ vars['a_validator'] = """'%s'""" % vars['validator']
+
+ self.pre(command, output_dir, vars)
+
+ interface_insert_template = open(os.path.join(self.template_dir(), 'interfaces/+interface_name+.py_insert')).read()
+ atschema_insert_template = open(os.path.join(self.template_dir(),'content/+content_class_filename+.py_insert')).read()
+ bridges_insert_template = open(os.path.join(self.template_dir(),'content/schema_field_bridge.txt_insert')).read()
+ content_messagefactory_insert_template = open(os.path.join(self.template_dir(), 'content/messagefactory_insert.txt_insert')).read()
+ interface_additional_imports_template = open(os.path.join(self.template_dir(), 'interfaces/additional_imports.txt_insert')).read()
+
+ # insert_into_file really wants the inserted text to end with a newline
+ interface_insert = str(cheetah_template(interface_insert_template, vars))+"\n"
+ atschema_insert = str(cheetah_template(atschema_insert_template, vars))+"\n"
+ bridges_insert = str(cheetah_template(bridges_insert_template, vars))+"\n"
+ content_messagefactory_insert = str(cheetah_template(content_messagefactory_insert_template, vars))+"\n"
+ interface_additional_imports = str(cheetah_template(interface_additional_imports_template, vars))+"\n"
+
+ # self.write_files(command, output_dir, vars)
+ command.insert_into_file(os.path.join(command.dest_dir(), 'content', '%s.py' % (vars['content_class_filename'])), self.marker_name, atschema_insert)
+ command.insert_into_file(os.path.join(command.dest_dir(), 'interfaces', '%s.py' % (vars['content_class_filename'])), 'schema definition goes here', interface_insert)
+ command.insert_into_file(os.path.join(command.dest_dir(), 'content', '%s.py' % (vars['content_class_filename'])), 'Your ATSchema to Python Property Bridges Here ...', bridges_insert)
+ command.insert_into_file(os.path.join(command.dest_dir(), 'content', '%s.py' % (vars['content_class_filename'])), 'Message Factory Imported Here', content_messagefactory_insert)
+ command.insert_into_file(os.path.join(command.dest_dir(), 'interfaces', '%s.py' % (vars['content_class_filename'])), 'Additional Imports Here', interface_additional_imports)
+
+ self.post(command, output_dir, vars)
+
+
+ def pre(self, command, output_dir, vars):
+
+ file = vars['content_class_filename']
+ if file.endswith('.py'):
+ file = os.path.splitext(file)[0]
+
+ vars['field_type'] = vars['field_type'].capitalize()
+
+ if vars['widget_type'].lower() == 'default':
+ vars['widget_type'] = self.fieldtypes[vars['field_type'].lower()][0]
+
+ vars['widget_type'] = vars['widget_type'].capitalize()
+
+ # camelcase multiword names
+ if vars['field_type'].lower() == 'fixedpoint':
+ vars['field_type'] = 'FixedPoint'
+
+ if vars['field_type'].lower() == 'datetime':
+ vars['field_type'] = 'DateTime'
+
+ if vars['field_type'].lower() == 'date':
+ vars['field_type'] = 'DateTime'
+
+ if vars['widget_type'].lower() == 'inandout':
+ vars['widget_type'] = 'InAndOut'
+
+ if vars['widget_type'].lower() == 'multiselection':
+ vars['widget_type'] = 'MultiSelection'
+
+ if vars['widget_type'].lower() == 'picklist':
+ vars['widget_type'] = 'PickList'
+
+ if vars['widget_type'].lower() == 'referencebrowser':
+ vars['widget_type'] = 'ReferenceBrowser'
+
+ if vars['widget_type'].lower() == 'textarea':
+ vars['widget_type'] = 'TextArea'
+
+ # try to get the zope.schema type, but default to TextLine if no dice
+ try:
+ vars['zopeschema_type'] = self.typemap[vars['field_type'].lower()]
+ except:
+ vars['zopeschema_type'] = self.typemap['unknown']
+
+ # if the widget is the RichWidget, set the type to 'SourceText'
+ if vars['widget_type'].lower() == 'rich':
+ vars['zopeschema_type'] = 'SourceText'
+
+ # if not vars['i18n_domain']:
+ # vars['i18n_domain'] = vars['package_dotted_name']
+
+ vars['content_class_filename'] = file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,244 @@
+"""
+Local templates that are generically useful for every plone related project.
+"""
+from zopeskel.base import var
+from zopeskel.localcommands import ZopeSkelLocalTemplate
+
+class PloneSubTemplate(ZopeSkelLocalTemplate):
+ use_cheetah = True
+ parent_templates = ['plone', 'archetype']
+
+
+class Portlet(PloneSubTemplate):
+ """
+ A plone 3 portlet skeleton
+ """
+ _template_dir = 'templates/plone/portlet'
+ summary = "A Plone 3 portlet"
+
+ vars = [
+ var('portlet_name', 'Portlet name (human readable)', default="Example portlet"),
+ var('portlet_type_name', 'Portlet type name (should not contain spaces)', default="ExamplePortlet"),
+ var('description', 'Portlet description', default=""),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['portlet_filename'] = vars['portlet_type_name'].lower()
+
+ vars['dotted_name'] = "%s.portlets" % vars['package_dotted_name']
+
+
+class View(PloneSubTemplate):
+ """
+ A browser view skeleton
+ """
+ _template_dir = 'templates/plone/view'
+ summary = "A browser view skeleton"
+
+ vars = [
+ var('view_name', 'Browser view name', default="Example"),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['view_filename'] = vars['view_name'].lower().replace(' ', '')
+ vars['view_classname'] = vars['view_name'].replace(' ', '')
+
+
+class ZCMLMetaDirective(PloneSubTemplate):
+ """
+ A zcml meta directive skeleton
+ """
+ _template_dir = 'templates/plone/zcmlmeta'
+ summary = "A ZCML meta directive skeleton"
+
+ vars = [
+ var('directive_name', 'The directive name', default="mydirective"),
+ var('directive_namespace', 'The directive namespace', default="mynamespace"),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['directive_class_name'] = vars['directive_name'].title()
+
+
+class I18nLocale(PloneSubTemplate):
+ """
+ A skeleton for an i18n language
+ """
+ _template_dir = 'templates/plone/i18nlocales'
+ summary = "An i18n locale directory structure"
+
+ vars = [
+ var('language_code', 'The iso-code of the language'),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ # There is no default for language_code, because that makes no sense
+ # To accomodate testing, we introduce a default here.
+
+ language_iso_code = vars['language_code'].lower().strip()
+ vars['language_iso_code'] = language_iso_code and language_iso_code or 'nl'
+
+class Form(PloneSubTemplate):
+ """
+ A form skeleton
+ """
+ _template_dir = 'templates/plone/form'
+ summary = "A form skeleton"
+
+ vars = [
+ var('form_name', 'Form class name', default="ExampleForm"),
+ var('form_label', "Form Title", default='Example Form'),
+ var('form_description', "Form Description", default=''),
+ var('form_actions', 'Comma separated list of form actions', default="Submit"),
+ var('form_invariants', 'Comma separated list of invariants', default=""),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ splitCSV = lambda in_str: [x.strip() for x in in_str.split(",")]
+ vars['form_filename'] = vars['form_name'].lower()
+ vars['form_actions'] = splitCSV(vars['form_actions'])
+ vars['form_invariants'] = splitCSV(vars['form_invariants'].strip())
+
+
+class Z3cForm(PloneSubTemplate):
+ """
+ A zc3 form skeleton
+ """
+ _template_dir = 'templates/archetype/form'
+ summary = "A form skeleton"
+
+ vars = [
+ var('form_name', 'Form name', default="Example"),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['form_filename'] = vars['form_name'].lower()
+
+class FormField(PloneSubTemplate):
+ """
+ A template to add a form field to a form. Essentially this
+ adds a field to Zope 3 schema.
+ """
+ _template_dir = 'templates/plone/formfield'
+ summary = "Schema field for a form"
+
+ _supported_fields = [
+ ("Bool", "Field containin a truth value."),
+ ("Text", "Field containing unicode text."),
+ ("TextLine", "Field containing a single line of unicode text."),
+ ("Datetime", "Field containing a DateTime."),
+ ("Date", "Field containing a date."),
+ ("Choice", "Obect from a source or vocabulary."),
+ ("Password", "Field containing a unicode string without newlines that is a password.")
+ ]
+ _field_description = "\n".join(
+ [" "* 25 + x[0].lower() + " : " + x[1] for x in _supported_fields]
+ )
+
+ vars = [
+ var('form_filename', "Name of the file containing the form in browser.", default="exampleform"),
+ var('field_name', "Name of the field (this should be a unique identifier).", default='examplefield'),
+ var('field_type', "Type of field. Use one of the following \n\n"+_field_description + "\n", default='textline'),
+ var('field_title', '', default='A short summary or label'),
+ var('field_description', 'A description of the field (to be displayed as a hint)', default=''),
+ var('field_required', 'Tells whether a field requires its value to exist (True/False)', default=False),
+ var('field_readonly', "If true, the field's value cannot be changed (True/False)", default=False),
+ var('field_default', 'The field default value may be None or a legal field value', default='None'),
+ var('field_missing_value', 'If a field has no assigned value, set it to this value', default=''),
+ var('field_constraint', 'Specify the name of a function to use for validation', default=''),
+ ]
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ # XXX this should be handled by _map_boolean in base.py
+ # but this template does not inherit from BaseTemplate
+ for var in FormField.vars:
+ if var.name in vars and (type(vars[var.name])==str) and var.default in [True, False, None]:
+ lowered = vars[var.name].lower().strip()
+ if lowered in ['t', 'y', 'true']:
+ vars[var.name] = True
+ elif lowered in ['f', 'n', 'false']:
+ vars[var.name] = False
+ elif lowered == 'none':
+ vars[var.name] = None
+
+ # make the field type case insensitive, if the field type is not in the list of enumerated types
+ # simple use the provided one
+ vars['field_type'] = dict([(x[0].lower(), x) for x in self._supported_fields]).get(vars['field_type'].lower(), (vars['field_type'],))[0]
+
+
+class BrowserLayer(PloneSubTemplate):
+ """
+ A browserlayer skeleton
+ """
+ _template_dir = 'templates/plone/browserlayer'
+ summary = "A Plone browserlayer"
+
+ vars = [
+ var('interface_name', 'Interface name for the browserlayer', default="IMyPackageBrowserLayer"),
+ var('layer_name', "Browser layer name", default='MyPackage'),
+ ]
+
+ def check_vars(self, vars, cmd):
+ """
+ Overloading check_vars to print welcome message and provide sensitive default values
+ """
+
+ print "A BrowserLayer is generally used in packages to be installed in a Plone Site."
+ print "If you didn't choose Register Profile option when creating this package"
+ print "you should probably add a <genericsetup:registerProfile /> directive in"
+ print "the main configure.zcml.\n"
+ package_dotted_name = [vars['namespace_package']]
+ if 'namespace_package2' in vars:
+ package_dotted_name.append(vars['namespace_package2'])
+ package_dotted_name.append(vars['package'])
+
+ layer_name = ''.join([x.capitalize() for x in package_dotted_name])
+ self.vars[1].default = layer_name
+ self.vars[0].default = 'I%sLayer' % (layer_name)
+
+ return super(BrowserLayer, self).check_vars(vars, cmd)
+
+
+ def pre(self, command, output_dir, vars):
+ """
+ you can use package_namespace, package_namespace2, package
+ and package_dotted_name of the parent package here. you get them
+ for free in the vars argument
+ """
+ vars['interface_filename'] = vars['layer_name'].lower() + 'layer'
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone_pas.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone_pas.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/plone_pas.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,140 @@
+"""
+Local templates for the plone PAS zopeskel project
+"""
+from zopeskel.localcommands import ZopeSkelLocalTemplate
+
+class PlonePasSubTemplate(ZopeSkelLocalTemplate):
+ use_cheetah = True
+ marker_name = 'implemented plugins'
+ parent_templates = ['plone_pas']
+
+
+class ExtractionPlugin(PlonePasSubTemplate):
+ """
+ A plone pas extraction plugin
+ """
+ _template_dir = 'templates/plone_pas/extraction'
+ summary = "A Plone PAS Extraction Plugin"
+
+
+class AuthenticationPlugin(PlonePasSubTemplate):
+ """
+ A plone pas authentication plugin
+ """
+ _template_dir = 'templates/plone_pas/authentication'
+ summary = "A Plone PAS Authentication Plugin"
+
+
+class ChallengePlugin(PlonePasSubTemplate):
+ """
+ A plone pas challenge plugin
+ """
+ _template_dir = 'templates/plone_pas/challenge'
+ summary = "A Plone PAS Challenge Plugin"
+
+
+class CredentialsResetPlugin(PlonePasSubTemplate):
+ """
+ A plone pas CredentialsReset plugin
+ """
+ _template_dir = 'templates/plone_pas/credentials_reset'
+ summary = "A Plone PAS CredentialsReset Plugin"
+
+
+class UserAdderPlugin(PlonePasSubTemplate):
+ """
+ A plone pas UserAdder plugin
+ """
+ _template_dir = 'templates/plone_pas/user_adder'
+ summary = "A Plone PAS UserAdder Plugin"
+
+
+class RoleAssignerPlugin(PlonePasSubTemplate):
+ """
+ A plone pas RoleAssigner plugin
+ """
+ _template_dir = 'templates/plone_pas/role_assigner'
+ summary = "A Plone PAS RoleAssigner Plugin"
+
+
+class UserFactoryPlugin(PlonePasSubTemplate):
+ """
+ A plone pas UserFactory plugin
+ """
+ _template_dir = 'templates/plone_pas/user_factory'
+ summary = "A Plone PAS UserFactory Plugin"
+
+
+class AnonymousUserFactoryPlugin(PlonePasSubTemplate):
+ """
+ A plone pas AnonymousUserFactory plugin
+ """
+ _template_dir = 'templates/plone_pas/anonymous_user_factory'
+ summary = "A Plone PAS AnonymousUserFactory Plugin"
+
+
+class PropertiesPlugin(PlonePasSubTemplate):
+ """
+ A plone pas Properties plugin
+ """
+ _template_dir = 'templates/plone_pas/properties'
+ summary = "A Plone PAS Properties Plugin"
+
+
+
+class GroupsPlugin(PlonePasSubTemplate):
+ """
+ A plone pas Groups plugin
+ """
+ _template_dir = 'templates/plone_pas/groups'
+ summary = "A Plone PAS Groups Plugin"
+
+
+class RolesPlugin(PlonePasSubTemplate):
+ """
+ A plone pas Roles plugin
+ """
+ _template_dir = 'templates/plone_pas/roles'
+ summary = "A Plone PAS Roles Plugin"
+
+
+class UpdatePlugin(PlonePasSubTemplate):
+ """
+ A plone pas Update plugin
+ """
+ _template_dir = 'templates/plone_pas/update'
+ summary = "A Plone PAS Update Plugin"
+
+
+class ValidationPlugin(PlonePasSubTemplate):
+ """
+ A plone pas Validation plugin
+ """
+ _template_dir = 'templates/plone_pas/validation'
+ summary = "A Plone PAS Validation Plugin"
+
+
+class UserEnumerationPlugin(PlonePasSubTemplate):
+ """
+ A plone pas UserEnumeration plugin
+ """
+ _template_dir = 'templates/plone_pas/user_enumeration'
+ summary = "A Plone PAS UserEnumeration Plugin"
+
+
+class GroupEnumerationPlugin(PlonePasSubTemplate):
+ """
+ A plone pas GroupEnumeration plugin
+ """
+ _template_dir = 'templates/plone_pas/group_enumeration'
+ summary = "A Plone PAS GroupEnumeration Plugin"
+
+
+class RoleEnumerationPlugin(PlonePasSubTemplate):
+ """
+ A plone pas RoleEnumeration plugin
+ """
+ _template_dir = 'templates/plone_pas/role_enumeration'
+ summary = "A Plone PAS RoleEnumeration Plugin"
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/+content_class_filename+.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/+content_class_filename+.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/+content_class_filename+.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,26 @@
+
+ atapi.${field_type}Field(
+ '${field_name}',
+ storage=atapi.AnnotationStorage(),
+ widget=atapi.${widget_type}Widget(
+ label=_(u"${field_label}"),
+ description=_(u"${field_desc}"),
+ ),
+#if str($required) == 'True'
+ required=${required},
+#end if
+#if str($default) != '' and str($field_type) != 'Computed'
+ default=_(u"${default}"),
+#end if
+#if str($field_type) == 'Reference'
+ relationship='${content_class_filename}_${field_name}',
+ allowed_types=(), # specify portal type names here ('Example Type',)
+ multiValued=False,
+#end if
+#if str($field_type) == 'Computed'
+ expression = '',
+#end if
+#if $a_validator
+ validators=($a_validator),
+#end if
+ ),
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/messagefactory_insert.txt_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/messagefactory_insert.txt_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/messagefactory_insert.txt_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+#*
+This template is added to the main content type template, through a non-standard
+ZopeSkel method!
+*#
+from ${package_dotted_name} import ${package}MessageFactory as _
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/schema_field_bridge.txt_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/schema_field_bridge.txt_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/content/schema_field_bridge.txt_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+ #*
+ This template is added to the main content type template, through a non-standard
+ ZopeSkel method!
+ *#
+ #if $field_type == 'Reference'
+ ${field_name} = atapi.ATReferenceFieldProperty('${field_name}')
+ #else
+ ${field_name} = atapi.ATFieldProperty('${field_name}')
+ #end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/+interface_name+.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/+interface_name+.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/+interface_name+.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+ ${field_name} = schema.${zopeschema_type}(
+ title=_(u"${field_label}"),
+ required=${required},
+ description=_(u"${field_desc}"),
+ #if str($zopeschema_type) == 'Object'
+ schema=Interface, # specify the interface(s) of the addable types here
+ #end if
+ )
+#
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+from ${contenttype_classname} import ${interface_name}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/additional_imports.txt_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/additional_imports.txt_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/atschema/interfaces/additional_imports.txt_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+#*
+This template is added to the main content type interface template, through a
+non-standard ZopeSkel method!
+*#
+from zope import schema
+
+from ${package_dotted_name} import ${package}MessageFactory as _
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/README.txt_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/README.txt_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/README.txt_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,123 @@
+The $contenttype_name content type
+===============================
+
+In this section we are tesing the $contenttype_name content type by performing
+basic operations like adding, updadating and deleting $contenttype_name content
+items.
+
+Adding a new $contenttype_name content item
+--------------------------------
+
+We use the 'Add new' menu to add a new content item.
+
+ >>> browser.getLink('Add new').click()
+
+Then we select the type of item we want to add. In this case we select
+'$contenttype_name' and click the 'Add' button to get to the add form.
+
+ >>> browser.getControl('$contenttype_name').click()
+ >>> browser.getControl(name='form.button.Add').click()
+ >>> '$contenttype_name' in browser.contents
+ True
+
+Now we fill the form and submit it.
+
+ >>> browser.getControl(name='title').value = '$contenttype_name Sample'
+ >>> browser.getControl('Save').click()
+ >>> 'Changes saved' in browser.contents
+ True
+
+And we are done! We added a new '$contenttype_name' content item to the portal.
+
+Updating an existing $contenttype_name content item
+---------------------------------------
+
+Let's click on the 'edit' tab and update the object attribute values.
+
+ >>> browser.getLink('Edit').click()
+ >>> browser.getControl(name='title').value = 'New $contenttype_name Sample'
+ >>> browser.getControl('Save').click()
+
+We check that the changes were applied.
+
+ >>> 'Changes saved' in browser.contents
+ True
+ >>> 'New $contenttype_name Sample' in browser.contents
+ True
+
+Removing a/an $contenttype_name content item
+--------------------------------
+
+If we go to the home page, we can see a tab with the 'New $contenttype_name
+Sample' title in the global navigation tabs.
+
+ >>> browser.open(portal_url)
+ >>> 'New $contenttype_name Sample' in browser.contents
+ True
+
+Now we are going to delete the 'New $contenttype_name Sample' object. First we
+go to the contents tab and select the 'New $contenttype_name Sample' for
+deletion.
+
+ >>> browser.getLink('Contents').click()
+ >>> browser.getControl('New $contenttype_name Sample').click()
+
+We click on the 'Delete' button.
+
+ >>> browser.getControl('Delete').click()
+ >>> 'Item(s) deleted' in browser.contents
+ True
+
+So, if we go back to the home page, there is no longer a 'New $contenttype_name
+Sample' tab.
+
+ >>> browser.open(portal_url)
+ >>> 'New $contenttype_name Sample' in browser.contents
+ False
+
+Adding a new $contenttype_name content item as contributor
+------------------------------------------------
+
+Not only site managers are allowed to add $contenttype_name content items, but
+also site contributors.
+
+Let's logout and then login as 'contributor', a portal member that has the
+contributor role assigned.
+
+ >>> browser.getLink('Log out').click()
+ >>> browser.open(portal_url + '/login_form')
+ >>> browser.getControl(name='__ac_name').value = 'contributor'
+ >>> browser.getControl(name='__ac_password').value = default_password
+ >>> browser.getControl(name='submit').click()
+ >>> browser.open(portal_url)
+
+We use the 'Add new' menu to add a new content item.
+
+ >>> browser.getLink('Add new').click()
+
+We select '$contenttype_name' and click the 'Add' button to get to the add form.
+
+ >>> browser.getControl('$contenttype_name').click()
+ >>> browser.getControl(name='form.button.Add').click()
+ >>> '$contenttype_name' in browser.contents
+ True
+
+Now we fill the form and submit it.
+
+ >>> browser.getControl(name='title').value = '$contenttype_name Sample'
+ >>> browser.getControl('Save').click()
+ >>> 'Changes saved' in browser.contents
+ True
+
+Done! We added a new $contenttype_name content item logged in as contributor.
+
+Finally, let's login back as manager.
+
+ >>> browser.getLink('Log out').click()
+ >>> browser.open(portal_url + '/login_form')
+ >>> browser.getControl(name='__ac_name').value = portal_owner
+ >>> browser.getControl(name='__ac_password').value = default_password
+ >>> browser.getControl(name='submit').click()
+ >>> browser.open(portal_url)
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/config.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/config.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/config.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ '$(contenttype_classname)': '$(add_permission_name)',
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/+content_class_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/+content_class_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/+content_class_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,67 @@
+"""Definition of the $contenttype_name content type
+"""
+
+from zope.interface import implements
+
+from Products.Archetypes import atapi
+#if str($folderish) == 'True'
+from Products.ATContentTypes.content import folder
+#else
+from Products.ATContentTypes.content import base
+#end if
+from Products.ATContentTypes.content import schemata
+
+# -*- Message Factory Imported Here -*-
+
+from ${package_dotted_name}.interfaces import ${interface_name}
+from ${package_dotted_name}.config import PROJECTNAME
+
+#if str($folderish) == 'True'
+${schema_name} = folder.ATFolderSchema.copy() + atapi.Schema((
+#else
+${schema_name} = schemata.ATContentTypeSchema.copy() + atapi.Schema((
+#end if
+
+ # -*- Your Archetypes field definitions here ... -*-
+
+))
+
+#if str($folderish) == 'True'
+# Set storage on fields copied from ATFolderSchema, making sure
+# they work well with the python bridge properties.
+#else
+# Set storage on fields copied from ATContentTypeSchema, making sure
+# they work well with the python bridge properties.
+#end if
+
+${schema_name}['title'].storage = atapi.AnnotationStorage()
+${schema_name}['description'].storage = atapi.AnnotationStorage()
+
+#if str($folderish) == 'True'
+schemata.finalizeATCTSchema(
+ ${schema_name},
+ folderish=True,
+ moveDiscussion=False
+)
+#else
+schemata.finalizeATCTSchema(${schema_name}, moveDiscussion=False)
+#end if
+
+
+#if str($folderish) == 'True'
+class ${contenttype_classname}(folder.ATFolder):
+#else
+class ${contenttype_classname}(base.ATCTContent):
+#end if
+ """${contenttype_description}"""
+ implements(${interface_name})
+
+ meta_type = "${contenttype_classname}"
+ schema = ${schema_name}
+
+ title = atapi.ATFieldProperty('title')
+ description = atapi.ATFieldProperty('description')
+
+ # -*- Your ATSchema to Python Property Bridges Here ... -*-
+
+atapi.registerType(${contenttype_classname}, PROJECTNAME)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/content/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+ <class class=".${content_class_filename}.${contenttype_classname}">
+ <require
+ permission="zope2.View"
+ interface="..interfaces.${interface_name}"
+ />
+ </class>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/+content_class_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/+content_class_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/+content_class_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+from zope.interface import Interface
+# -*- Additional Imports Here -*-
+
+
+class $(interface_name)(Interface):
+ """$(contenttype_description)"""
+
+ # -*- schema definition goes here -*-
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/interfaces/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+from ${content_class_filename} import $(interface_name)
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/factorytool.xml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/factorytool.xml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/factorytool.xml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ <type portal_type="${contenttype_name}" />
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/rolemap.xml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/rolemap.xml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/rolemap.xml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<?xml version="1.0"?>
+#<rolemap>
+# <permissions>
+# <!-- -*- extra stuff goes here -*- -->
+ <permission name="$add_permission_name" acquire="False">
+ <role name="Manager" />
+ <role name="Contributor" />
+ </permission>
+# </permissions>
+#</rolemap>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/+types_xml_filename+.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/+types_xml_filename+.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types/+types_xml_filename+.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<object name="${contenttype_name}"
+ meta_type="Factory-based Type Information with dynamic views"
+ i18n:domain="${package_dotted_name}" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title" i18n:translate="">${contenttype_name}</property>
+ <property name="description"
+ i18n:translate="">${contenttype_description}</property>
+ <property name="content_meta_type">${contenttype_classname}</property>
+#if str($folderish) == 'True'
+ <property name="content_icon">folder_icon.gif</property>
+#else
+ <property name="content_icon">document_icon.gif</property>
+#end if
+ <property name="product">${package_dotted_name}</property>
+ <property name="factory">add${contenttype_classname}</property>
+ <property name="immediate_view">atct_edit</property>
+ <property name="global_allow">${global_allow}</property>
+ <property name="filter_content_types">False</property>
+ <property name="allow_discussion">${allow_discussion}</property>
+ <property name="default_view">base_view</property>
+ <property name="view_methods">
+ <element value="base_view" />
+ </property>
+ <alias from="(Default)" to="(dynamic view)" />
+ <alias from="edit" to="atct_edit" />
+ <alias from="sharing" to="@@sharing" />
+ <alias from="view" to="(selected layout)" />
+ <action title="View" action_id="view" category="object" condition_expr=""
+#if str($folderish) == 'True'
+ url_expr="string:\${folder_url}/" visible="True">
+#else
+ url_expr="string:\${object_url}/" visible="True">
+#end if
+ <permission value="View" />
+ </action>
+ <action title="Edit" action_id="edit" category="object" condition_expr=""
+ url_expr="string:\${object_url}/edit" visible="True">
+ <permission value="Modify portal content" />
+ </action>
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types.xml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types.xml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/archetype/contenttype/profiles/default/types.xml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+ <object name="${contenttype_name}"
+ meta_type="Factory-based Type Information with dynamic views" />
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/browser/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+#<configure xmlns="http://namespaces.zope.org/zope"
+# xmlns:browser="http://namespaces.zope.org/browser"
+# i18n_domain="${namespace_package}.${package}">
+#
+# <!-- -*- extra stuff goes here -*- -->
+
+ <!-- If you are using plone version 3.0, you will need to include the
+ plone.browserlayer package in your buildout and uncomment the following
+ line in order to use ${interface_name} as a layer attribute -->
+ <!--
+ <include package="plone.browserlayer" />
+ -->
+ <!-- Example of browser component with ${interface_name} layer attribute -->
+ <!--
+ <browser:page
+ name="my-view"
+ for="*"
+ permission="zope.Public"
+ template="my-view.pt"
+ layer="..interfaces.${interface_name}"
+ />
+ -->
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/+interface_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/+interface_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/+interface_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+from zope.interface import Interface
+# -*- Additional Imports Here -*-
+
+
+class $(interface_name)(Interface):
+ """ A layer specific to this product.
+ Is registered using browserlayer.xml
+ """
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/interfaces/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+#
+from ${interface_filename} import $(interface_name)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/default/browserlayer.xml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/default/browserlayer.xml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/browserlayer/profiles/default/browserlayer.xml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+#<?xml version="1.0"?>
+#<layers>
+# <!-- -*- extra stuff goes here -*- -->
+
+ <layer name="${layer_name}"
+ interface="${namespace_package}.${package}.interfaces.${interface_filename}.${interface_name}"
+ />
+#</layers>
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+# # -*- extra stuff goes here -*-
+from zope.i18nmessageid import MessageFactory
+
+${package}MessageFactory = MessageFactory('${namespace_package}.${package}')
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/+form_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/+form_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/+form_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,35 @@
+from zope import interface, schema
+from zope.formlib import form
+from Products.Five.formlib import formbase
+from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
+
+from ${package_dotted_name} import ${package}MessageFactory as _
+
+class I${form_name}Schema(interface.Interface):
+ # -*- extra stuff goes here -*-
+
+#for $invariant in $form_invariants
+#if $invariant
+ @interface.invariant
+ def invariant_${invariant}(input):
+ pass
+ # Check input values example:
+ # if input.name != 'value':
+ # raise interface.Invalid(_(u"Some error occurred !"))
+#end if
+#end for
+
+class ${form_name}(formbase.PageForm):
+ form_fields = form.FormFields(I${form_name}Schema)
+ label = _(u'${form_label}')
+ description = _(u'${form_description}')
+
+#for $action in $form_actions
+ @form.action('${action}')
+ def action${action}(self, action, data):
+ pass
+ # Put the action handler code here
+
+#end for
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/browser/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,13 @@
+#<configure xmlns="http://namespaces.zope.org/zope"
+# xmlns:browser="http://namespaces.zope.org/browser"
+# i18n_domain="${package_dotted_name}">
+#
+# <!-- -*- extra stuff goes here -*- -->
+
+ <browser:page
+ for="*"
+ name="${form_filename}"
+ class=".${form_filename}.${form_name}"
+ permission="zope.Public" />
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:five="http://namespaces.zope.org/five"
+# xmlns:i18n="http://namespaces.zope.org/i18n"
+# i18n_domain="${namespace_package}.${package}">
+
+# <!-- -*- extra stuff goes here -*- -->
+ <include package=".browser" />
+
+#</configure>
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/form.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/form.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/form/form.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,184 @@
+from Products.Five.formlib import formbase
+
+from zope import interface, schema
+from zope.formlib import form
+from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
+
+
+def failing_constraint(value):
+ return 1 == 2
+
+
+def successfull_constraint(value):
+ return 1 == 1
+
+
+class IObjectSchema(interface.Interface):
+ test_field = schema.Text(
+ title=u'Test field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+ default=u'default',
+ missing_value=u'missing value')
+
+class IExampleSchema(interface.Interface):
+ """
+ Field types:
+ Datetime - Field containing a DateTime
+ Date - Field containing a date
+ Timedelta - Field containing a timedelta
+ Password - Field containing a unicode string without newlines that is a
+ password
+ Object - Field containing an Object value
+ URI - A field containing an absolute URI
+ ASCII - Field containing a 7-bit ASCII string. No characters > DEL
+ (chr(127)) are allowed
+ ASCIILine - Field containing a 7-bit ASCII string without newlines
+ Bytes - Field containing a byte string (like the python str)
+ BytesLine - Field containing a byte string without newlines
+ Tuple - Field containing a value that implements the API of a
+ conventional Python tuple
+ List - Field containing a value that implements the API of a
+ conventional Python list
+ Set - Field containing a value that implements the API of a
+ conventional Python standard library sets
+ FrozenSet - Field containing a value that implements the API of a
+ conventional Python 2.4+ frozenset
+ Dict - Field containing a conventional dict
+ SourceText - Field for source text of object
+ Id - A field containing a unique identifier
+ A unique identifier is either an absolute URI or a dotted name.
+ If it's a dotted name, it should have a module/package name as a
+ prefix
+ DottedName - Dotted name field
+ InterfaceField - Fields with a value that is an interface (implementing
+ zope.interface.Interface)
+
+ Field types arguments:
+ title - A short summary or label
+ description - A description of the field (to be displayed as a hint)
+ required - Tells whether a field requires its value to exist
+ readonly - If true, the field's value cannot be changed
+ default - The field default value may be None or a legal field value
+ missing_value - If a field has no assigned value, set it to this value
+ constraint - function checking a constraint on the field
+ """
+
+ # Text - Field containing a unicode string
+ text_field = schema.Text(
+ title=u'Text field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+ default=u'default value',
+ missing_value=u'missing value'
+ )
+
+ # TextLine - Field containing a unicode string without newlines
+ textline_field = schema.TextLine(
+ title=u'Textline field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+ default=u'default value',
+ missing_value=u'missing value',
+ constraint=successfull_constraint
+ )
+
+ # Int - Field containing an Integer Value
+ int_field = schema.Int(
+ title=u'Integer field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+ default=0,
+ missing_value=1,
+ min=0,
+ max=10
+ )
+
+ # Bool - Boolean Field
+ bool_field = schema.Bool(
+ title=u'Boolean field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+# default=True,
+# missing_value=True
+ )
+
+ # Float - Field containing a Float
+ float_field = schema.Float(
+ title=u'Float field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+# default=0.0,
+# missing_value=0.0
+ )
+
+ # Choice - Field whose value is contained in a predefined set
+ # Only one, values or vocabulary, may be specified for a given choice
+ choice_field = schema.Choice(
+ title=u'Choice field',
+ description=u'field description',
+ required=True,
+ readonly=False,
+# default='Title 2',
+# missing_value='Option 2',
+# Only one of the arguments: vocabulary, source or values may be used
+ vocabulary=SimpleVocabulary((
+ SimpleTerm(value=1, token='Option 1', title='Title 1'),
+ SimpleTerm(value=2, token='Option 2', title='Title 2')
+ ))
+# source=VocabularyExample
+# values=['Option 1', 'Option 2'],
+ )
+
+# object_field = schema.Object(
+# title=u'Object field',
+# description=u'field description',
+# required=True,
+# readonly=False,
+# default=None,
+# missing_value=None,
+# schema=IObjectSchema
+# )
+
+
+class ExampleForm(formbase.PageForm):
+ form_fields = form.FormFields(IExampleSchema)
+ # Put here the label to be displayed as form title
+ label = u'Form label'
+ # Put here the form description to be displayed under the form title
+ description = u'Form short description'
+
+ # Instead of 'Submit button' put here the label of the form submit button
+ @form.action('Submit button', failure='handle_failure')
+ def handle_success(self, action, data):
+ """
+ Called when the action was submitted and there are NO validation
+ errors.
+
+ This form is generated with ZopeSkel. Please make sure you fill in
+ the implementation of the form processing.
+
+ """
+ # Put here the feedback to show in case the form submission succeeded
+ self.status = 'The handle_success method of the %s form is not \
+ implemented.' % (self.__class__.__name__)
+
+ # Put here the code for processing the form
+
+
+ def handle_failure(self, action, data, errors):
+ """
+ Called when the action was submitted and there are validation errors.
+
+ """
+ # Put here the feedback message to show in case the validation failed
+ self.status = 'Errors occured while submitting the form'
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/browser/+form_filename+.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/browser/+form_filename+.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/formfield/browser/+form_filename+.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+
+ ${field_name} = schema.${field_type}(
+ title=u'${field_title}',
+ description=u'${field_description}',
+ required=${field_required},
+ readonly=${field_readonly},
+ default=${field_default},
+#if str($field_missing_value).strip()
+ missing_value=${field_missing_value},
+#end if
+#if str($field_constraint)
+ constraint=${field_constraint},
+#end if
+#if $field_type == 'Choice'
+ vocabulary=SimpleVocabulary((
+ SimpleTerm(value=1, token='Option 1', title='Title 1'),
+ SimpleTerm(value=2, token='Option 2', title='Title 2')
+ ))
+#end if
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:five="http://namespaces.zope.org/five"
+# xmlns:i18n="http://namespaces.zope.org/i18n"
+# i18n_domain="${namespace_package}.${package}">
+
+# <!-- -*- extra stuff goes here -*- -->
+ <i18n:registerTranslations directory="locales" />
+
+#</configure>
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/i18nlocales/locales/+language_iso_code+/LC_MESSAGES/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+The <packagename>.po file containing language-specific translations for your product will go here when it is generated.
+
+For more information on internationalization and the difference between the i18n directory and this locales directory, read here:
+
+http://maurits.vanrees.org/weblog/archive/2007/09/i18n-locales-and-plone-3.0
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+# # -*- extra stuff goes here -*-
+from zope.i18nmessageid import MessageFactory
+
+${package}MessageFactory = MessageFactory('${namespace_package}.${package}')
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:five="http://namespaces.zope.org/five"
+# xmlns:i18n="http://namespaces.zope.org/i18n"
+# i18n_domain="${namespace_package}.${package}">
+
+# <!-- -*- extra stuff goes here -*- -->
+ <include package=".portlets" />
+
+#</configure>
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.pt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.pt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.pt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+<dl class="portlet portlet${portlet_type_name}"
+ i18n:domain="${package_dotted_name}">
+
+ <dt class="portletHeader">
+ <span class="portletTopLeft"></span>
+ <span>
+ Header
+ </span>
+ <span class="portletTopRight"></span>
+ </dt>
+
+ <dd class="portletItem odd">
+ Body text
+ </dd>
+
+ <dd class="portletFooter">
+ <span class="portletBottomLeft"></span>
+ <span>
+ Footer
+ </span>
+ <span class="portletBottomRight"></span>
+ </dd>
+
+</dl>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/+portlet_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,99 @@
+from zope.interface import Interface
+from zope.interface import implements
+
+from plone.app.portlets.portlets import base
+from plone.portlets.interfaces import IPortletDataProvider
+
+from zope import schema
+from zope.formlib import form
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+
+from ${package_dotted_name} import ${package}MessageFactory as _
+
+from zope.i18nmessageid import MessageFactory
+__ = MessageFactory("plone")
+
+class I${portlet_type_name}(IPortletDataProvider):
+ """A portlet
+
+ It inherits from IPortletDataProvider because for this portlet, the
+ data that is being rendered and the portlet assignment itself are the
+ same.
+ """
+
+ # TODO: Add any zope.schema fields here to capture portlet configuration
+ # information. Alternatively, if there are no settings, leave this as an
+ # empty interface - see also notes around the add form and edit form
+ # below.
+
+ # some_field = schema.TextLine(title=_(u"Some field"),
+ # description=_(u"A field to use"),
+ # required=True)
+
+
+class Assignment(base.Assignment):
+ """Portlet assignment.
+
+ This is what is actually managed through the portlets UI and associated
+ with columns.
+ """
+
+ implements(I${portlet_type_name})
+
+ # TODO: Set default values for the configurable parameters here
+
+ # some_field = u""
+
+ # TODO: Add keyword parameters for configurable parameters here
+ # def __init__(self, some_field=u''):
+ # self.some_field = some_field
+
+ def __init__(self):
+ pass
+
+ @property
+ def title(self):
+ """This property is used to give the title of the portlet in the
+ "manage portlets" screen.
+ """
+ return __(u"${portlet_name}")
+
+
+class Renderer(base.Renderer):
+ """Portlet renderer.
+
+ This is registered in configure.zcml. The referenced page template is
+ rendered, and the implicit variable 'view' will refer to an instance
+ of this class. Other methods can be added and referenced in the template.
+ """
+
+ render = ViewPageTemplateFile('${portlet_filename}.pt')
+
+
+# NOTE: If this portlet does not have any configurable parameters, you can
+# inherit from NullAddForm and remove the form_fields variable.
+
+class AddForm(base.AddForm):
+ """Portlet add form.
+
+ This is registered in configure.zcml. The form_fields variable tells
+ zope.formlib which fields to display. The create() method actually
+ constructs the assignment that is being added.
+ """
+ form_fields = form.Fields(I${portlet_type_name})
+
+ def create(self, data):
+ return Assignment(**data)
+
+
+# NOTE: IF this portlet does not have any configurable parameters, you can
+# remove this class definition and delete the editview attribute from the
+# <plone:portlet /> registration in configure.zcml
+
+class EditForm(base.EditForm):
+ """Portlet edit form.
+
+ This is registered with configure.zcml. The form_fields variable tells
+ zope.formlib which fields to display.
+ """
+ form_fields = form.Fields(I${portlet_type_name})
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/portlets/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:plone="http://namespaces.plone.org/plone"
+# i18n_domain="${package_dotted_name}">
+#
+# <!-- Ensure Plone's portlets ZCML has already been processed; without
+# this, we may get a permission lookup error
+# -->
+# <include package="plone.app.portlets" />
+#
+# <!-- -*- extra stuff goes here -*- -->
+
+ <plone:portlet
+ name="${dotted_name}.${portlet_type_name}"
+ interface=".${portlet_filename}.I${portlet_type_name}"
+ assignment=".${portlet_filename}.Assignment"
+ view_permission="zope2.View"
+ edit_permission="cmf.ManagePortal"
+ renderer=".${portlet_filename}.Renderer"
+ addview=".${portlet_filename}.AddForm"
+ editview=".${portlet_filename}.EditForm"
+ />
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/metadata.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/metadata.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/metadata.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<metadata>
+ <version>1000</version>
+</metadata>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/portlets.xml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/portlets.xml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/profiles/default/portlets.xml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,23 @@
+#<?xml version="1.0"?>
+#<!-- This file is used to register new types of portlets. It can also
+# be used to register completely new column types. See CMFPlone's version
+# of this file for more information.
+# -->
+#<portlets
+# xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+# i18n:domain="plone">
+# <!-- -*- extra stuff goes here -*- -->
+
+ <!-- to have your portlet's title and description translated in
+ @@manage-portlets, provide the messageids for the i18n:domain plone
+ (see http://dev.plone.org/plone/ticket/9631 or
+ http://dev.plone.org/plone/ticket/9090) for more information on
+ internationalization with portlets or in plone in general -->
+ <portlet
+ addview="${dotted_name}.${portlet_type_name}"
+ title="${portlet_name}"
+ description="${description}"
+ i18n:attributes="title; description"
+ />
+
+#</portlets>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/base_+portlet_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/base_+portlet_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/base_+portlet_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+
+from Testing import ZopeTestCase as ztc
+
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import onsetup
+
+ at onsetup
+def setup_product():
+ """Set up additional products and ZCML required to test this product.
+
+ The @onsetup decorator causes the execution of this body to be deferred
+ until the setup of the Plone site testing layer.
+ """
+
+ # Load the ZCML configuration for this package and its dependencies
+
+ fiveconfigure.debug_mode = True
+ import ${dotted_name}
+ zcml.load_config('configure.zcml', ${dotted_name})
+ fiveconfigure.debug_mode = False
+
+ # We need to tell the testing framework that these products
+ # should be available. This can't happen until after we have loaded
+ # the ZCML.
+
+ ztc.installPackage('${dotted_name}')
+
+# The order here is important: We first call the deferred function and then
+# let PloneTestCase install it during Plone site setup
+
+setup_product()
+ptc.setupPloneSite(products=['${dotted_name}'])
+
+
+class TestCase(ptc.PloneTestCase):
+ """Base class used for test cases
+ """
+
+
+class FunctionalTestCase(ptc.FunctionalTestCase):
+ """Test case class used for functional (doc-)tests
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/test_+portlet_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/test_+portlet_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/portlet/tests/test_+portlet_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,94 @@
+from zope.component import getUtility, getMultiAdapter
+
+from plone.portlets.interfaces import IPortletType
+from plone.portlets.interfaces import IPortletManager
+from plone.portlets.interfaces import IPortletAssignment
+from plone.portlets.interfaces import IPortletDataProvider
+from plone.portlets.interfaces import IPortletRenderer
+
+from plone.app.portlets.storage import PortletAssignmentMapping
+
+from ${dotted_name} import ${portlet_filename}
+from ${dotted_name}.tests.base_${portlet_filename} import TestCase
+
+
+class TestPortlet(TestCase):
+
+ def afterSetUp(self):
+ self.setRoles(('Manager',))
+
+ def test_portlet_type_registered(self):
+ portlet = getUtility(IPortletType, name='${dotted_name}.${portlet_type_name}')
+ self.assertEquals(portlet.addview, '${dotted_name}.${portlet_type_name}')
+
+ def test_interfaces(self):
+ # TODO: Pass any keywoard arguments to the Assignment constructor
+ portlet = ${portlet_filename}.Assignment()
+ self.failUnless(IPortletAssignment.providedBy(portlet))
+ self.failUnless(IPortletDataProvider.providedBy(portlet.data))
+
+ def test_invoke_add_view(self):
+ portlet = getUtility(IPortletType, name='${dotted_name}.${portlet_type_name}')
+ mapping = self.portal.restrictedTraverse('++contextportlets++plone.leftcolumn')
+ for m in mapping.keys():
+ del mapping[m]
+ addview = mapping.restrictedTraverse('+/' + portlet.addview)
+
+ # TODO: Pass a dictionary containing dummy form inputs from the add form
+ addview.createAndAdd(data={})
+
+ self.assertEquals(len(mapping), 1)
+ self.failUnless(isinstance(mapping.values()[0], ${portlet_filename}.Assignment))
+
+ # NOTE: This test can be removed if the portlet has no edit form
+ def test_invoke_edit_view(self):
+ mapping = PortletAssignmentMapping()
+ request = self.folder.REQUEST
+
+ mapping['foo'] = ${portlet_filename}.Assignment()
+ editview = getMultiAdapter((mapping['foo'], request), name='edit')
+ self.failUnless(isinstance(editview, ${portlet_filename}.EditForm))
+
+ def test_obtain_renderer(self):
+ context = self.folder
+ request = self.folder.REQUEST
+ view = self.folder.restrictedTraverse('@@plone')
+ manager = getUtility(IPortletManager, name='plone.rightcolumn', context=self.portal)
+
+ # TODO: Pass any keywoard arguments to the Assignment constructor
+ assignment = ${portlet_filename}.Assignment()
+
+ renderer = getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
+ self.failUnless(isinstance(renderer, ${portlet_filename}.Renderer))
+
+
+class TestRenderer(TestCase):
+
+ def afterSetUp(self):
+ self.setRoles(('Manager',))
+
+ def renderer(self, context=None, request=None, view=None, manager=None, assignment=None):
+ context = context or self.folder
+ request = request or self.folder.REQUEST
+ view = view or self.folder.restrictedTraverse('@@plone')
+ manager = manager or getUtility(IPortletManager, name='plone.rightcolumn', context=self.portal)
+
+ # TODO: Pass any default keywoard arguments to the Assignment constructor
+ assignment = assignment or ${portlet_filename}.Assignment()
+ return getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
+
+ def test_render(self):
+ # TODO: Pass any keywoard arguments to the Assignment constructor
+ r = self.renderer(context=self.portal, assignment=${portlet_filename}.Assignment())
+ r = r.__of__(self.folder)
+ r.update()
+ output = r.render()
+ # TODO: Test output
+
+
+def test_suite():
+ from unittest import TestSuite, makeSuite
+ suite = TestSuite()
+ suite.addTest(makeSuite(TestPortlet))
+ suite.addTest(makeSuite(TestRenderer))
+ return suite
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+# # -*- extra stuff goes here -*-
+from zope.i18nmessageid import MessageFactory
+
+${package}MessageFactory = MessageFactory('${namespace_package}.${package}')
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.pt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.pt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.pt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ lang="en"
+ metal:use-macro="here/main_template/macros/master"
+ i18n:domain="${package_dotted_name}">
+<body>
+ <div metal:fill-slot="main">
+ <tal:main-macro metal:define-macro="main"
+ tal:define="testview view/test">
+
+ <span tal:content="testview/dummy">test</span>
+
+ </tal:main-macro>
+ </div>
+</body>
+</html>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/+view_filename+view.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,42 @@
+from zope.interface import implements, Interface
+
+from Products.Five import BrowserView
+from Products.CMFCore.utils import getToolByName
+
+from ${package_dotted_name} import ${package}MessageFactory as _
+
+
+class I${view_classname}View(Interface):
+ """
+ ${view_name} view interface
+ """
+
+ def test():
+ """ test method"""
+
+
+class ${view_classname}View(BrowserView):
+ """
+ ${view_name} browser view
+ """
+ implements(I${view_classname}View)
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ @property
+ def portal_catalog(self):
+ return getToolByName(self.context, 'portal_catalog')
+
+ @property
+ def portal(self):
+ return getToolByName(self.context, 'portal_url').getPortalObject()
+
+ def test(self):
+ """
+ test method
+ """
+ dummy = _(u'a dummy string')
+
+ return {'dummy': dummy}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/browser/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:browser="http://namespaces.zope.org/browser"
+# i18n_domain="${package_dotted_name}">
+#
+# <!-- -*- extra stuff goes here -*- -->
+
+ <browser:page
+ for="*"
+ name="${view_filename}_view"
+ class=".${view_filename}view.${view_classname}View"
+ template="${view_filename}view.pt"
+ allowed_interface=".${view_filename}view.I${view_classname}View"
+ permission="zope.Public"
+ />
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/view/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:five="http://namespaces.zope.org/five"
+# xmlns:i18n="http://namespaces.zope.org/i18n"
+# i18n_domain="${namespace_package}.${package}">
+
+# <!-- -*- extra stuff goes here -*- -->
+ <include package=".browser" />
+
+#</configure>
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/configure.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/configure.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/configure.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:five="http://namespaces.zope.org/five"
+# xmlns:i18n="http://namespaces.zope.org/i18n"
+# i18n_domain="${namespace_package}.${package}">
+
+# <!-- -*- extra stuff goes here -*- -->
+ <include package=".meta" />
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/meta.zcml_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/meta.zcml_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/meta.zcml_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+#<configure
+# xmlns="http://namespaces.zope.org/zope"
+# xmlns:meta="http://namespaces.zope.org/meta">
+#
+# <!-- -*- extra stuff goes here -*- -->
+
+ <meta:directive
+ name="$directive_name"
+ namespace="http://namespaces.zope.org/${directive_namespace}"
+ schema=".metadirectives.I${directive_class_name}Directive"
+ handler=".metaconfigure.${directive_class_name}Directive"
+ />
+
+#</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metaconfigure.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metaconfigure.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metaconfigure.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+\#from zope.app.component.metaconfigure import handler
+\#from zope.app.component.interface import provideInterface
+\#from zope.configuration.exceptions import ConfigurationError
+
+\#\# -*- extra stuff goes here -*-
+
+def ${directive_class_name}Directive(_context, name=None, for_=None, factory=None):
+ """
+ register the ${directive_name} directive
+ """
+ if name is None or for_ is None or factory is None:
+ raise ConfigurationError(
+ "You must specify the 'name', the 'for' and the 'factory' attributes.")
+
+ # # the following is just an example
+ # _context.action(
+ # discriminator = ('${directive_class_name}', name),
+ # callable = handler,
+ # args = ('provideAdapter', (for_,),
+ # IExampleInterface, name, factory, _context.info)
+ # )
+ #
+ # for_ = tuple(for_)
+ #
+ # for iface in for_:
+ # if iface is not None:
+ # _context.action( discriminator = None,
+ # callable = provideInterface,
+ # args = ('', iface)
+ # )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metadirectives.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metadirectives.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone/zcmlmeta/meta/metadirectives.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+\#from zope.interface import Interface
+\#from zope.schema import TextLine
+\#from zope.configuration.fields import GlobalInterface, GlobalObject
+
+\#\# -*- extra stuff goes here -*-
+
+class I${directive_class_name}Directive(Interface):
+ """
+ Defines a schema for ${directive_name} directive
+ (The attributes are given as example)
+ """
+
+ name = TextLine(
+ title=u"Name",
+ description=u"The name of the ${directive_name} directive.",
+ required=True
+ )
+
+ for_ = GlobalInterface(
+ title=u"interface",
+ description=u"""Specifies the interface for which the directive is
+ registered.""",
+ required=True
+ )
+
+ factory = GlobalObject(
+ title=u"hander",
+ description=u"The factory",
+ required=True
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IAnonymousUserFactoryPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.anonymous_user_factory.AnonymousUserFactoryPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import anonymous_user_factory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/anonymous_user_factory.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/anonymous_user_factory.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/anonymous_user_factory/plugins/anonymous_user_factory.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class AnonymousUserFactoryPlugin(BasePlugin):
+ """ Create a new anonymous IPropertiedUser.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('createAnonymousUser')
+ def createAnonymousUser(self):
+ """Return an anonymous user, if possible.
+
+ o Return None to allow another plugin, or the default, to fire.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IAuthenticationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.authentication.AuthenticationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import authentication
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/authentication.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/authentication.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/authentication/plugins/authentication.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,28 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class AuthenticationPlugin(BasePlugin):
+ """ Map credentials to a user ID.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('authenticateCredentials')
+ def authenticateCredentials(self, credentials):
+
+ """ credentials -> (userid, login)
+
+ o 'credentials' will be a mapping, as returned by IExtractionPlugin.
+
+ o Return a tuple consisting of user ID (which may be different
+ from the login name) and login
+
+ o If the credentials cannot be authenticated, return None.
+ """
+ user_id = ''
+ user_login = ''
+
+ \#add your code here
+
+ return (user_id, user_login)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IChallengePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.challenge.ChallengePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import challenge
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/challenge.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/challenge.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/challenge/plugins/challenge.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,41 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class ChallengePlugin(BasePlugin):
+ """Initiate a challenge to the user to provide credentials.
+
+ Challenge plugins have an attribute 'protocol' representing
+ the protocol the plugin operates under, defaulting to None.
+
+ Plugins operating under the same protocol will all be given an
+ attempt to fire. The first plugin of a protocol group that
+ successfully fires establishes the protocol of the overall
+ challenge.
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('challenge')
+ def challenge(self, request, response):
+
+ """ Assert via the response that credentials will be gathered.
+
+ Takes a REQUEST object and a RESPONSE object.
+
+ Returns True if it fired, False otherwise.
+
+ Two common ways to initiate a challenge:
+
+ - Add a 'WWW-Authenticate' header to the response object.
+
+ NOTE: add, since the HTTP spec specifically allows for
+ more than one challenge in a given response.
+
+ - Cause the response object to redirect to another URL (a
+ login form page, for instance)
+ """
+
+ \# add your code here
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.ICredentialsResetPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.credentials_reset.CredentialsResetPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import credentials_reset
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/credentials_reset.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/credentials_reset.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_reset/plugins/credentials_reset.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class CredentialsResetPlugin(BasePlugin):
+ """ Callback: user has logged out.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('resetCredentials')
+ def resetCredentials(self, request, response):
+ """ Scribble as appropriate.
+ """
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.ICredentialsUpdatePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.credentials_update.CredentialsUpdatePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import credentials_update
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/credentials_update.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/credentials_update.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/credentials_update/plugins/credentials_update.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class CredentialsUpdatePlugin(BasePlugin):
+ """ Callback: user has changed her password.
+
+ This interface is not responsible for the actual password change,
+ it is used after a successful password change event.
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('updateCredentials')
+ def updateCredentials(self, request, response, login, new_password):
+ """ Scribble as appropriate.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IExtractionPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.extraction.ExtractionPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import extraction
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/extraction.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/extraction.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/extraction/plugins/extraction.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class ExtractionPlugin(BasePlugin):
+ """Extracts login name and credentials from a request.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('extractCredentials')
+ def extractCredentials(self, request):
+ """request -> {...}
+
+ o Return a mapping of any derived credentials.
+
+ o Return an empty mapping to indicate that the plugin found no
+ appropriate credentials.
+ """
+ creds = {}
+
+ \#add your code here
+
+ return creds
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IGroupEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.group_enumeration.GroupEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import group_enumeration
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/group_enumeration.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/group_enumeration.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/group_enumeration/plugins/group_enumeration.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,63 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class GroupEnumerationPlugin( BasePlugin ):
+ """Allow querying groups by ID, and searching for groups.
+
+ o XXX: can these be done by a single plugin?
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('enumerateGroups')
+ def enumerateGroups(self,
+ id=None,
+ exact_match=False,
+ sort_by=None,
+ max_results=None,
+ **kw):
+ """ -> ( group_info_1, ... group_info_N )
+
+ o Return mappings for groups matching the given criteria.
+
+ o 'id' in combination with 'exact_match' true, will
+ return at most one mapping per supplied ID ('id' and 'login'
+ may be sequences).
+
+ o If 'exact_match' is False, then 'id' may be treated by
+ the plugin as "contains" searches (more complicated searches
+ may be supported by some plugins using other keyword arguments).
+
+ o If 'sort_by' is passed, the results will be sorted accordingly.
+ known valid values are 'id' (some plugins may support others).
+
+ o If 'max_results' is specified, it must be a positive integer,
+ limiting the number of returned mappings. If unspecified, the
+ plugin should return mappings for all groups satisfying the
+ criteria.
+
+ o Minimal keys in the returned mappings:
+
+ 'id' -- (required) the group ID
+
+ 'pluginid' -- (required) the plugin ID (as returned by getId())
+
+ 'properties_url' -- (optional) the URL to a page for updating the
+ group's properties.
+
+ 'members_url' -- (optional) the URL to a page for updating the
+ principals who belong to the group.
+
+ o Plugin *must* ignore unknown criteria.
+
+ o Plugin may raise ValueError for invalid critera.
+
+ o Insufficiently-specified criteria may have catastrophic
+ scaling issues for some implementations.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IGroupsPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.groups.GroupsPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import groups
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/groups.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/groups.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/groups/plugins/groups.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,23 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class GroupsPlugin(BasePlugin):
+ """ Determine the groups to which a user belongs.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('getGroupsForPrincipal')
+ def getGroupsForPrincipal(self, principal, request=None):
+ """ principal -> (group_1, ... group_N)
+
+ o Return a sequence of group names to which the principal
+ (either a user or another group) belongs.
+
+ o May assign groups based on values in the REQUEST object, if present
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IPropertiesPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.properties.PropertiesPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import properties
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/properties.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/properties.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/properties/plugins/properties.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,29 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class PropertiesPlugin(BasePlugin):
+ """ Return a property set for a user.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('getPropertiesForUser')
+ def getPropertiesForUser(self, user, request=None):
+ """ user -> {}
+
+ o User will implement IPropertiedUser.
+
+ o Plugin should return a dictionary or an object providing
+ IPropertiesPlugin.
+
+ o Plugin may scribble on the user, if needed (but must still
+ return a mapping, even if empty).
+
+ o May assign properties based on values in the REQUEST object, if
+ present
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IRoleAssignerPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.role_assigner.RoleAssignerPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import role_assigner
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/role_assigner.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/role_assigner.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_assigner/plugins/role_assigner.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,31 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class RoleAssignerPlugin(BasePlugin):
+ """ Assign a role to an identified principal
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('doAssignRoleToPrincipal')
+ def doAssignRoleToPrincipal(self, principal_id, role):
+ """ Create a principal/role association in a Role Manager
+
+ o Return a Boolean indicating whether the role was assigned or not
+ """
+
+ \#add your code here
+
+ pass
+
+ security.declarePrivate('doRemoveRoleFromPrincipal')
+ def doRemoveRoleFromPrincipal(self, principal_id, role):
+ """ Remove a principal/role association from a Role Manager
+
+ o Return a Boolean indicating whether the role was removed or not
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IRoleEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.role_enumeration.RoleEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import role_enumeration
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/role_enumeration.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/role_enumeration.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/role_enumeration/plugins/role_enumeration.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,61 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class RoleEnumerationPlugin( BasePlugin ):
+ """ Allow querying roles by ID, and searching for roles.
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('enumerateRoles')
+ def enumerateRoles(self,
+ id=None,
+ exact_match=False,
+ sort_by=None,
+ max_results=None,
+ **kw):
+ """ -> ( role_info_1, ... role_info_N )
+
+ o Return mappings for roles matching the given criteria.
+
+ o 'id' in combination with 'exact_match' true, will
+ return at most one mapping per supplied ID ('id' and 'login'
+ may be sequences).
+
+ o If 'exact_match' is False, then 'id' may be treated by
+ the plugin as "contains" searches (more complicated searches
+ may be supported by some plugins using other keyword arguments).
+
+ o If 'sort_by' is passed, the results will be sorted accordingly.
+ known valid values are 'id' (some plugins may support others).
+
+ o If 'max_results' is specified, it must be a positive integer,
+ limiting the number of returned mappings. If unspecified, the
+ plugin should return mappings for all roles satisfying the
+ criteria.
+
+ o Minimal keys in the returned mappings:
+
+ 'id' -- (required) the role ID
+
+ 'pluginid' -- (required) the plugin ID (as returned by getId())
+
+ 'properties_url' -- (optional) the URL to a page for updating the
+ role's properties.
+
+ 'members_url' -- (optional) the URL to a page for updating the
+ principals to whom the role is assigned.
+
+ o Plugin *must* ignore unknown criteria.
+
+ o Plugin may raise ValueError for invalid critera.
+
+ o Insufficiently-specified criteria may have catastrophic
+ scaling issues for some implementations.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IRolesPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.roles.RolesPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import roles
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/roles.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/roles.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/roles/plugins/roles.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class RolesPlugin(BasePlugin):
+ """Determine the (global) roles which a user has.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('getRoles ForPrincipal')
+ def getRolesForPrincipal(self, principal, request=None):
+ """principal -> (role_1, ... role_N)
+
+ o Return a sequence of role names which the principal has.
+
+ o May assign roles based on values in the REQUEST object, if present.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IUpdatePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.update.UpdatePlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import update
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/update.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/update.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/update/plugins/update.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class UpdatePlugin(BasePlugin):
+ """ Allow the user or the application to update the user's properties.
+ """
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('updateUserInfo')
+ def updateUserInfo(self, user, set_id, set_info):
+ """ Update backing store for 'set_id' using 'set_info'.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IUserAdderPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.user_adder.UserAdderPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import user_adder
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/user_adder.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/user_adder.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_adder/plugins/user_adder.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class UserAdderPlugin(BasePlugin):
+ """ Create a new user record in a User Manager
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('doAddUser')
+ def doAddUser(self, login, password):
+ """ Add a user record to a User Manager, with the given login
+ and password
+
+ o Return a Boolean indicating whether a user was added or not
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IUserEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.user_enumeration.UserEnumerationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import user_enumeration
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/user_enumeration.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/user_enumeration.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_enumeration/plugins/user_enumeration.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,65 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class UserEnumerationPlugin(BasePlugin):
+ """Allow querying users by ID, and searching for users.
+
+ o XXX: can these be done by a single plugin?
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('enumerateUsers')
+ def enumerateUsers(self,
+ id=None,
+ login=None,
+ exact_match=False,
+ sort_by=None,
+ max_results=None,
+ **kw):
+ """-> ( user_info_1, ... user_info_N )
+
+ o Return mappings for users matching the given criteria.
+
+ o 'id' or 'login', in combination with 'exact_match' true, will
+ return at most one mapping per supplied ID ('id' and 'login'
+ may be sequences).
+
+ o If 'exact_match' is False, then 'id' and / or login may be
+ treated by the plugin as "contains" searches (more complicated
+ searches may be supported by some plugins using other keyword
+ arguments).
+
+ o If 'sort_by' is passed, the results will be sorted accordingly.
+ known valid values are 'id' and 'login' (some plugins may support
+ others).
+
+ o If 'max_results' is specified, it must be a positive integer,
+ limiting the number of returned mappings. If unspecified, the
+ plugin should return mappings for all users satisfying the criteria.
+
+ o Minimal keys in the returned mappings:
+
+ 'id' -- (required) the user ID, which may be different than
+ the login name
+
+ 'login' -- (required) the login name
+
+ 'pluginid' -- (required) the plugin ID (as returned by getId())
+
+ 'editurl' -- (optional) the URL to a page for updating the
+ mapping's user
+
+ o Plugin *must* ignore unknown criteria.
+
+ o Plugin may raise ValueError for invalid criteria.
+
+ o Insufficiently-specified criteria may have catastrophic
+ scaling issues for some implementations.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IUserFactoryPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.user_factory.UserFactoryPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import user_factory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/user_factory.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/user_factory.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/user_factory/plugins/user_factory.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class UserFactoryPlugin(BasePlugin):
+ """Create a new IPropertiedUser.
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('createUser')
+ def createUser(self, user_id, name):
+ """ Return a user, if possible.
+
+ o Return None to allow another plugin, or the default, to fire.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/interface.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/interface.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/interface.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ interfaces.plugins.IValidationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugin.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugin.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugin.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+ plugins.validation.ValidationPlugin,
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/__init__.py_insert
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/__init__.py_insert (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/__init__.py_insert 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+import validation
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/validation.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/validation.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/localcommands/templates/plone_pas/validation/plugins/validation.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+
+
+class ValidationPlugin(BasePlugin):
+ """ Specify allowable values for user properties.
+
+ o E.g., constrain minimum password length, allowed characters, etc.
+
+ o Operate on entire property sets, not individual properties.
+ """
+
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('validateUserInfo')
+ def validateUserInfo(self, user, set_id, set_info):
+ """-> ( error_info_1, ... error_info_N )
+
+ o Returned values are dictionaries, containing at least keys:
+
+ 'id' -- the ID of the property, or None if the error is not
+ specific to one property.
+
+ 'error' -- the message string, suitable for display to the user.
+ """
+
+ \#add your code here
+
+ pass
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/nested_namespace.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/nested_namespace.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/nested_namespace.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,38 @@
+import copy
+
+from zopeskel.base import get_var
+from zopeskel.base import var, EXPERT, EASY
+from zopeskel.basic_namespace import BasicNamespace
+from zopeskel.vars import DottedVar
+
+VAR_NS2 = DottedVar(
+ 'namespace_package2',
+ title='Namespace 2 Package Name',
+ description='Name of inner namespace package',
+ default='plone',
+ modes=(EXPERT,),
+ page='Namespaces',
+ help="""
+This is the name of the inner namespace package (Python folder) for this
+project. For example, in 'plone.app.example', this would be
+'app' ('plone' will be the first namespace, and 'example' would be
+the package name).
+"""
+)
+
+class NestedNamespace(BasicNamespace):
+ _template_dir = 'templates/nested_namespace'
+ summary = "A basic Python project with a nested namespace (2 dots in name)"
+ ndots = 2
+ help = """
+This creates a Python project without any Zope or Plone features.
+"""
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(BasicNamespace.vars)
+ get_var(vars, 'namespace_package').default = 'plone'
+ vars.insert(2, VAR_NS2)
+ get_var(vars, 'package').default = 'example'
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,63 @@
+import copy
+import shutil
+import os
+
+from zopeskel.basic_zope import BasicZope
+from zopeskel.base import get_var
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import BooleanVar
+
+class Plone(BasicZope):
+ _template_dir = 'templates/plone'
+ summary = "A project for Plone products"
+ help = """
+This creates a Plone project (to create a Plone *site*, you probably
+want to use the one of the templates for a buildout).
+
+To create a Plone project with a name like 'plone.app.myproject'
+(2 dots, a 'nested namespace'), use the 'plone_app' template.
+"""
+ category = "Plone Development"
+ required_templates = ['basic_namespace']
+ use_local_commands = True
+ use_cheetah = True
+ vars = copy.deepcopy(BasicZope.vars)
+ vars.insert(5, BooleanVar(
+ 'add_profile',
+ title='Register Profile',
+ description='Should this package register a GS Profile',
+ modes=(EASY, EXPERT),
+ default=False,
+ help="""
+If your package has need of a Generic Setup profile, set this value to 'True'.
+
+Having a Generic Setup profile registered makes your package 'installable'
+using the ZMI portal_quickinstaller or Plone's 'Add/Remove Products' control
+panel. This allows any portions of your package that require Generic
+Setup--such as portlets, content types, actions and so on--to be
+properly installed.
+"""
+ ))
+ get_var(vars, 'namespace_package').default = 'plone'
+ get_var(vars, 'package').default = 'example'
+
+ def post(self, command, output_dir, vars):
+ if vars['add_profile'] == False:
+ # if we do not want a profile, remove it.
+ path = os.path.join(output_dir,
+ vars['namespace_package'],
+ vars['package'])
+ try:
+ shutil.rmtree(os.path.join(path, 'profiles'))
+ except OSError, e:
+ msg = """WARNING: Error in template rendering:
+
+%s
+
+Your package may have structural problems, please check before
+using it.
+"""
+ self.post_run_msg = msg % str(e)
+
+ super(Plone, self).post(command, output_dir, vars)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+import copy
+from zopeskel.plone3_buildout import Plone3Buildout
+from zopeskel.base import get_var
+
+class Plone25Buildout(Plone3Buildout):
+ _template_dir = 'templates/plone2.5_buildout'
+ summary = "A buildout for Plone 2.5 projects"
+ help = """
+This template creates a buildout for Plone 2.5, appropriate for
+development. If you also need ZEO or caching, you may wish to look
+at the plone_hosting template.
+"""
+ required_templates = ['plone3_buildout']
+
+ vars = copy.deepcopy(Plone3Buildout.vars)
+ get_var(vars, 'plone_version').default = "2.5.5"
+
+ # The Plone3Buildout has an appropriate "use-the-installer"
+ # message, but this wouldn't be right here, so let's
+ # override it.
+ pre_run_msg = ""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_theme.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_theme.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone25_theme.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,41 @@
+import copy
+import os
+
+from zopeskel.plone import Plone
+from zopeskel.plone2_theme import theme_vars
+from zopeskel.base import get_var, EXPERT
+from zopeskel.plone2_theme import cleanupStylsheets
+
+class Plone25Theme(Plone):
+ _template_dir = 'templates/plone2.5_theme'
+ summary = "A theme for Plone 2.5"
+ help = """
+This creates a project for a theme for Plone 2.5
+"""
+ category = "Plone Theme Development"
+ required_templates = ['plone']
+ use_cheetah = True
+
+ vars = copy.deepcopy(Plone.vars)
+ get_var(vars, 'namespace_package').default = 'Products'
+ get_var(vars, 'description').default = 'An installable theme for Plone 2.5'
+ get_var(vars, 'keywords').default = 'web zope plone theme'
+ #add_profile should always default to True for theme packages
+ get_var(vars, 'add_profile').default = True
+ #add_profile need not appear as a question for theme packages
+ get_var(vars, 'add_profile').modes = ()
+ vars = vars[:3] + theme_vars + vars[3:]
+
+ def pre(self, command, output_dir, vars):
+ if vars['skinname'] == '':
+ # A title is needed in profiles.zcml otherwise adding a
+ # Plone Site will throw an error when displaying the
+ # extension profiles.
+ vars['skinname'] = 'Custom Theme'
+ super(Plone25Theme, self).pre(command, output_dir, vars)
+
+ def post(self, command, output_dir, vars):
+ if str(vars['empty_styles']) == 'False':
+ np, p = vars['namespace_package'], vars['package']
+ cleanupStylsheets(os.path.join(output_dir, np, p, 'skins'))
+ super(Plone25Theme, self).post(command, output_dir, vars)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone2_theme.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone2_theme.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone2_theme.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,136 @@
+import os
+import copy
+
+from zopeskel.base import BaseTemplate
+from zopeskel.base import get_var
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.base import BasicPackage
+from zopeskel.vars import StringVar, BooleanVar
+
+TARGET_STYLESHEETS = (
+ 'base.css.dtml',
+ 'generated.css.dtml',
+ 'portlets.css.dtml',
+ 'public.css.dtml'
+ )
+
+def cleanupStylsheets(skinsdir, targets=TARGET_STYLESHEETS):
+ for dirpath, dirnames, filenames in os.walk(skinsdir):
+ for target in [t for t in targets if t in filenames]:
+ print "Removing %s from %s%s" %(target, dirpath, os.sep)
+ os.remove(os.path.join(dirpath, target))
+
+
+theme_vars = [
+ StringVar(
+ 'skinname',
+ title='Skin Name',
+ description='Name of the theme (human facing, added to portal_skins)',
+ modes=(EASY, EXPERT),
+ page='Main',
+ help="""
+This becomes the theme name (eg "My Theme").
+
+It appears as the skin name choice in portal_skins, and is generated into
+the GenericSetup profile.
+"""
+ ),
+
+ StringVar(
+ 'skinbase',
+ title='Skin Base',
+ description='Name of the theme from which this is copied',
+ modes=(EXPERT,),
+ page='Main',
+ default='Plone Default',
+ help="""
+Themes can descend from other themes--by choosing a base theme here,
+your new theme will use the same skinpath ordering as this theme, except
+your theme-specific folders will appear at the top (right below 'custom').
+
+Typically, this will be 'Plone Default', the standard Plone theme.
+Unless you are certain what you are doing, keep this choice.
+"""
+ ),
+
+ BooleanVar('empty_styles',
+ title='Empty Styles?',
+ description='Override default public stylesheets with empty ones?',
+ modes=(EASY, EXPERT),
+ page='Main',
+ default=False,
+ help="""
+If this is not selected, your new theme will have the same CSS as the
+theme you are descending from (your skin base, answered above).
+
+If this is selected, your theme will have empty CSS files for several
+common 'public' areas--thereby starting you off with a theme that has
+less of the skin base's look and feel.
+
+Typically, if you are descending from Plone Default, this effectively
+hides some of the 'plone look and feel' from your theme; you'd then
+have to write CSS to provide more of your own look and feel.
+
+You can always refine the choice made here--to hide more of the base
+theme, create additional empty CSS files in your new theme to override
+other standard CSS files. To gain back some of the lost base look,
+you can just delete these overriding CSS files from your theme
+and the originals will now shine through.
+"""
+ ),
+
+ BooleanVar('include_doc',
+ title='Include Documentation?',
+ description="Include in-line documentation in generated code?",
+ modes=(EASY, EXPERT),
+ page="Main",
+ default=True,
+ help="""
+If selected, this adds verbose, helpful comments to the generated files.
+It does not change the appearance or functionality of the theme.
+These comments can always later be deleted.
+
+It is recommend you leave this on.
+"""
+ ),
+ ]
+
+class Plone2Theme(BaseTemplate):
+
+ # This does not descend from AbstractZope, since it's not
+ # a egg package, but just a raw Zope Product (unlike other
+ # templates)
+
+ _template_dir = 'templates/plone2_theme'
+ summary = "A theme for Plone 2.1"
+ ndots = 0
+ help = """
+This creates a project for a theme for Plone 2.1.
+
+This is not an egg, but a classic Product, and therefore is usable in
+Plone 2.1. This product should also work, without changes, in Plone
+2.5, though you may prefer to use the 'plone25_theme' template for
+this, as this will build an eggified Plone 2 theme.
+
+This template expects a name that is just the name of a classic
+product--a legal Python identifer without any dots in the name.
+"""
+ category = "Plone Development"
+
+ use_cheetah = True
+
+ vars = copy.deepcopy(BasicPackage.vars)
+ get_var(vars, 'description').default = 'An installable theme for Plone'
+ get_var(vars, 'keywords').default = 'web zope plone theme'
+ vars = theme_vars + vars[:3] + vars[4:6]
+
+ def pre(self, command, output_dir, vars):
+ if vars['skinname'] == '':
+ # It is always good to have a name for the skin.
+ vars['skinname'] = 'Custom Skin'
+ super(Plone2Theme, self).pre(command, output_dir, vars)
+
+ def post(self, command, output_dir, vars):
+ if str(vars['empty_styles']) == 'False':
+ cleanupStylsheets(os.path.join(output_dir, 'skins'))
+ super(Plone2Theme, self).post(command, output_dir, vars)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,68 @@
+import copy
+
+from zopeskel import abstract_buildout
+
+class Plone3Buildout(abstract_buildout.AbstractBuildout):
+ _template_dir = 'templates/plone3_buildout'
+ summary = "A buildout for Plone 3 installation"
+ help = """
+This template creates a Plone 3 buildout (for most users, a preferred
+way to get an installation of Plone 3 is to use the appropriate installer,
+as these are all buildout-based since Plone 3.1)
+"""
+ pre_run_msg = """
+*** NOTE: You probably don't want to use this template!
+
+Since Plone 3.1, the preferred way to get a buildout-based setup for
+Plone is to use the standard installer for your operating system (the
+Windows installer, the Mac installer, or the Unified Installer for
+Linux/Unix/BSD). These give you a best-practice, widely-used
+setup with an isolated Python and a well-documented buildout.
+This template is here for older versions of Plone and for experts
+who explicitly want a raw, non-installer-based installation.
+
+(This message is particularly aimed at people following out-of-date
+books/documentation that suggest this is the right way to get
+a Plone-based buildout. This is no longer the case.)
+"""
+
+ post_run_msg = """
+Generation finished.
+
+You probably want to run python bootstrap.py and then edit
+buildout.cfg before running bin/buildout -v".
+
+See README.txt for details.
+"""
+
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_buildout.AbstractBuildout.vars)
+ vars.extend(
+ [ abstract_buildout.VAR_PLONEVER,
+ abstract_buildout.VAR_Z2_INSTALL,
+ abstract_buildout.VAR_PLONE_PRODUCTS,
+ abstract_buildout.VAR_ZOPE_USER,
+ abstract_buildout.VAR_ZOPE_PASSWD,
+ abstract_buildout.VAR_HTTP,
+ abstract_buildout.VAR_DEBUG_MODE,
+ abstract_buildout.VAR_VERBOSE_SEC,
+ ]
+ )
+
+ def pre(self, command, output_dir, vars):
+ vars['tarballs'] = vars['plone_version'].startswith("3.0") or \
+ vars['plone_version'].startswith("3.1")
+ vars['z29tarballs'] = vars['plone_version'].startswith("2.")
+ if vars['z29tarballs']:
+ vars['zope2_version'] = "2.9.12"
+ vars['eggifiedplone'] = not vars['z29tarballs'] and not vars['tarballs']
+ vars['eggifiedzope'] = vars['plone_version'].startswith("4.")
+ if vars['eggifiedzope']:
+ vars['zope2_install'] = True
+ vars['zope2_version'] = "2.12.3"
+ super(Plone3Buildout, self).pre(command, output_dir, vars)
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_portlet.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_portlet.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_portlet.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,59 @@
+import copy
+
+from zopeskel.plone_app import PloneApp
+from zopeskel.base import get_var
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import StringVar, DottedVar
+
+class Plone3Portlet(PloneApp):
+ _template_dir = 'templates/plone3_portlet'
+ summary = "A Plone 3 portlet"
+ help = """
+This creates a Plone project for a portlet.
+"""
+ required_templates = ['nested_namespace']
+ use_cheetah = True
+
+ vars = copy.deepcopy(PloneApp.vars)
+ get_var(vars, 'namespace_package').default = 'collective'
+ get_var(vars, 'namespace_package2').default = 'portlet'
+ vars.append(
+ StringVar(
+ 'portlet_name',
+ title='Portlet Name',
+ description='Name of portlet (human readable)',
+ modes=(EASY,EXPERT),
+ default='Example Portlet',
+ help="""
+This becomes the human-readable title of the portlet.
+It gets generated in the GenericSetup profile file for the portlet.
+It appears in the Plone UI when managing portlets.
+"""
+ )
+ )
+ vars.append(
+ DottedVar(
+ 'portlet_type_name',
+ title='Portlet Type Name',
+ description='Name of portlet type (actual name)',
+ modes=(EASY, EXPERT),
+ default='ExamplePortlet',
+ help="""
+This becomes the actual name of the portlet. It is not displayed
+in the Plone UI, but is the name it is registered under, and is
+used as the class name for the portlet, and is used in the
+generated GenericSetup profile.
+"""
+ )
+ )
+
+ def pre(self, command, output_dir, vars):
+ vars['zip_safe'] = False
+ vars['portlet_filename'] = vars['portlet_type_name'].lower()
+ vars['dotted_name'] = "%s.%s.%s" % (vars['namespace_package'],
+ vars['namespace_package2'],
+ vars['package'])
+
+ super(Plone3Portlet, self).pre(command, output_dir, vars)
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_theme.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_theme.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone3_theme.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+import copy
+import datetime
+
+from zopeskel.plone25_theme import Plone25Theme
+from zopeskel.base import get_var, EXPERT
+
+class Plone3Theme(Plone25Theme):
+ _template_dir = 'templates/plone3_theme'
+ summary = "A theme for Plone 3"
+ help = """
+This creates a project for a theme for Plone 3.
+"""
+ required_templates = ['plone']
+ use_cheetah = True
+
+ vars = copy.deepcopy(Plone25Theme.vars)
+ get_var(vars, 'namespace_package').default = 'plonetheme'
+ get_var(vars, 'description').default = 'An installable theme for Plone 3'
+ #add_profile should always default to True for theme packages
+ get_var(vars, 'add_profile').default = True
+ #add_profile need not appear as a question for theme packages
+ get_var(vars, 'add_profile').modes = ()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone4_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone4_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone4_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,58 @@
+import copy
+
+from zopeskel import abstract_buildout
+
+class Plone4Buildout(abstract_buildout.AbstractBuildout):
+ _template_dir = 'templates/plone4_buildout'
+ summary = "A buildout for Plone 4 developer installation"
+ help = """
+
+This template creates a Plone 4 buildout (for most users, a preferred
+way to get an installation of Plone is to use the appropriate installer,
+as these are all buildout-based since Plone 3.1)
+"""
+ pre_run_msg = """
+*** NOTE: You probably don't want to use this template!
+
+Since Plone 3.1, the preferred way to get a buildout-based setup for
+Plone is to use the standard installer for your operating system (the
+Windows installer, the Mac installer, or the Unified Installer for
+Linux/Unix/BSD). These give you a best-practice, widely-used
+setup with an isolated Python and a well-documented buildout.
+This template is here for older versions of Plone and for experts
+who explicitly want a raw, non-installer-based installation.
+
+(This message is particularly aimed at people following out-of-date
+books/documentation that suggest this is the right way to get
+a Plone-based buildout. This is no longer the case.)
+"""
+
+ post_run_msg = """
+Generation finished.
+
+You probably want to run python bootstrap.py and then edit
+buildout.cfg before running bin/buildout -v".
+
+See README.txt for details.
+"""
+
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_buildout.AbstractBuildout.vars)
+ vars.extend(
+ [ abstract_buildout.VAR_PLONEVER,
+ ]
+ )
+
+ # Set default Plone 4 version
+ vars[1].default = "4.0.1"
+
+ def pre(self, command, output_dir, vars):
+ vars['eggifiedzope'] = True
+ vars['zope2_install'] = True
+ vars['zope2_version'] = "2.12.3"
+ super(Plone4Buildout, self).pre(command, output_dir, vars)
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_app.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_app.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_app.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+import copy
+
+from zopeskel.base import get_var
+from zopeskel.base import var
+from zopeskel import abstract_zope
+
+class PloneApp(abstract_zope.AbstractNestedZope):
+ _template_dir = 'templates/plone_app'
+ summary = "A project for Plone products with a nested namespace (2 dots in name)"
+ help = """
+This creates a Plone project (to create a Plone *site*, you probably
+want to use the one of the templates for a buildout).
+
+To create a Plone project with a name like 'mycompany.myproject' (1 dot,
+a 'basic namespace'), use the 'plone' template instead.
+"""
+ required_templates = ['nested_namespace']
+ use_cheetah = True
+ category = "Plone Development"
+
+ vars = copy.deepcopy(abstract_zope.AbstractNestedZope.vars)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_pas.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_pas.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/plone_pas.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+import copy
+
+from zopeskel import abstract_zope
+from zopeskel.base import get_var
+
+class PlonePas(abstract_zope.AbstractNestedZope):
+ _template_dir = 'templates/plone_pas'
+ summary = "A project for a Plone PAS plugin"
+ help = """
+This create a project for developing a PAS ('pluggable authentication
+system') plugin.
+"""
+ category = "Plone Development"
+ required_templates = ['nested_namespace']
+ use_cheetah = True
+ use_local_commands = True
+
+ vars = copy.deepcopy(abstract_zope.AbstractNestedZope.vars)
+ get_var(vars, 'namespace_package2').default = 'pas'
+
+ def pre(self, command, output_dir, vars):
+ vars['multiplugin_name'] = vars['package'].title()
+ super(PlonePas, self).pre(command, output_dir, vars)
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/recipe.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/recipe.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/recipe.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,19 @@
+import copy
+
+from zopeskel.nested_namespace import NestedNamespace
+from zopeskel.base import get_var
+
+class Recipe(NestedNamespace):
+ """A template for buildout recipes"""
+ _template_dir = 'templates/recipe'
+ summary = "A recipe project for zc.buildout"
+ help = """
+This creates a skeleton for a buildout recipe.
+"""
+ category = "Buildout"
+ required_templates = []
+ use_cheetah = True
+ vars = copy.deepcopy(NestedNamespace.vars)
+ get_var(vars, 'namespace_package2').default = 'recipe'
+ get_var(vars, 'license_name').default = 'ZPL'
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/silva_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/silva_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/silva_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+import copy
+
+from zopeskel import abstract_buildout
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import StringVar, StringChoiceVar
+
+
+class SilvaBuildout(abstract_buildout.AbstractBuildout):
+ _template_dir = 'templates/silva_buildout'
+ summary = "A buildout for Silva projects"
+ help = """
+This template creates an installation of Silva
+(http://www.infrae.com/products/silva).
+"""
+ post_run_msg = """
+Generation finished.
+
+You probably want to run python bootstrap.py and then edit
+buildout.cfg before running bin/buildout -v".
+
+See README.txt for details.
+"""
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_buildout.AbstractBuildout.vars)
+ vars.extend([
+ abstract_buildout.VAR_Z2_INSTALL,
+ StringChoiceVar(
+ 'silva_distribution',
+ title='Silva Distribution',
+ description='Version of Silva to install, "stable" or "development"',
+ default="stable",
+ modes=(EASY, EXPERT),
+ page='Main',
+ choices=('stable','development'),
+ ),
+ abstract_buildout.VAR_ZOPE_USER,
+ abstract_buildout.VAR_ZOPE_PASSWD,
+ abstract_buildout.VAR_HTTP,
+ abstract_buildout.VAR_DEBUG_MODE,
+ abstract_buildout.VAR_VERBOSE_SEC,
+ ]
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,51 @@
+Introduction
+============
+
+This is a full-blown functional test. The emphasis here is on testing what
+the user may input and see, and the system is largely tested as a black box.
+We use PloneTestCase to set up this test as well, so we have a full Plone site
+to play with. We *can* inspect the state of the portal, e.g. using
+self.portal and self.folder, but it is often frowned upon since you are not
+treating the system as a black box. Also, if you, for example, log in or set
+roles using calls like self.setRoles(), these are not reflected in the test
+browser, which runs as a separate session.
+
+Being a doctest, we can tell a story here.
+
+First, we must perform some setup. We use the testbrowser that is shipped
+with Five, as this provides proper Zope 2 integration. Most of the
+documentation, though, is in the underlying zope.testbrower package.
+
+ >>> from Products.Five.testbrowser import Browser
+ >>> browser = Browser()
+ >>> portal_url = self.portal.absolute_url()
+
+The following is useful when writing and debugging testbrowser tests. It lets
+us see all error messages in the error_log.
+
+ >>> self.portal.error_log._ignored_exceptions = ()
+
+With that in place, we can go to the portal front page and log in. We will
+do this using the default user from PloneTestCase:
+
+ >>> from Products.PloneTestCase.setup import portal_owner, default_password
+
+Because add-on themes or products may remove or hide the login portlet, this test will use the login form that comes with plone.
+
+ >>> browser.open(portal_url + '/login_form')
+ >>> browser.getControl(name='__ac_name').value = portal_owner
+ >>> browser.getControl(name='__ac_password').value = default_password
+ >>> browser.getControl(name='submit').click()
+
+Here, we set the value of the fields on the login form and then simulate a
+submit click. We then ensure that we get the friendly logged-in message:
+
+ >>> "You are now logged in" in browser.contents
+ True
+
+Finally, let's return to the front page of our site before continuing
+
+ >>> browser.open(portal_url)
+
+-*- extra stuff goes here -*-
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,54 @@
+"""Main product initializer
+"""
+
+from zope.i18nmessageid import MessageFactory
+#if str($zope2product) == 'True'
+from ${namespace_package}.${package} import config
+
+from Products.Archetypes import atapi
+from Products.CMFCore import utils
+#end if
+
+\# Define a message factory for when this product is internationalised.
+\# This will be imported with the special name "_" in most modules. Strings
+\# like _(u"message") will then be extracted by i18n tools for translation.
+
+${package}MessageFactory = MessageFactory('${namespace_package}.${package}')
+#if str($zope2product) == 'True'
+
+
+def initialize(context):
+ """Initializer called when used as a Zope 2 product.
+
+ This is referenced from configure.zcml. Regstrations as a "Zope 2 product"
+ is necessary for GenericSetup profiles to work, for example.
+
+ Here, we call the Archetypes machinery to register our content types
+ with Zope and the CMF.
+ """
+
+ # Retrieve the content types that have been registered with Archetypes
+ # This happens when the content type is imported and the registerType()
+ # call in the content type's module is invoked. Actually, this happens
+ # during ZCML processing, but we do it here again to be explicit. Of
+ # course, even if we import the module several times, it is only run
+ # once.
+
+ content_types, constructors, ftis = atapi.process_types(
+ atapi.listTypes(config.PROJECTNAME),
+ config.PROJECTNAME)
+
+ # Now initialize all these content types. The initialization process takes
+ # care of registering low-level Zope 2 factories, including the relevant
+ # add-permission. These are listed in config.py. We use different
+ # permissions for each content type to allow maximum flexibility of who
+ # can add which content types, where. The roles are set up in rolemap.xml
+ # in the GenericSetup profile.
+
+ for atype, constructor in zip(content_types, constructors):
+ utils.ContentInit('%s: %s' % (config.PROJECTNAME, atype.portal_type),
+ content_types=(atype, ),
+ permission=config.ADD_PERMISSIONS[atype.portal_type],
+ extra_constructors=(constructor,),
+ ).initialize(context)
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/browser/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="${namespace_package}.${package}">
+
+ <include package="plone.app.contentmenu" />
+
+ <!-- -*- extra stuff goes here -*- -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/config.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/config.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/config.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+"""Common configuration constants
+"""
+
+PROJECTNAME = '${namespace_package}.${package}'
+
+ADD_PERMISSIONS = {
+ # -*- extra stuff goes here -*-
+}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+#if str($add_profile) == 'True'
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+#end if
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($zope2product) == 'True'
+ <five:registerPackage package="." initialize=".initialize" />
+#end if
+
+ <!-- Include the sub-packages that use their own configure.zcml files. -->
+ <include package=".browser" />
+ <include package=".content" />
+ <include package=".portlets" />
+
+#if str($add_profile) == 'True'
+ <!-- Register the installation GenericSetup extension profile -->
+ <genericsetup:registerProfile
+ name="default"
+ title="${title}"
+ directory="profiles/default"
+ description="${description}"
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+#end if
+
+ <!-- -*- extra stuff goes here -*- -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/content/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ i18n_domain="${namespace_package}.${package}">
+
+ <!-- configure your content components here -->
+
+ <!-- -*- extra stuff goes here -*- -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/interfaces/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+# -*- extra stuff goes here -*-
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/portlets/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,12 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:plone="http://namespaces.plone.org/plone"
+ i18n_domain="${namespace_package}.${package}">
+
+ <!-- Ensure Plone's portlets ZCML has already been processed;
+ without this, we may get a permission lookup error -->
+ <include package="plone.app.portlets" />
+
+ <!-- -*- extra stuff goes here -*- -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/factorytool.xml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/factorytool.xml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/factorytool.xml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- This import step informs the portal_factory tool that we want it to
+ manage our content types. This tool deals with the fact that in
+ Archetypes and most CMF types, the object is actually created before
+ the first edit form is filled in. That is, there are no true "add forms".
+ The factory tool creates a temporary object in lieu of an "add form",
+ and then moves the object to the proper location after it has been
+ successfully saved.
+ -->
+<object name="portal_factory" meta_type="Plone Factory Tool">
+ <factorytypes>
+ <!-- -*- extra stuff goes here -*- -->
+ </factorytypes>
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<metadata>
+ <version>1000</version>
+</metadata>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/portlets.xml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/portlets.xml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/portlets.xml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- This file is used to register new types of portlets. It can also
+ be used to register completely new column types. See CMFPlone's version
+ of this file for more information.
+ -->
+<portlets
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <!-- -*- extra stuff goes here -*- -->
+</portlets>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/types.xml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/types.xml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/profiles/default/types.xml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- This file registers new types with portal_types. The types are
+ then configured with the corresponding files in types/*.xml. Note
+ that spaces are allowed in type names, but the corresponding XML file
+ uses an underscore instead. The "Factory-based Type Information with
+ dynamic views" refers to an FTI from Products.CMFDynamicViewFTI,
+ which supports Plone's "display" menu.
+ -->
+<object name="portal_types" meta_type="Plone Types Tool">
+ <!-- -*- extra stuff goes here -*- -->
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/base.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/base.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/base.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,87 @@
+"""Test setup for integration and functional tests.
+
+When we import PloneTestCase and then call setupPloneSite(), all of
+Plone's products are loaded, and a Plone site will be created. This
+happens at module level, which makes it faster to run each test, but
+slows down test runner startup.
+"""
+
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+
+from Testing import ZopeTestCase as ztc
+
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import onsetup
+
+# When ZopeTestCase configures Zope, it will *not* auto-load products
+# in Products/. Instead, we have to use a statement such as:
+#
+# ztc.installProduct('SimpleAttachment')
+#
+# This does *not* apply to products in eggs and Python packages (i.e.
+# not in the Products.*) namespace. For that, see below.
+#
+# All of Plone's products are already set up by PloneTestCase.
+
+
+ at onsetup
+def setup_product():
+ """Set up the package and its dependencies.
+
+ The @onsetup decorator causes the execution of this body to be
+ deferred until the setup of the Plone site testing layer. We could
+ have created our own layer, but this is the easiest way for Plone
+ integration tests.
+ """
+
+ # Load the ZCML configuration for the example.tests package.
+ # This can of course use <include /> to include other packages.
+
+ fiveconfigure.debug_mode = True
+ import ${namespace_package}.${package}
+ zcml.load_config('configure.zcml', ${namespace_package}.${package})
+ fiveconfigure.debug_mode = False
+
+ # We need to tell the testing framework that these products
+ # should be available. This can't happen until after we have loaded
+ # the ZCML. Thus, we do it here. Note the use of installPackage()
+ # instead of installProduct().
+ #
+ # This is *only* necessary for packages outside the Products.*
+ # namespace which are also declared as Zope 2 products, using
+ # <five:registerPackage /> in ZCML.
+
+ # We may also need to load dependencies, e.g.:
+ #
+ # ztc.installPackage('borg.localrole')
+ #
+
+ ztc.installPackage('${namespace_package}.${package}')
+
+# The order here is important: We first call the (deferred) function
+# which installs the products we need for this product. Then, we let
+# PloneTestCase set up this product on installation.
+
+setup_product()
+ptc.setupPloneSite(products=['${namespace_package}.${package}'])
+
+
+class TestCase(ptc.PloneTestCase):
+ """We use this base class for all the tests in this package. If
+ necessary, we can put common utility or setup code in here. This
+ applies to unit test cases.
+ """
+
+
+class FunctionalTestCase(ptc.FunctionalTestCase):
+ """We use this class for functional integration tests that use
+ doctest syntax. Again, we can put basic common utility or setup
+ code in here.
+ """
+
+ def afterSetUp(self):
+ roles = ('Member', 'Contributor')
+ self.portal.portal_membership.addMember('contributor',
+ 'secret',
+ roles, [])
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/test_doctest.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/test_doctest.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/+namespace_package+/+package+/tests/test_doctest.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,25 @@
+import unittest
+import doctest
+
+\#from zope.testing import doctestunit
+\#from zope.component import testing, eventtesting
+
+from Testing import ZopeTestCase as ztc
+
+from ${namespace_package}.${package}.tests import base
+
+
+def test_suite():
+ return unittest.TestSuite([
+
+ # Demonstrate the main content types
+ ztc.ZopeDocFileSuite(
+ 'README.txt', package='${namespace_package}.${package}',
+ test_class=base.FunctionalTestCase,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE |
+ doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS),
+
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CHANGES.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CHANGES.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CHANGES.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+Changelog
+=========
+
+#set $header_text = "%s (xxxx-xx-xx)" % $version or "0.0.0"
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+- Created recipe with ZopeSkel
+ [${$author or $empty}]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CONTRIBUTORS.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CONTRIBUTORS.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/CONTRIBUTORS.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+${$author or $empty}, Author
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/MANIFEST.in_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/MANIFEST.in_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/MANIFEST.in_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+recursive-include ${namespace_package} *
+global-exclude *pyc
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+.. contents::
+
+.. Note!
+ -----
+ Update the following URLs to point to your:
+
+ - code repository
+ - bug tracker
+ - questions/comments feedback mail
+ (do not set a real mail, to avoid spams)
+
+ Or remove it if not used.
+
+- Code repository: http://svn.somewhere.com/...
+- Questions and comments to somemailing_list
+- Report bugs at http://bug.somewhere.com/..
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/archetype/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"""
+This module contains the tool of $project
+"""
+import os
+from setuptools import setup, find_packages
+
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+version = ${repr($version) or "0.0.0"}
+
+long_description = (
+ read('README.txt')
+ + '\n' +
+ 'Change history\n'
+ '**************\n'
+ + '\n' +
+ read('CHANGES.txt')
+ + '\n' +
+ 'Detailed Documentation\n'
+ '**********************\n'
+ + '\n' +
+ read(${repr($namespace_package)}, ${repr($package)}, 'README.txt')
+ + '\n' +
+ 'Contributors\n'
+ '************\n'
+ + '\n' +
+ read('CONTRIBUTORS.txt')
+ + '\n' +
+ 'Download\n'
+ '********\n')
+
+tests_require = ['zope.testing']
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=long_description,
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ 'Framework :: Plone',
+ 'Intended Audience :: Developers',
+ #from zopeskel.base import LICENSE_CATEGORIES
+ #if $license_name.strip() in $LICENSE_CATEGORIES
+ $repr($LICENSE_CATEGORIES[$license_name.strip()]),
+ #end if
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', ],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=['setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ tests_require=tests_require,
+ extras_require=dict(tests=tests_require),
+ test_suite='$namespace_package.${package}.tests.test_docs.test_suite',
+ entry_points="""
+ # -*- entry_points -*-#
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ setup_requires=["PasteScript"],
+ paster_plugins=["ZopeSkel"],
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/+namespace_package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+Introduction
+============
+
+${long_description or None}
+
+This product may contain traces of nuts.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/docs/HISTORY.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/docs/HISTORY.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/docs/HISTORY.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+Changelog
+=========
+
+#set $header_text = "%sdev (unreleased)" % $version
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+- Initial release
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_namespace/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=[${repr($namespace_package)}],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+${project} Package Readme
+=========================
+
+Overview
+--------
+
+$description
+
+
+Your tests here
+---------------
+
+ >>> 1 + 1
+ 3
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five">
+
+#if str($zope2product) == 'True'
+ <five:registerPackage package="." initialize=".zope2.initialize" />
+#end if
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/tests.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/tests.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/tests.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+import unittest
+
+from zope.testing import doctestunit
+from zope.component import testing
+from Testing import ZopeTestCase as ztc
+
+def test_suite():
+ return unittest.TestSuite([
+
+ # Unit tests for your API
+ doctestunit.DocFileSuite(
+ 'README.txt', package='${namespace_package}.${package}',
+ setUp=testing.setUp, tearDown=testing.tearDown),
+
+ #doctestunit.DocTestSuite(
+ # module='${namespace_package}.${package}.mymodule',
+ # setUp=testing.setUp, tearDown=testing.tearDown),
+
+ # Integration tests that use ZopeTestCase
+ #ztc.ZopeDocFileSuite(
+ # 'README.txt', package='${namespace_package}.${package}',
+ # setUp=testing.setUp, tearDown=testing.tearDown),
+
+ #ztc.FunctionalDocFileSuite(
+ # 'browser.txt', package='${namespace_package}.${package}'),
+
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/zope2.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/zope2.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/+package+/zope2.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+#
+
+#if str($zope2product) == 'True'
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+namespace_package+/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+project+-configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+project+-configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/basic_zope/+project+-configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+<include package="${package}" />
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/+namespace_package+.+namespace_package2+.+package+-configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/+namespace_package+.+namespace_package2+.+package+-configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/+namespace_package+.+namespace_package2+.+package+-configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+<include package="${namespace_package}.${namespace_package2}.${package}" />
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:kss="http://namespaces.zope.org/kss"
+ xmlns:zcml="http://namespaces.zope.org/zcml">
+
+ <!-- Including this configuration will activate this plugin inside zope. -->
+
+ <!-- Include demo setup conditionally -->
+ <include zcml:condition="installed kss.demo" package=".demo" />
+
+ <!-- Third party library dependencies -->
+
+ <!--
+ <browser:resource
+ file="3rd_party/myfile.js"
+ name="myfile.js"
+ />
+ -->
+
+ <!-- Event types -->
+
+ <!--
+ <kss:eventtype
+ name="${package}-myevent"
+ jsfile="javascript/myfile.js"
+ />
+ -->
+
+ <!-- Client actions & commands -->
+
+ <!--
+ <kss:action
+ name="${package}-myaction"
+ jsfile="javascript/myfile.js"
+ command_factory="selector"
+ params_mandatory=""
+ params_optional=""
+ />
+ -->
+
+ <!-- Command sets -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.kss
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.kss (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.kss 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+# fill in your kss rules in here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.pt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.pt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/+package+.pt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+<html tal:define="viewname string:${package}">
+ <head>
+ <!-- add your third party resources here -->
+
+ <!-- link rel="stylesheet" type="text/css"
+ tal:attributes="href string:\${context/@@absolute_url}/++resource++${package}.css"/-->
+
+ <metal:header use-macro="context/@@header_macros/header_resources" />
+
+ </head>
+ <body>
+ <p metal:use-macro="context/@@body_macros/header">header</p>
+ <!-- START of demo content -->
+
+ <h2>Demo of ${package}:</h2>
+ <div id="description">${description}</div>
+ </body>
+</html>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:kss="http://namespaces.zope.org/kss"
+ i18n_domain="kss"
+ >
+
+ <!-- Set up the demo utility, needed for registration -->
+ <!-- utility
+ name="${package}"
+ factory=".zopeconfig.KSSDemos"
+ provides="kss.demo.interfaces.IKSSDemoResource"
+ permission="zope.Public"
+ /-->
+
+ <!-- Set up resources needed for the demo -->
+ <!-- browser:page
+ for="kss.demo.interfaces.ISimpleContent"
+ template="${package}.pt"
+ name="${package}.html"
+ permission="zope2.View"
+ /-->
+
+ <browser:resource
+ file="${package}.kss"
+ name="${package}.kss"
+ />
+
+ <!-- browser:resource
+ file="${package}.css"
+ name="${package}.css"
+ /-->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/zopeconfig.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/zopeconfig.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/demo/zopeconfig.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,33 @@
+from kss.demo.interfaces import (
+ IKSSDemoResource,
+ IKSSSeleniumTestResource,
+ )
+from kss.demo.resource import (
+ KSSDemo,
+ KSSSeleniumTestDirectory,
+ )
+from zope.interface import implements
+
+# Create a mesh of provided interfaces
+# This is needed, because an utility must have a single interface.
+class IResource(IKSSDemoResource, IKSSSeleniumTestResource):
+ pass
+
+# XXX you do not need to change anything above here
+# -------------------------------------------------
+
+class KSSDemos(object):
+ implements(IResource)
+
+ demos = (
+ # List your demos here.
+ # (Second parameter can be a subcategory within the demo if needed.)
+ #KSSDemo('${package}', '', '${package}.html', 'Demo Title (to edit!)'),
+ )
+
+ # directories are relative from the location of this .py file
+ selenium_tests = (
+ # if you only have one test directory, you
+ # need not change anything here.
+ #KSSSeleniumTestDirectory('selenium_tests'),
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/+package+.js_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/+package+.js_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/+package+/javascript/+package+.js_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2007
+ * Authors: KSS Project Contributors (see docs/CREDITS.txt)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+kukit.${package} = {};
+
+
+/* kukit.eventsGlobalRegistry.registerForAllEvents(
+ '${package}', ['dragstart', 'dragsuccess', 'dragfailure'],
+ EventBinder, '__bind_drag__', null, 'Node');
+ kukit.eventsGlobalRegistry.registerForAllEvents(
+ '${package}', ['drop'],
+ EventBinder, '__bind_drop__', null, 'Node');
+*/
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/+namespace_package2+/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/+namespace_package+/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/kss_plugin/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,39 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Framework :: Plone",
+ "Framework :: Zope2",
+ "Framework :: Zope3",
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=[
+ 'setuptools',
+ 'kss.core'
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/+namespace_package2+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/+namespace_package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+Introduction
+============
+
+${long_description or None}
+
+This product may contain traces of nuts.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/docs/HISTORY.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/docs/HISTORY.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/docs/HISTORY.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+Changelog
+=========
+
+#set $header_text = "%sdev (unreleased)" % $version
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+- Initial release
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/nested_namespace/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+ # -*- extra stuff goes here -*-
+
+#if str($zope2product) == 'True'
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+#end if
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,25 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+#if str($add_profile) == 'True'
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+#end if
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($zope2product) == 'True' and $namespace_package != 'Products'
+ <five:registerPackage package="." initialize=".initialize" />
+#end if
+
+#if str($add_profile) == 'True'
+ <genericsetup:registerProfile
+ name="default"
+ title="${namespace_package}.${package}"
+ directory="profiles/default"
+ description="Installs the ${namespace_package}.${package} package"
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+#end if
+ <!-- -*- extra stuff goes here -*- -->
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<metadata>
+ <version>1000</version>
+</metadata>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/+namespace_package+/+package+/tests.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,63 @@
+import unittest
+
+\#from zope.testing import doctestunit
+\#from zope.component import testing
+from Testing import ZopeTestCase as ztc
+
+#if str($zope2product) != 'True'
+from Products.Five import zcml
+#end if
+from Products.Five import fiveconfigure
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import PloneSite
+ptc.setupPloneSite()
+
+import ${namespace_package}.${package}
+
+
+class TestCase(ptc.PloneTestCase):
+
+ class layer(PloneSite):
+
+ @classmethod
+ def setUp(cls):
+ fiveconfigure.debug_mode = True
+ #if str($zope2product) == 'True'
+ ztc.installPackage(${namespace_package}.${package})
+ #else
+ zcml.load_config('configure.zcml',
+ ${namespace_package}.${package})
+ #end if
+ fiveconfigure.debug_mode = False
+
+ @classmethod
+ def tearDown(cls):
+ pass
+
+
+def test_suite():
+ return unittest.TestSuite([
+
+ \# Unit tests
+ \#doctestunit.DocFileSuite(
+ \# 'README.txt', package='${namespace_package}.${package}',
+ \# setUp=testing.setUp, tearDown=testing.tearDown),
+
+ \#doctestunit.DocTestSuite(
+ \# module='${namespace_package}.${package}.mymodule',
+ \# setUp=testing.setUp, tearDown=testing.tearDown),
+
+
+ \# Integration tests that use PloneTestCase
+ \#ztc.ZopeDocFileSuite(
+ \# 'README.txt', package='${namespace_package}.${package}',
+ \# test_class=TestCase),
+
+ \#ztc.FunctionalDocFileSuite(
+ \# 'browser.txt', package='${namespace_package}.${package}',
+ \# test_class=TestCase),
+
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/INSTALL.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/INSTALL.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/INSTALL.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,72 @@
+#set $full_package_name = "%s.%s" % ($namespace_package, $package)
+#set $header_text = "%s Installation" % $project
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+To install ${project} into the global Python environment (or a workingenv),
+using a traditional Zope 2 instance, you can do this:
+
+* When you're reading this you have probably already run
+ ``easy_install ${project}``. Find out how to install setuptools
+ (and EasyInstall) here:
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+#if str($zope2product) == 'True'
+* If you are using Zope 2.9 (not 2.10), get `pythonproducts`_ and install it
+ via::
+
+ python setup.py install --home /path/to/instance
+
+into your Zope instance.
+
+#end if
+* Create a file called ``${project}-configure.zcml`` in the
+ ``/path/to/instance/etc/package-includes`` directory. The file
+ should only contain this::
+
+ <include package="${full_package_name}" />
+
+#if str($zope2product) == 'True'
+.. _pythonproducts: http://plone.org/products/pythonproducts
+
+#end if
+
+Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance
+recipe to manage your project, you can do this:
+
+* Add ``${project}`` to the list of eggs to install, e.g.:
+
+ [buildout]
+ ...
+ eggs =
+ ...
+ ${project}
+
+* Tell the plone.recipe.zope2instance recipe to install a ZCML slug:
+
+ [instance]
+ recipe = plone.recipe.zope2instance
+ ...
+ zcml =
+ ${full_package_name}
+
+* Re-run buildout, e.g. with:
+
+ $ ./bin/buildout
+
+You can skip the ZCML slug if you are going to explicitly include the package
+from another package's configure.zcml file.
+#if str($zope2product) == 'True' and $namespace_package == 'Products'
+
+
+Because its top level Python namespace package is called ``Products``, this
+package can also be installed in Zope 2 as an old style **Zope 2 Product**.
+
+For that, move (or symlink) the ``$package`` folder of this project
+(``$project/$namespace_package/$package``) into the ``Products`` directory of
+the Zope instance it has to be installed for, and restart the server.
+
+You can also skip the ZCML slug if you install this package the **Zope 2
+Product** way.
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.GPL
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.GPL (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.GPL 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/docs/LICENSE.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+ ${project} is copyright $author
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,38 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Framework :: Plone",
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=[${repr($namespace_package)}],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ setup_requires=["PasteScript"],
+ paster_plugins=["ZopeSkel"],
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_buildout/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_buildout/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_buildout/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,327 @@
+=======================
+Using a custom buildout
+=======================
+
+Note: If you are using Windows, if you do not have PIL installed, or you are
+not using Python 2.4 as your main system Python, please see the relevant
+sections below.
+
+You probably got here by running something like:
+
+ $ paster create -t plone3_buildout
+
+Now, you need to run:
+
+ $ python bootstrap.py
+
+This will install zc.buildout for you.
+
+To create an instance immediately, run:
+
+ $ bin/buildout
+
+This will download Plone's products for you, as well as other dependencies,
+create a new Zope 2 installation (unless you specified an existing one when
+you ran "paster create"), and create a new Zope instance configured with these
+products.
+
+You can start your Zope instance by running:
+
+ $ bin/instance start
+
+or, to run in foreground mode:
+
+ $ bin/instance fg
+
+To run unit tests, you can use:
+
+ $ bin/instance test -s my.package
+
+Installing PIL
+--------------
+
+To use Plone, you need PIL, the Python Imaging Library. If you don't already
+have this, download and install it from http://www.pythonware.com/products/pil.
+
+Using a different Python installation
+--------------------------------------
+
+Buildout will use your system Python installation by default. However, Zope
+2.10 (and by extension, Plone) will only work with Python 2.4. You can verify
+which version of Python you have, by running:
+
+ $ python -V
+
+If that is not a 2.4 version, you need to install Python 2.4 from
+http://python.org. If you wish to keep another version as your main system
+Python, edit buildout.cfg and add an 'executable' option to the "[buildout]"
+section, pointing to a python interpreter binary:
+
+ [buildout]
+ ...
+ executable = /path/to/python
+
+Working with buildout.cfg
+-------------------------
+
+You can change any option in buildout.cfg and re-run bin/buildout to reflect
+the changes. This may delete things inside the 'parts' directory, but should
+keep your Data.fs and source files intact.
+
+To save time, you can run buildout in "offline" (-o) and non-updating (-N)
+mode, which will prevent it from downloading things and checking for new
+versions online:
+
+ $ bin/buildout -Nov
+
+Creating new eggs
+-----------------
+
+New packages you are working on (but which are not yet released as eggs and
+uploaded to the Python Package Index, aka PYPI) should be placed in src. You can do:
+
+ $ cd src/
+ $ paster create -t plone my.package
+
+Use "paster create --list-templates" to see all available templates. Answer
+the questions and you will get a new egg. Then tell buildout about your egg
+by editing buildout.cfg and adding your source directory to 'develop':
+
+ [buildout]
+ ...
+ develop =
+ src/my.package
+
+You can list multiple packages here, separated by whitespace or indented
+newlines.
+
+You probably also want the Zope instance to know about the package. Add its
+package name to the list of eggs in the "[instance]" section, or under the
+main "[buildout]" section:
+
+ [instance]
+ ...
+ eggs =
+ ${buildout:eggs}
+ ${plone:eggs}
+ my.package
+
+Leave the ${buildout:eggs} part in place - it tells the instance to use the
+eggs that buildout will have downloaded from the Python Package Index
+previously.
+
+If you also require a ZCML slug for your package, buildout can create one
+automatically. Just add the package to the 'zcml' option:
+
+ [instance]
+ ...
+ zcml =
+ my.package
+
+When you are finished, re-run buildout. Offline, non-updating mode should
+suffice:
+
+ $ bin/buildout -Nov
+
+Developing old-style products
+-----------------------------
+
+If you are developing old-style Zope 2 products (not eggs) then you can do so
+by placing the product code in the top-level 'products' directory. This is
+analogous to the 'Products/' directory inside a normal Zope 2 instance and is
+scanned on start-up for new products.
+
+Depending on a new egg
+----------------------
+
+If you want to use a new egg that is in the Python Package Index, all you need
+to do is to add it to the "eggs" option under the main "[buildout]" section:
+
+ [buildout]
+ ...
+ eggs =
+ my.package
+
+If it's listed somewhere else than the Python Package Index, you can add a link
+telling buildout where to find it in the 'find-links' option:
+
+ [buildout]
+ ...
+ find-links =
+ http://dist.plone.org
+ http://download.zope.org/distribution/
+ http://effbot.org/downloads
+ http://some.host.com/packages
+
+Using existing old-style products
+---------------------------------
+
+If you are using an old-style (non-egg) product, you can either add it as an
+automatically downloaded archive or put it in the top-level "products" folder.
+The former is probably better, because it means you can redistribute your
+buildout.cfg more easily:
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+
+If someproduct-1.3.tar.gz extracts into several products inside a top-level
+directory, e.g. SomeProduct-1.3/PartOne and SomeProduct-1.3/PartTwo, then
+add it as a "nested package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ nested-packages =
+ someproduct-1.3.tar.gz
+
+Alternatively, if it extracts to a directory which contains the version
+number, add it as a "version suffix package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ version-suffix-packages =
+ someproduct-1.3.tar.gz
+
+You can also track products by adding a new bundle checkout part. It
+doesn't strictly have to be an svn bundle at all, any svn location will do,
+and cvs is also supported:
+
+ [buildout]
+ ...
+ parts =
+ plone
+ zope2
+ productdistros
+ myproduct
+ instance
+ zopepy
+
+Note that "myproduct" comes before the "instance" part. You then
+need to add a new section to buildout.cfg:
+
+ [myproduct]
+ recipe = plone.recipe.bundlecheckout
+ url = http://svn.plone.org/svn/collective/myproduct/trunk
+
+Finally, you need to tell Zope to find this new checkout and add it to its
+list of directories that are scanned for products:
+
+ [instance]
+ ...
+ products =
+ ${buildout:directory}/products
+ ${productdistros:location}
+ ${plonebundle:location}
+ ${myproduct:location}
+
+Without this last step, the "myproduct" part is simply managing an svn
+checkout and could potentially be used for something else instead.
+
+=============
+Using Windows
+=============
+
+To use buildout on Windows, you will need to install a few dependencies which
+other platforms manage on their own.
+
+Here are the steps you need to follow (thanks to Hanno Schlichting for these):
+
+Python (http://python.org)
+--------------------------
+
+ - Download and install Python 2.4.4 using the Windows installer from
+ http://www.python.org/ftp/python/2.4.4/python-2.4.4.msi
+ Select 'Install for all users' and it will put Python into the
+ "C:\Python24" folder by default.
+
+ - You also want the pywin32 extensions available from
+ http://downloads.sourceforge.net/pywin32/pywin32-210.win32-py2.4.exe?modtime=1159009237&big_mirror=0
+
+ - And as a last step you want to download the Python imaging library available
+ from http://effbot.org/downloads/PIL-1.1.6.win32-py2.4.exe
+
+ - If you develop Zope based applications you will usually only need Python 2.4
+ at the moment, so it's easiest to put the Python binary on the systems PATH,
+ so you don't need to specify its location manually each time you call it.
+
+ Thus, put "C:\Python24" and "C:\Python24\Scripts" onto the PATH. You can
+ find the PATH definition in the control panel under system preferences on
+ the advanced tab at the bottom. The button is called environment variables.
+ You want to add it at the end of the already existing PATH in the system
+ section. Paths are separated by a semicolons.
+
+ - You can test if this was successful by opening a new shell (cmd) and type
+ in 'python -V'. It should report version 2.4.4 (or whichever version you
+ installed).
+
+ Opening a new shell can be done quickly by using the key combination
+ 'Windows-r' or if you are using Parallels on a Mac 'Apple-r'. Type in 'cmd'
+ into the popup box that opens up and hit enter.
+
+
+Subversion (http://subversion.tigris.org)
+-----------------------------------------
+
+ - Download the nice installer from
+ http://subversion.tigris.org/files/documents/15/35379/svn-1.4.2-setup.exe
+
+ - Run the installer. It defaults to installing into
+ "C:\Program Files\Subversion".
+
+ - Now put the install locations bin subfolder (for example
+ "C:\Program Files\Subversion\bin") on your system PATH in the same way you
+ put Python on it.
+
+ - Open a new shell again and type in: 'svn --version' it should report
+ version 1.4.2 or newer.
+
+
+MinGW (http://www.mingw.org/)
+-----------------------------
+
+ This is a native port of the gcc compiler and its dependencies for Windows.
+ There are other approaches enabling you to compile Python C extensions on
+ Windows including Cygwin and using the official Microsoft C compiler, but this
+ is a lightweight approach that uses only freely available tools. As
+ it's used by a lot of people chances are high it will work for you and there's
+ plenty of documentation out there to help you in troubleshooting problems.
+
+ - Download the MinGW installer from
+ http://downloads.sourceforge.net/mingw/MinGW-5.1.3.exe?modtime=1168794334&big_mirror=1
+
+ - The installer will ask you which options you would like to install. Choose
+ base and make here. It will install into "C:\MinGW" by default. The install
+ might take some time as it's getting files from sourceforge.net and you
+ might need to hit 'retry' a couple of times.
+
+ - Now put the install location's bin subfolder (for example "C:\MinGW\bin") on
+ your system PATH in the same way you put Python on it.
+
+ - Test this again by typing in: 'gcc --version' on a newly opened shell and
+ it should report version 3.4.2 or newer.
+
+
+Configure Distutils to use MinGW
+--------------------------------
+
+ Some general information are available from
+ http://www.mingw.org/MinGWiki/index.php/Python%20extensions for example but
+ you don't need to read them all.
+
+ - Create a file called 'distutils.cfg' in "C:\Python24\Lib\distutils". Open it
+ with a text editor ('notepad distutils.cfg') and fill in the following lines:
+
+ [build]
+ compiler=mingw32
+
+ This will tell distutils to use MinGW as the default compiler, so you don't
+ need to specify it manually using "--compiler=mingw32" while calling a
+ package's setup.py with a command that involves building C extensions. This
+ is extremely useful if the build command is written down in a buildout
+ recipe where you cannot change the options without hacking the recipe
+ itself. The z2c.recipe.zope2install used in ploneout is one such example.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/Install.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/Install.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/Install.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+from Products.CMFCore.utils import getToolByName
+
+def install(portal):
+ setup_tool = getToolByName(portal, 'portal_setup')
+ originalContext = setup_tool.getImportContextID()
+ setup_tool.setImportContext('profile-${namespace_package}.${package}:default')
+ setup_tool.runAllImportSteps()
+ setup_tool.setImportContext(originalContext)
+ return "Ran all import steps."
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/Extensions/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+# this file is here to make importable the modules stored in the product
+# 'Extensions' folder.
+# keep these lines to make it non-zero size and have winzip cooperate.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+\# Register our skins directory - this makes it available via portal_skins.
+from Products.CMFCore.DirectoryView import registerDirectory
+from config import GLOBALS
+#if $namespace_package == "Products"
+
+registerDirectory('skins', GLOBALS)
+#else
+
+from Products.CMFCore import utils
+from Globals import package_home
+from os.path import dirname
+
+\# temporarily add the path to the namespace package to the products path,
+\# so that the directory views are set up correctly
+ppath = utils.ProductsPath
+utils.ProductsPath.append(dirname(package_home(GLOBALS)))
+registerDirectory('skins', GLOBALS)
+utils.ProductsPath = ppath
+#end if
+#if str($zope2product) == 'True'
+
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/config.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/config.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/config.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+GLOBALS = globals()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,15 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ i18n_domain="${namespace_package}.${package}">
+
+ <include package="Products.GenericSetup" file="meta.zcml" />
+
+#if str($zope2product) == 'True'
+ <!-- Note: this needs at least Five 1.4. -->
+ <five:registerPackage package="." initialize=".initialize" />
+
+#end if
+ <include file="profiles.zcml" />
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_css tool. -->
+
+#end if
+<object name="portal_css" meta_type="Stylesheets Registry">
+
+#if str($include_doc) == 'True'
+ <!-- Stylesheets that will be registered with the portal_css tool are defined
+ here. You can also specify values for existing resources if you need to
+ modify some of their properties.
+ Stylesheet elements accept these parameters:
+ - 'id' (required): it must respect the name of the css or DTML file
+ (case sensitive). '.dtml' suffixes must be ignored.
+ - 'expression' (optional - default: ''): a tal condition.
+ - 'media' (optional - default: ''): possible values: 'screen', 'print',
+ 'projection', 'handheld'...
+ - 'rel' (optional - default: 'stylesheet')
+ - 'title' (optional - default: '')
+ - 'rendering' (optional - default: 'import'): 'import', 'link' or
+ 'inline'.
+ - 'enabled' (optional - default: True): boolean
+ - 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+ - 'insert_before', 'insert_after' (optional - default: '') resource id
+ See registerStylesheet() arguments in
+ ResourceRegistries/tools/CSSRegistry.py for the latest list of all
+ available keys and default values.
+ -->
+#end if
+ <stylesheet title="" cacheable="True" compression="safe" cookable="True"
+ enabled="1" expression="" id="${package}.css" media="screen"
+ rel="stylesheet" rendering="import"/>
+
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/import_steps.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/import_steps.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/import_steps.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="${package}_various"
+ version="20070220-01"
+ handler="${namespace_package}.${package}.setuphandlers.setupVarious"
+ title="${skinname}: miscellaneous import steps">
+ <dependency step="skins" />
+ Various import steps that are not handled by GS import/export
+ handlers.
+ </import-step>
+</import-steps>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_javascripts tool.
+ -->
+
+#end if
+<object name="portal_javascripts">
+
+#if str($include_doc) == 'True'
+ <!-- Javascript files that will be registered with the
+ portal_javascripts tool are defined here. You can also specify values
+ for existing resources if you need to modify some of their properties.
+ Javascript elements accept these parameters:
+ - 'id' (required): same rules as for stylesheets (see
+ 'cssregistry.xml').
+ - 'expression' (optional - default: ''): a tal condition.
+ - 'inline' (optional - default: False)
+ - 'enabled' (optional - default: True): boolean
+ - 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+ See registerScript() arguments in ResourceRegistries/tools/JSRegistry.py
+ for the latest list of all available keys and default values.
+ -->
+#end if
+<!-- EXAMPLE (UNCOMMENT TO MAKE AVAILABLE):
+ <javascript cacheable="True" compression="safe" cookable="True"
+ enabled="True" expression="" id="example.js" inline="False"/>
+ -->
+
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_skins tool -->
+
+<!-- Change the value of these parameters to modify portal_skins behavior:
+ - allow_any: change it to True if you want users to be able to select the
+ skin to use from their personal preferences management page. In the
+ ZMI, this value is known as 'Skin flexibility'.
+ - cookie_persistence: change it to True if you want to make the skin cookie
+ persist indefinitely. In the ZMI, this value is known as 'Skin Cookie
+ persistence'.
+ -->
+#end if
+<object name="portal_skins" allow_any="False" cookie_persistence="False"
+ default_skin="${skinname}">
+
+#if str($include_doc) == 'True'
+ <!-- This list registers the folders that are stored in the skins directory
+ of your product (on the filesystem) as Filesystem Directory Views within
+ the portal_skins tool, so that they become usable as skin layers.
+ -->
+#end if
+ <object name="${package}_images"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_images"/>
+ <object name="${package}_custom_images"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_custom_images"/>
+ <object name="${package}_styles"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_styles"/>
+ <object name="${package}_custom_styles"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_custom_styles"/>
+ <object name="${package}_templates"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_templates"/>
+ <object name="${package}_custom_templates"
+ meta_type="Filesystem Directory View"
+ directory="${package}/skins/${package}_custom_templates"/>
+
+#if str($include_doc) == 'True'
+ <!-- A skin-path in this file corresponds to a Skin Selection in the
+ 'Properties' tab of the portal_skins tool, in the ZMI.
+ You can define for each new skin path the layers that it holds. A new
+ skin can be based on another existing one by using the 'based-on'
+ attribute.
+ The definition of a layer accepts these parameters:
+ - name: quite self explanatory, the name of the layer.
+ - insert-before: name of the layer before which it must be added.
+ - insert-after: name of the layer after which it must be added.
+ Note: insert-before (and -after) accepts the value "*" which means
+ "all".
+ -->
+#end if
+ <skin-path name="${skinname}">
+ <layer name="custom"/>
+ <layer name="${package}_styles"/>
+ <layer name="kupu_tests"/>
+ <layer name="CMFPlacefulWorkflow"/>
+ <layer name="PasswordReset"/>
+ <layer name="kupu_plone"/>
+ <layer name="kupu"/>
+ <layer name="ATContentTypes"/>
+ <layer name="ATReferenceBrowserWidget"/>
+ <layer name="archetypes"/>
+ <layer name="mimetypes_icons"/>
+ <layer name="ResourceRegistries"/>
+ <layer name="gruf"/>
+ <layer name="plone_ecmascript"/>
+ <layer name="plone_wysiwyg"/>
+ <layer name="plone_prefs"/>
+ <layer name="plone_portlets"/>
+#if $skinbase == "Plone Tableless"
+ <layer name="plone_tableless"/>
+#end if
+ <layer name="plone_templates"/>
+ <layer name="plone_styles"/>
+ <layer name="plone_form_scripts"/>
+ <layer name="plone_scripts"/>
+ <layer name="plone_forms"/>
+ <layer name="plone_images"/>
+ <layer name="plone_content"/>
+ <layer name="plone_login"/>
+ <layer name="plone_deprecated"/>
+ <layer name="plone_3rdParty"/>
+ <layer name="cmf_legacy"/>
+ </skin-path>
+
+ <skin-path name="*">
+ <layer name="${package}_images"
+ insert-after="custom"/>
+ <layer name="${package}_templates"
+ insert-after="${package}_images"/>
+ </skin-path>
+
+ <skin-path name="${skinname}">
+ <layer name="${package}_custom_images"
+ insert-before="${package}_images"/>
+ <layer name="${package}_custom_templates"
+ insert-after="${package}_custom_images"/>
+ <layer name="${package}_custom_styles"
+ insert-after="${package}_custom_templates"/>
+ </skin-path>
+
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/profiles.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($add_profile) == 'True'
+ <genericsetup:registerProfile
+ name="default"
+ title="$skinname"
+ directory="profiles/default"
+ description="Extension profile for ${skinname} Product."
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+#end if
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/setuphandlers.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/setuphandlers.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/setuphandlers.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+def setupVarious(context):
+ pass # Replace this line with your own import stuff
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_images/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+This folder holds Filesystem Image files that are registered for the
+'${skinname}' Skin Selection only.
+They act as replacement for the default Plone (or 3rd party product) ones.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+This folder holds CSS and Filesystem Properties Object (commonly
+'base_properties.props') files that are registered for the
+'${skinname}' Skin Selection only.
+They act as replacement for the default Plone (or 3rd party product) ones.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base_properties.props_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base_properties.props_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/base_properties.props_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,52 @@
+# Please note that this approach will gradually be phased out, probably in
+# Plone 2.2 or 2.3. Using DTML in CSS is something we want to stop doing.
+
+DEPRECATED:string=This approach is deprecated and will be phased out in Plone 2.2 or 2.3
+
+title:string=${skinname}'s color, font, logo and border defaults
+
+plone_skin:string=${skinname}
+
+logoName:string=logo.jpg
+
+fontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+fontBaseSize:string=69%
+fontColor:string=Black
+fontSmallSize:string=85%
+
+backgroundColor:string=White
+
+linkColor:string=#436976
+linkActiveColor:string=Red
+linkVisitedColor:string=Purple
+
+borderWidth:string=1px
+borderStyle:string=solid
+borderStyleAnnotations:string=dashed
+
+globalBorderColor:string=#8cacbb
+globalBackgroundColor:string=#dee7ec
+globalFontColor:string=#436976
+
+headingFontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+
+contentViewBorderColor:string=#74ae0b
+contentViewBackgroundColor:string=#cde2a7
+contentViewFontColor:string=#578308
+
+inputFontColor:string=Black
+
+textTransform:string=lowercase
+
+evenRowBackgroundColor:string=#eef3f5
+oddRowBackgroundColor:string=transparent
+
+notifyBorderColor:string=#ffa500
+notifyBackgroundColor:string=#ffce7b
+
+discreetColor:string=#76797c
+helpBackgroundColor:string=#ffffe1
+
+portalMinWidth:string=70em
+columnOneWidth:string=16em
+columnTwoWidth:string=16em
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/generated.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/generated.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/generated.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/portlets.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/portlets.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/portlets.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/public.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/public.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_styles/public.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_custom_templates/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+This folder holds Filesystem Page Template files that are registered for the
+'${skinname}' Skin Selection only.
+They act as replacement for the default Plone (or 3rd party product) ones.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/CONTENT.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/CONTENT.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_images/CONTENT.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+This folder holds Filesystem Image files that are registered for all Skin
+Selections (all selectable skins in the 'portal_skins' tool).
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/+package+.css.dtml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/+package+.css.dtml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/+package+.css.dtml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_styles/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+Although this folder is not meant for storing customization skins, it holds
+stylesheet files that are registered for the '${skinname}' Skin Selection only.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/CONTENT.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/CONTENT.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/skins/+package+_templates/CONTENT.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+This folder holds Filesystem Page Template files that are registered for all
+Skin Selections (all selectable skins in the 'portal_skins' tool).
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/version.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/version.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/+namespace_package+/+package+/version.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+${version}
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/MANIFEST.in_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/MANIFEST.in_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2.5_theme/MANIFEST.in_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+recursive-include ${namespace_package} *
+global-exclude *pyc
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/Install.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/Install.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/Install.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,23 @@
+from cStringIO import StringIO
+
+from Products.${project}.Extensions.utils import *
+from Products.${project}.config import *
+
+def install(self):
+ out = StringIO()
+
+ setupSkins(self, out, GLOBALS, SKINSELECTIONS, SELECTSKIN, DEFAULTSKIN,
+ ALLOWSELECTION, PERSISTENTCOOKIE)
+ registerResources(self, out, 'portal_css', STYLESHEETS)
+ registerResources(self, out, 'portal_javascripts', JAVASCRIPTS)
+
+ print >> out, "Installation completed."
+ return out.getvalue()
+
+
+def uninstall(self):
+ out = StringIO()
+
+ removeSkins(self, out, SKINSELECTIONS, DEFAULTSKIN, RESETSKINTOOL)
+ resetResources(self, out, 'portal_css', STYLESHEETS)
+ resetResources(self, out, 'portal_javascripts', JAVASCRIPTS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+# this file is here to make Install.py and utils.py importable.
+# keep these lines to make it non-zero size and have winzip cooperate.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/utils.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/utils.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/Extensions/utils.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,147 @@
+import os, string
+from Globals import package_home
+from Products.CMFCore.DirectoryView import addDirectoryViews
+from Products.CMFCore.utils import getToolByName
+
+
+def getSkinsFolderNames(globals, skins_dir='skins'):
+ # Get the content of the skins folder
+ skins_path = os.path.join(package_home(globals), skins_dir)
+ return [ filename for filename in os.listdir(skins_path)
+ if (not filename.startswith('.') or filename in ('CVS', '{arch}'))
+ and os.path.isdir(os.path.join(skins_path, filename)) ]
+
+def setupSkin(self, out, globals, skin_selection, make_default,
+ allow_any, cookie_persistence, skins_dir='skins'):
+ skins_tool = getToolByName(self, 'portal_skins')
+ skin_name, base_skin = skin_selection['name'], skin_selection['base']
+
+ # Only add the skin selection if it doesn't already exist
+ if skin_name not in skins_tool.getSkinSelections():
+
+ # Get the skin layers of the base skin and convert to an array
+ layers = skins_tool.getSkinPath(base_skin)
+ layers = map(string.strip, string.split(layers, ','))
+
+ # Add the skin folders to the layers, under 'custom'
+ filenames = skin_selection.get('layers',
+ getSkinsFolderNames(globals, skins_dir))
+ for filename in filenames:
+ if filename not in layers:
+ try:
+ layers.insert(layers.index('custom')+1, filename)
+ except ValueError:
+ layers.insert(0, filename)
+
+ # Add our skin selection
+ layers = ', '.join(layers)
+ skins_tool.addSkinSelection(skin_name, layers)
+ print >> out, "Added skin selection to portal_skins."
+
+ # Activate the skin selection
+ if make_default:
+ skins_tool.default_skin = skin_name
+
+ # Setup other tool properties
+ skins_tool.allow_any = allow_any
+ skins_tool.cookie_persistence = cookie_persistence
+
+ else:
+ print >> out, "Skin selection already exists, leaving it alone."
+
+def setupSkins(self, out, globals, skin_selections, select_skin, default_skin,
+ allow_any, cookie_persistence, skins_dir='skins'):
+ skins_tool = getToolByName(self, 'portal_skins')
+
+ # Add directory views
+ addDirectoryViews(skins_tool, skins_dir, globals)
+ print >> out, "Added directory views to portal_skins."
+
+ # Install skin selections
+ for skin in skin_selections:
+ make_default = False
+ if select_skin and skin['name'] == default_skin:
+ make_default = True
+ setupSkin(self, out, globals, skin, make_default,
+ allow_any, cookie_persistence, skins_dir)
+
+def registerResources(self, out, toolname, resources):
+ tool = getToolByName(self, toolname)
+ existing = tool.getResourceIds()
+ cook = False
+ for resource in resources:
+ if not resource['id'] in existing:
+ # register additional resource in the specified registry...
+ if toolname == "portal_css":
+ tool.registerStylesheet(**resource)
+ if toolname == "portal_javascripts":
+ tool.registerScript(**resource)
+ print >> out, "Added %s to %s." % (resource['id'], tool)
+ else:
+ # ...or update existing one
+ parameters = tool.getResource(resource['id'])._data
+ for key in [k for k in resource.keys() if k != 'id']:
+ originalkey = 'original_'+key
+ original = parameters.get(originalkey)
+ if not original:
+ parameters[originalkey] = parameters[key]
+ parameters[key] = resource[key]
+ print >> out, "Updated %s in %s." % (resource['id'], tool)
+ cook = True
+ if cook:
+ tool.cookResources()
+ print >> out, "Successfuly Installed/Updated resources in %s." % tool
+
+def removeSkins(self, out, skin_selections=(),
+ default=None, resetskintool=True):
+ skins_tool = getToolByName(self, 'portal_skins')
+
+ # Remove skin selections from portal_skins
+ for skin in skin_selections:
+ skin_name = skin['name']
+ if skin_name in skins_tool.getSkinSelections():
+ skins_tool.manage_skinLayers(del_skin=1, chosen=(skin_name,))
+ print >> out, \
+ "Removed skin selection '%s' from portal skins." %skin_name
+
+ # Set Skins Tool parameters back to defaults
+ if resetskintool:
+ # Restore Plone defaults
+ skins_tool.allow_any = 0
+ skins_tool.cookie_persistence = 0
+ selection = 'Plone Default'
+ print >> out, "Restored Plone defaults in portal_skins"
+ else:
+ # Select the base of the default skin selection in the skins tool
+ if skin_selections:
+ if default:
+ selection = [ s for s in skin_selections
+ if s['name'] == default ]
+ if selection:
+ selection = selection[0]['base']
+ else:
+ selection = skin_selections[0]['base']
+ skins_tool.default_skin = selection
+ print >> out, "Setup '%s' as default skin in portal_skins" % selection
+
+def resetResources(self, out, toolname, resources):
+ # Revert resource customizations
+ tool = getToolByName(self, toolname)
+ for resource in [tool.getResource(r['id']) for r in resources]:
+ if resource is None:
+ continue
+ for key in resource._data.keys():
+ originalkey = 'original_'+key
+ if resource._data.has_key(originalkey):
+ try: # <- BBB
+ resource._data[key] = resource._data[originalkey]['value']
+ except TypeError:
+ resource._data[key] = resource._data[originalkey]
+ del resource._data[originalkey]
+
+__all__ = (
+ "setupSkins",
+ "registerResources",
+ "removeSkins",
+ "resetResources",
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/HISTORY.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/HISTORY.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/HISTORY.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+Changelog for ${project}
+
+ (name of developer listed in brackets)
+
+${project} - ${version} Unreleased
+
+ - Initial theme product structure.
+ [zopeskel]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+${project} Readme
+${project and '='*(len($project)+7) or '========'}
+
+Overview
+--------
+
+$description
+${long_description and '\n'+long_description or None}
+
+Installation
+------------
+
+Place ${project} in the Products directory of your Zope instance
+and restart the server.
+
+Go to the 'Site Setup' page in the Plone interface and click on the
+'Add/Remove Products' link.
+
+Choose ${project} (check its checkbox) and click the 'Install' button.
+
+You may have to empty your browser cache to see the effects of the product
+installation/uninstallation.
+
+Uninstall
+ This can be done from the same management screen.
+
+
+Selecting a skin
+----------------
+
+Depending on the value given to SELECTSKIN (in config.py), the skin will be
+selected (or not) as default one while installing the product. If you need to
+switch from a default skin to another, go to the 'Site Setup' page, and choose
+'Skins' (as portal manager). You can also decide from that page if members can
+choose their preferred skin and, in that case, if the skin cookie should be
+persistent.
+
+Note -- Don't forget to perform a full refresh of the page or reload all
+images (not from browser cache) after selecting a skin. In Firefox, you can do
+so by pressing the 'shift' key while reloading the page. In IE, use the key
+combination <Ctrl-F5>.
+
+
+Credits
+-------
+
+Written by ${author or None}${author_email and ' (%s)'%$author_email or None}
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+# Register our skins directory - this makes it available via portal_skins.
+from Products.CMFCore.DirectoryView import registerDirectory
+
+from config import GLOBALS
+registerDirectory('skins', GLOBALS)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/config.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/config.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/config.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,92 @@
+GLOBALS = globals()
+
+#if str($include_doc) == 'True'
+# CHANGE this tuple of python dictionaries to list the different skin
+# selections and their associated specific layers.
+# 'name' (required): the name of the new skin.
+# This will be what the user sees when choosing skins, and will be the
+# name of a property in portal_skins.
+# 'base' (required): the name of the skin selection on which the new one
+# is based.
+# 'layers' (optional): the name of the specific layers for the skin
+# selection. By default (if the value is empty or if the key is absent
+# from the dictionnary), all the folders in 'skins/' will be listed
+# underneath 'custom' in the new skin selection layers.
+#end if
+SKINSELECTIONS = (
+ {'name': '$skinname',
+ 'base': '$skinbase',
+ },
+ )
+
+#if str($include_doc) == 'True'
+# CHANGE it to False if you don't want the new skin selection to be selected
+# at installation.
+#end if
+SELECTSKIN = True
+
+#if str($include_doc) == 'True'
+# CHANGE it to the name of the skin selection that must be set as default in
+# case SELECTSKIN is set to True.
+#end if
+DEFAULTSKIN = '$skinname'
+
+#if str($include_doc) == 'True'
+# CHANGE this tuple of python dictionnaries to list the stylesheets that
+# will be registered with the portal_css tool.
+# 'id' (required):
+# it must respect the name of the css or DTML file (case sensitive).
+# '.dtml' suffixes must be ignored.
+# 'expression' (optional - default: ''): a tal condition.
+# 'media' (optional - default: ''): possible values: 'screen', 'print',
+# 'projection', 'handheld'...
+# 'rel' (optional - default: 'stylesheet')
+# 'title' (optional - default: '')
+# 'rendering' (optional - default: 'import'): 'import', 'link' or 'inline'.
+# 'enabled' (optional - default: True): boolean
+# 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+# See registerStylesheet() arguments in
+# ResourceRegistries/tools/CSSRegistry.py
+# for the latest list of all available keys and default values.
+#end if
+STYLESHEETS = (
+ {'id': '${package}.css', 'media': 'screen', 'rendering': 'import'},
+ )
+
+#if str($include_doc) == 'True'
+# CHANGE this tuple of python dictionnaries to list the javascripts that
+# will be registered with the portal_javascripts tool.
+# 'id' (required): same rules as for stylesheets.
+# 'expression' (optional - default: ''): a tal condition.
+# 'inline' (optional - default: False): boolean
+# 'enabled' (optional - default: True): boolean
+# 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+# See registerScript() arguments in ResourceRegistries/tools/JSRegistry.py
+# for the latest list of all available keys and default values.
+JAVASCRIPTS = (
+# {'id': '${package}.js.dtml',},
+ )
+#else
+JAVASCRIPTS = ()
+#end if
+
+#if str($include_doc) == 'True'
+# CHANGE it to True if you want users to be able to select the skin to use
+# from their personal preferences management page.
+# In the ZMI, this value is known as 'Skin flexibility'.
+#end if
+ALLOWSELECTION = False
+
+#if str($include_doc) == 'True'
+# CHANGE it to True if you want to make the skin cookie persist indefinitely.
+# In the ZMI, this value is known as 'Skin Cookie persistence'.
+#end if
+PERSISTENTCOOKIE = False
+
+#if str($include_doc) == 'True'
+# CHANGE it to True if you want portal_skins properties to be reset to Plone
+# default values when the product is uninstalled:
+# Default Skin: 'Plone Default', Skin flexibility: False,
+# Skin Cookie persistence: False.
+#end if
+RESETSKINTOOL = False
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/+package+.css.dtml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/+package+.css.dtml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/+package+.css.dtml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base_properties.props_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base_properties.props_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/base_properties.props_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+title:string=$skinname's color, font, logo and border defaults
+
+plone_skin:string=$skinname
+
+logoName:string=logo.jpg
+
+fontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+fontBaseSize:string=69%
+fontColor:string=Black
+fontSmallSize:string=85%
+
+backgroundColor:string=White
+
+linkColor:string=#436976
+linkActiveColor:string=Red
+linkVisitedColor:string=Purple
+
+borderWidth:string=1px
+borderStyle:string=solid
+borderStyleAnnotations:string=dashed
+
+globalBorderColor:string=#8cacbb
+globalBackgroundColor:string=#dee7ec
+globalFontColor:string=#436976
+
+headingFontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+
+contentViewBorderColor:string=#74ae0b
+contentViewBackgroundColor:string=#cde2a7
+contentViewFontColor:string=#578308
+
+inputFontColor:string=Black
+
+textTransform:string=lowercase
+
+evenRowBackgroundColor:string=#eef3f5
+oddRowBackgroundColor:string=transparent
+
+notifyBorderColor:string=#ffa500
+notifyBackgroundColor:string=#ffce7b
+
+discreetColor:string=#76797c
+helpBackgroundColor:string=#ffffe1
+
+portalMinWidth:string=70em
+columnOneWidth:string=16em
+columnTwoWidth:string=16em
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/generated.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/generated.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/generated.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/portlets.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/portlets.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/portlets.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/public.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/public.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/skins/+package+_styles/public.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+"""\
+To run all tests type 'python runalltests.py'
+"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/framework.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/framework.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/framework.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# ZopeTestCase
+#
+# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
+#
+# This version of framework.py will use the SOFTWARE_HOME
+# environment variable to locate Zope and the Testing package.
+#
+# If the tests are run in an INSTANCE_HOME installation of Zope,
+# Products.__path__ and sys.path with be adjusted to include the
+# instance's Products and lib/python directories respectively.
+#
+# If you explicitly set INSTANCE_HOME prior to running the tests,
+# auto-detection is disabled and the specified path will be used
+# instead.
+#
+# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
+# will be adjusted to use it.
+#
+# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
+# is assumed, and you can attach to a running ZEO server (via the
+# instance's custom_zodb.py).
+#
+##############################################################################
+#
+# The following code should be at the top of every test module:
+#
+# import os, sys
+# if __name__ == '__main__':
+# execfile(os.path.join(sys.path[0], 'framework.py'))
+#
+# ...and the following at the bottom:
+#
+# if __name__ == '__main__':
+# framework()
+#
+##############################################################################
+
+__version__ = '0.2.3'
+
+# Save start state
+#
+
+import os
+import sys
+
+__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
+__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
+
+if __SOFTWARE_HOME.endswith(os.sep):
+ __SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
+
+if __INSTANCE_HOME.endswith(os.sep):
+ __INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
+
+# Find and import the Testing package
+#
+if not sys.modules.has_key('Testing'):
+ p0 = sys.path[0]
+ if p0 and __name__ == '__main__':
+ os.chdir(p0)
+ p0 = ''
+ s = __SOFTWARE_HOME
+ p = d = s and s or os.getcwd()
+ while d:
+ if os.path.isdir(os.path.join(p, 'Testing')):
+ zope_home = os.path.dirname(os.path.dirname(p))
+ sys.path[:1] = [p0, p, zope_home]
+ break
+ p, d = s and ('','') or os.path.split(p)
+ else:
+ print 'Unable to locate Testing package.',
+ print 'You might need to set SOFTWARE_HOME.'
+ sys.exit(1)
+
+import Testing, unittest
+execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
+
+# Include ZopeTestCase support
+#
+if 1: # Create a new scope
+
+ p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
+
+ if not os.path.isdir(p):
+ print 'Unable to locate ZopeTestCase package.',
+ print 'You might need to install ZopeTestCase.'
+ sys.exit(1)
+
+ ztc_common = 'ztc_common.py'
+ ztc_common_global = os.path.join(p, ztc_common)
+
+ f = 0
+ if os.path.exists(ztc_common_global):
+ execfile(ztc_common_global)
+ f = 1
+ if os.path.exists(ztc_common):
+ execfile(ztc_common)
+ f = 1
+
+ if not f:
+ print 'Unable to locate %s.' % ztc_common
+ sys.exit(1)
+
+# Debug
+#
+print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
+print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
+sys.stdout.flush()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/runalltests.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/runalltests.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/runalltests.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,28 @@
+#
+# Runs all tests in the current directory
+#
+# Execute like:
+# python runalltests.py
+#
+# Alternatively use the testrunner:
+# python /path/to/Zope/utilities/testrunner.py -qa
+#
+
+import os, sys
+if __name__ == '__main__':
+ execfile(os.path.join(sys.path[0], 'framework.py'))
+
+import unittest
+TestRunner = unittest.TextTestRunner
+suite = unittest.TestSuite()
+
+tests = os.listdir(os.curdir)
+tests = [n[:-3] for n in tests if n.startswith('test') and n.endswith('.py')]
+
+for test in tests:
+ m = __import__(test)
+ if hasattr(m, 'test_suite'):
+ suite.addTest(m.test_suite())
+
+if __name__ == '__main__':
+ TestRunner().run(suite)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testSkeleton.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testSkeleton.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testSkeleton.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,37 @@
+#
+# This file is a skeleton test suite.
+# It is here for letting you add new tests to the product without having to
+# modify the existing testStyleInstallation.py module.
+# You may modify its name to something that describes what it tests
+# (keeping its 'test' prefix).
+#
+
+import os, sys
+if __name__ == '__main__':
+ execfile(os.path.join(sys.path[0], 'framework.py'))
+
+from Products.PloneTestCase import PloneTestCase
+
+PloneTestCase.installProduct('${project}')
+PloneTestCase.setupPloneSite(products=['${project}'])
+
+
+class TestSomething(PloneTestCase.PloneTestCase):
+
+ def afterSetUp(self):
+ pass
+
+ def testSomething(self):
+ # Test something
+ self.assertEqual(1+1, 2)
+
+
+def test_suite():
+ from unittest import TestSuite, makeSuite
+ suite = TestSuite()
+ suite.addTest(makeSuite(TestSomething))
+ return suite
+
+if __name__ == '__main__':
+ framework()
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testStyleInstallation.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testStyleInstallation.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/tests/testStyleInstallation.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,201 @@
+#
+# Unit Tests for the style install and uninstall methods
+#
+
+import os, sys
+if __name__ == '__main__':
+ execfile(os.path.join(sys.path[0], 'framework.py'))
+
+from Products.PloneTestCase import PloneTestCase
+
+from Products.${project}.config import *
+from Products.${project}.Extensions.utils import getSkinsFolderNames
+PROJECTNAME = '${project}'
+
+PloneTestCase.installProduct(PROJECTNAME)
+PloneTestCase.setupPloneSite(products=[PROJECTNAME])
+
+class testSkinsTool(PloneTestCase.PloneTestCase):
+
+ def afterSetUp(self):
+ self.tool = getattr(self.portal, 'portal_skins')
+
+ def testSkinSelectionCreated(self):
+ """Test if a new skin exists in portal_skins."""
+ for skin_selection in SKINSELECTIONS:
+ self.failUnless(
+ skin_selection['name'] in self.tool.getSkinSelections())
+
+ def testSkinPaths(self):
+ """Test if the skin layers in the new skin were correctly added."""
+ skinsfoldernames = getSkinsFolderNames(GLOBALS)
+ skins_dict = {}
+ for skin in SKINSELECTIONS:
+ skins_dict[skin['name']] = skin.get('layers', skinsfoldernames)
+ for selection, layers in self.tool.getSkinPaths():
+ if skins_dict.has_key(selection):
+ for specific_layer in skins_dict[selection]:
+ self.failUnless(specific_layer in layers)
+ else:
+ for foldername in skinsfoldernames:
+ self.failIf(foldername in layers)
+
+ def testSkinSelection(self):
+ """Test if the new skin was selected as default one."""
+ if SELECTSKIN:
+ self.assertEqual(self.tool.getDefaultSkin(), DEFAULTSKIN)
+
+ def testSkinFlexibility(self):
+ """Test if the users can choose their skin."""
+ self.assertEqual(self.tool.getAllowAny(), ALLOWSELECTION)
+
+ def testCookiePersistance(self):
+ """Test if the skin choice is peristant between sessions."""
+ self.assertEqual(bool(self.tool.getCookiePersistence()),
+ PERSISTENTCOOKIE)
+
+class testResourceRegistrations(PloneTestCase.PloneTestCase):
+
+ def afterSetUp(self):
+ self.qitool = getattr(self.portal, 'portal_quickinstaller')
+ self.csstool = getattr(self.portal, 'portal_css')
+ self.jstool = getattr(self.portal, 'portal_javascripts')
+ product_settings = getattr(self.qitool, PROJECTNAME)
+ self.stylesheets = product_settings.resources_css
+ self.javascripts = product_settings.resources_js
+
+ def testStylesheetsInstalled(self):
+ """Test if new stylesheets were added to portal_css."""
+ stylesheetids = self.csstool.getResourceIds()
+ for css in STYLESHEETS:
+ self.failUnless(css['id'] in stylesheetids)
+
+ def testStylesheetProperties(self):
+ """Test if new stylesheets have correct parameters."""
+ for config in STYLESHEETS:
+ res = self.csstool.getResource(config['id'])
+ for key in [key for key in config.keys() if key != 'id']:
+ self.assertEqual(res._data[key], config[key])
+
+ def testStylesheetsUpdated(self):
+ """Test if existing stylesheets were correctly updated."""
+ for config in [c for c in STYLESHEETS
+ if c['id'] not in self.stylesheets]:
+ resource = self.csstool.getResource(config['id'])
+ for key in [k for k in config.keys() if k != 'id']:
+ self.failUnless(resource._data.has_key('original_'+key))
+
+ def testJavascriptsInstalled(self):
+ """Test if new javascripts were added to portal_javascripts."""
+ javascriptids = self.jstool.getResourceIds()
+ for js in JAVASCRIPTS:
+ self.failUnless(js['id'] in javascriptids)
+
+ def testMemberStylesheetProperties(self):
+ """Test if new javascripts have correct parameters."""
+ for config in JAVASCRIPTS:
+ res = self.jstool.getResource(config['id'])
+ for key in [key for key in config.keys() if key != 'id']:
+ self.assertEqual(res._data[key], config[key])
+
+ def testJavascriptsUpdated(self):
+ """Test if existing javascripts were correctly updated."""
+ for config in [c for c in JAVASCRIPTS
+ if c['id'] not in self.javascripts]:
+ resource = self.jstool.getResource(config['id'])
+ for key in [k for k in config.keys() if k != 'id']:
+ self.failUnless(resource._data.has_key('original_'+key))
+
+
+class testUninstall(PloneTestCase.PloneTestCase):
+
+ def afterSetUp(self):
+ """Test if ."""
+ self.qitool = getattr(self.portal, 'portal_quickinstaller')
+ self.skinstool = getattr(self.portal, 'portal_skins')
+ self.csstool = getattr(self.portal, 'portal_css')
+ self.jstool = getattr(self.portal, 'portal_javascripts')
+ product_settings = getattr(self.qitool, PROJECTNAME)
+ self.stylesheets = product_settings.resources_css
+ self.javascripts = product_settings.resources_js
+ self.qitool.uninstallProducts(products=[PROJECTNAME])
+ self.ttool = getattr(self.portal, 'portal_types')
+
+ def testProductUninstalled(self):
+ """Test if the product was uninstalled."""
+ self.failIf(self.qitool.isProductInstalled(PROJECTNAME))
+
+ def testSkinSelectionDeleted(self):
+ """Test if the skin selection was removed from portal_skins."""
+ skin_selections = self.skinstool.getSkinSelections()
+ for skin in SKINSELECTIONS:
+ self.failIf(skin['name'] in skin_selections)
+
+ def testDefaultSkinChanged(self):
+ """Test if default skin is back to old value or default Plone."""
+ default_skin = self.skinstool.getDefaultSkin()
+ if RESETSKINTOOL:
+ self.assertEqual(default_skin, 'Plone Default')
+ else:
+ if DEFAULTSKIN:
+ for skin in SKINSELECTIONS:
+ if skin['name'] == DEFAULTSKIN:
+ self.assertEqual(default_skin, skin['base'])
+ else:
+ self.assertEqual(default_skin, SKINSELECTIONS[0]['base'])
+
+ def testResetSkinFlexibility(self):
+ """Test if the users still can choose their skin."""
+ allow_any = self.skinstool.getAllowAny()
+ if RESETSKINTOOL:
+ self.failIf(allow_any)
+ else:
+ self.assertEqual(allow_any, ALLOWSELECTION)
+
+ def testResetCookiePersistance(self):
+ """Test if the skin choice is still peristant between sessions."""
+ cookie_peristence = self.skinstool.getCookiePersistence()
+ if RESETSKINTOOL:
+ self.failIf(cookie_peristence)
+ else:
+ self.assertEqual(cookie_peristence, PERSISTENTCOOKIE)
+
+ def testStylesheetsUninstalled(self):
+ """Test if added stylesheets were removed from portal_css."""
+ resourceids = self.csstool.getResourceIds()
+ for css in self.stylesheets:
+ self.failIf(css in resourceids)
+
+ def testResetDefaultStylesheets(self):
+ """Test if values were reverted in existing stylesheets."""
+ for config in [c for c in STYLESHEETS
+ if c['id'] not in self.stylesheets]:
+ resource = self.csstool.getResource(config['id'])
+ for key in [k for k in config.keys() if k != 'id']:
+ self.failIf(resource._data.has_key('original_'+key))
+
+ def testJavascriptsUninstalled(self):
+ """Test if added javascripts were removed from portal_js."""
+ resourceids = self.jstool.getResourceIds()
+ for js in self.javascripts:
+ self.failIf(js in resourceids)
+
+ def testResetDefaultJavascripts(self):
+ """Test if values were reverted in existing javascripts."""
+ for config in [c for c in JAVASCRIPTS
+ if c['id'] not in self.javascripts]:
+ resource = self.jstool.getResource(config['id'])
+ for key in [k for k in config.keys() if k != 'id']:
+ self.failIf(resource._data.has_key('original_'+key))
+
+
+if __name__ == '__main__':
+ framework()
+else:
+ import unittest
+ def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(testSkinsTool))
+ suite.addTest(unittest.makeSuite(testResourceRegistrations))
+ suite.addTest(unittest.makeSuite(testUninstall))
+ return suite
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/version.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/version.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone2_theme/version.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+$version
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,327 @@
+=======================
+Using a custom buildout
+=======================
+
+Note: If you are using Windows, if you do not have PIL installed, or you are
+not using Python 2.4 as your main system Python, please see the relevant
+sections below.
+
+You probably got here by running something like:
+
+ $ paster create -t plone3_buildout
+
+Now, you need to run:
+
+ $ python bootstrap.py
+
+This will install zc.buildout for you.
+
+To create an instance immediately, run:
+
+ $ bin/buildout
+
+This will download Plone's eggs and products for you, as well as other
+dependencies, create a new Zope 2 installation (unless you specified
+an existing one when you ran "paster create"), and create a new Zope instance
+configured with these products.
+
+You can start your Zope instance by running:
+
+ $ bin/instance start
+
+or, to run in foreground mode:
+
+ $ bin/instance fg
+
+To run unit tests, you can use:
+
+ $ bin/instance test -s my.package
+
+Installing PIL
+--------------
+
+To use Plone, you need PIL, the Python Imaging Library. If you don't already
+have this, download and install it from http://www.pythonware.com/products/pil.
+
+Using a different Python installation
+--------------------------------------
+
+Buildout will use your system Python installation by default. However, Zope
+2.10 (and by extension, Plone) will only work with Python 2.4. You can verify
+which version of Python you have, by running:
+
+ $ python -V
+
+If that is not a 2.4 version, you need to install Python 2.4 from
+http://python.org. If you wish to keep another version as your main system
+Python, edit buildout.cfg and add an 'executable' option to the "[buildout]"
+section, pointing to a python interpreter binary:
+
+ [buildout]
+ ...
+ executable = /path/to/python
+
+Working with buildout.cfg
+-------------------------
+
+You can change any option in buildout.cfg and re-run bin/buildout to reflect
+the changes. This may delete things inside the 'parts' directory, but should
+keep your Data.fs and source files intact.
+
+To save time, you can run buildout in "offline" (-o) and non-updating (-N)
+mode, which will prevent it from downloading things and checking for new
+versions online:
+
+ $ bin/buildout -Nov
+
+Creating new eggs
+-----------------
+
+New packages you are working on (but which are not yet released as eggs and
+uploaded to the Python Package Index, aka PYPI) should be placed in src. You can do:
+
+ $ cd src/
+ $ paster create -t plone my.package
+
+Use "paster create --list-templates" to see all available templates. Answer
+the questions and you will get a new egg. Then tell buildout about your egg
+by editing buildout.cfg and adding your source directory to 'develop':
+
+ [buildout]
+ ...
+ develop =
+ src/my.package
+
+You can list multiple packages here, separated by whitespace or indented
+newlines.
+
+You probably also want the Zope instance to know about the package. Add its
+package name to the list of eggs in the "[instance]" section, or under the
+main "[buildout]" section:
+
+ [instance]
+ ...
+ eggs =
+ ${buildout:eggs}
+ ${plone:eggs}
+ my.package
+
+Leave the ${buildout:eggs} part in place - it tells the instance to use the
+eggs that buildout will have downloaded from the Python Package Index
+previously.
+
+If you also require a ZCML slug for your package, buildout can create one
+automatically. Just add the package to the 'zcml' option:
+
+ [instance]
+ ...
+ zcml =
+ my.package
+
+When you are finished, re-run buildout. Offline, non-updating mode should
+suffice:
+
+ $ bin/buildout -Nov
+
+Developing old-style products
+-----------------------------
+
+If you are developing old-style Zope 2 products (not eggs) then you can do so
+by placing the product code in the top-level 'products' directory. This is
+analogous to the 'Products/' directory inside a normal Zope 2 instance and is
+scanned on start-up for new products.
+
+Depending on a new egg
+----------------------
+
+If you want to use a new egg that is in the Python Package Index, all you need
+to do is to add it to the "eggs" option under the main "[buildout]" section:
+
+ [buildout]
+ ...
+ eggs =
+ my.package
+
+If it's listed somewhere else than the Python Package Index, you can add a link
+telling buildout where to find it in the 'find-links' option:
+
+ [buildout]
+ ...
+ find-links =
+ http://dist.plone.org
+ http://download.zope.org/distribution/
+ http://effbot.org/downloads
+ http://some.host.com/packages
+
+Using existing old-style products
+---------------------------------
+
+If you are using an old-style (non-egg) product, you can either add it as an
+automatically downloaded archive or put it in the top-level "products" folder.
+The former is probably better, because it means you can redistribute your
+buildout.cfg more easily:
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+
+If someproduct-1.3.tar.gz extracts into several products inside a top-level
+directory, e.g. SomeProduct-1.3/PartOne and SomeProduct-1.3/PartTwo, then
+add it as a "nested package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ nested-packages =
+ someproduct-1.3.tar.gz
+
+Alternatively, if it extracts to a directory which contains the version
+number, add it as a "version suffix package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ version-suffix-packages =
+ someproduct-1.3.tar.gz
+
+You can also track products by adding a new bundle checkout part. It
+doesn't strictly have to be an svn bundle at all, any svn location will do,
+and cvs is also supported:
+
+ [buildout]
+ ...
+ parts =
+ plone
+ zope2
+ productdistros
+ myproduct
+ instance
+ zopepy
+
+Note that "myproduct" comes before the "instance" part. You then
+need to add a new section to buildout.cfg:
+
+ [myproduct]
+ recipe = plone.recipe.bundlecheckout
+ url = http://svn.plone.org/svn/collective/myproduct/trunk
+
+Finally, you need to tell Zope to find this new checkout and add it to its
+list of directories that are scanned for products:
+
+ [instance]
+ ...
+ products =
+ ${buildout:directory}/products
+ ${productdistros:location}
+ ${plonebundle:location}
+ ${myproduct:location}
+
+Without this last step, the "myproduct" part is simply managing an svn
+checkout and could potentially be used for something else instead.
+
+=============
+Using Windows
+=============
+
+To use buildout on Windows, you will need to install a few dependencies which
+other platforms manage on their own.
+
+Here are the steps you need to follow (thanks to Hanno Schlichting for these):
+
+Python (http://python.org)
+--------------------------
+
+ - Download and install Python 2.4.4 using the Windows installer from
+ http://www.python.org/ftp/python/2.4.4/python-2.4.4.msi
+ Select 'Install for all users' and it will put Python into the
+ "C:\Python24" folder by default.
+
+ - You also want the pywin32 extensions available from
+ http://downloads.sourceforge.net/pywin32/pywin32-210.win32-py2.4.exe?modtime=1159009237&big_mirror=0
+
+ - And as a last step you want to download the Python imaging library available
+ from http://effbot.org/downloads/PIL-1.1.6.win32-py2.4.exe
+
+ - If you develop Zope based applications you will usually only need Python 2.4
+ at the moment, so it's easiest to put the Python binary on the systems PATH,
+ so you don't need to specify its location manually each time you call it.
+
+ Thus, put "C:\Python24" and "C:\Python24\Scripts" onto the PATH. You can
+ find the PATH definition in the control panel under system preferences on
+ the advanced tab at the bottom. The button is called environment variables.
+ You want to add it at the end of the already existing PATH in the system
+ section. Paths are separated by a semicolons.
+
+ - You can test if this was successful by opening a new shell (cmd) and type
+ in 'python -V'. It should report version 2.4.4 (or whichever version you
+ installed).
+
+ Opening a new shell can be done quickly by using the key combination
+ 'Windows-r' or if you are using Parallels on a Mac 'Apple-r'. Type in 'cmd'
+ into the popup box that opens up and hit enter.
+
+
+Subversion (http://subversion.tigris.org)
+-----------------------------------------
+
+ - Download the nice installer from
+ http://subversion.tigris.org/files/documents/15/35379/svn-1.4.2-setup.exe
+
+ - Run the installer. It defaults to installing into
+ "C:\Program Files\Subversion".
+
+ - Now put the install locations bin subfolder (for example
+ "C:\Program Files\Subversion\bin") on your system PATH in the same way you
+ put Python on it.
+
+ - Open a new shell again and type in: 'svn --version' it should report
+ version 1.4.2 or newer.
+
+
+MinGW (http://www.mingw.org/)
+-----------------------------
+
+ This is a native port of the gcc compiler and its dependencies for Windows.
+ There are other approaches enabling you to compile Python C extensions on
+ Windows including Cygwin and using the official Microsoft C compiler, but this
+ is a lightweight approach that uses only freely available tools. As
+ it's used by a lot of people chances are high it will work for you and there's
+ plenty of documentation out there to help you in troubleshooting problems.
+
+ - Download the MinGW installer from
+ http://downloads.sourceforge.net/mingw/MinGW-5.1.3.exe?modtime=1168794334&big_mirror=1
+
+ - The installer will ask you which options you would like to install. Choose
+ base and make here. It will install into "C:\MinGW" by default. The install
+ might take some time as it's getting files from sourceforge.net and you
+ might need to hit 'retry' a couple of times.
+
+ - Now put the install location's bin subfolder (for example "C:\MinGW\bin") on
+ your system PATH in the same way you put Python on it.
+
+ - Test this again by typing in: 'gcc --version' on a newly opened shell and
+ it should report version 3.4.2 or newer.
+
+
+Configure Distutils to use MinGW
+--------------------------------
+
+ Some general information are available from
+ http://www.mingw.org/MinGWiki/index.php/Python%20extensions for example but
+ you don't need to read them all.
+
+ - Create a file called 'distutils.cfg' in "C:\Python24\Lib\distutils". Open it
+ with a text editor ('notepad distutils.cfg') and fill in the following lines:
+
+ [build]
+ compiler=mingw32
+
+ This will tell distutils to use MinGW as the default compiler, so you don't
+ need to specify it manually using "--compiler=mingw32" while calling a
+ package's setup.py with a command that involves building C extensions. This
+ is extremely useful if the build command is written down in a buildout
+ recipe where you cannot change the options without hacking the recipe
+ itself. The z2c.recipe.zope2install used in ploneout is one such example.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+import urllib2
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="distribute", default=False,
+ help="Use Disribute rather than Setuptools.")
+
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.version is not None:
+ VERSION = '==%s' % options.version
+else:
+ VERSION = ''
+
+# We decided to always use distribute, make sure this is the default for us
+# USE_DISTRIBUTE = options.distribute
+USE_DISTRIBUTE = True
+args = args + ['bootstrap']
+
+to_reload = False
+try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ to_reload = True
+ raise ImportError
+except ImportError:
+ ez = {}
+ if USE_DISTRIBUTE:
+ setup_url = 'http://python-distribute.org/distribute_setup.py'
+ exec urllib2.urlopen(setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+ else:
+ ez_setup_url = 'http://peak.telecommunity.com/dist/ez_setup.py'
+ exec urllib2.urlopen(ez_setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ if to_reload:
+ reload(pkg_resources)
+ else:
+ import pkg_resources
+
+
+def quote(c):
+ if sys.platform == 'win32':
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+
+if USE_DISTRIBUTE:
+ requirement = 'distribute'
+else:
+ requirement = 'setuptools'
+
+pythonpath = ws.find(pkg_resources.Requirement.parse(requirement)).location
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout' + VERSION],
+ env=dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote(sys.executable),
+ '-c', quote(cmd), '-mqNxd', quote(tmpeggs), 'zc.buildout' + VERSION,
+ dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,192 @@
+[buildout]
+parts =
+#if not $eggifiedplone
+ plone
+#end if
+#if not $zope2_install
+ zope2
+#end if
+ productdistros
+ instance
+ zopepy
+
+#if $eggifiedplone
+\# Change the number here to change the version of Plone being used
+extends =
+#if $eggifiedzope
+ http://download.zope.org/Zope2/index/${zope2_version}/versions.cfg
+#end if
+ http://dist.plone.org/release/${plone_version}/versions.cfg
+#end if
+versions = versions
+
+
+\# Add additional egg download sources here. dist.plone.org contains archives
+\# of Plone packages.
+find-links =
+#if $eggifiedplone
+ http://dist.plone.org/release/${plone_version}
+#else
+ http://dist.plone.org
+#end if
+ http://dist.plone.org/thirdparty
+
+\# Add additional eggs here
+#if not $eggifiedplone
+\# elementtree is required by Plone
+#end if
+eggs =
+#if not $eggifiedplone
+ elementtree
+#end if
+
+\# Reference any eggs you are developing here, one per line
+\# e.g.: develop = src/my.package
+develop =
+
+#if not $eggifiedplone
+[versions]
+\# Version pins for new style products go here
+plone.recipe.zope2instance = 3.6
+#end if
+
+#if $tarballs
+[plone]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.plone
+recipe = plone.recipe.plone==${plone_version}
+#if $plone_products_install
+\# By overriding the download URLs and making them an empty list, we
+\# Make sure our own products directory takes precedence
+urls =
+#end if
+#end if
+
+#if $z29tarballs
+[plone]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.distros
+recipe = plone.recipe.distros
+urls = http://launchpad.net/plone/2.5/${plone_version}/+download/Plone-${plone_version}.tar.gz
+nested-packages = Plone-${plone_version}.tar.gz
+version-suffix-packages = Plone-${plone_version}.tar.gz
+#end if
+
+#if not $zope2_install
+[zope2]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.zope2install
+recipe = plone.recipe.zope2install
+fake-zope-eggs = true
+#if $tarballs
+url = \${plone:zope2-url}
+#end if
+#if $z29tarballs
+url = http://www.zope.org/Products/Zope/${zope2_version}/Zope-${zope2_version}-final.tgz
+#end if
+#if $eggifiedplone
+url = \${versions:zope2-url}
+#end if
+#end if
+
+\# Use this section to download additional old-style products.
+\# List any number of URLs for product tarballs under URLs (separate
+\# with whitespace, or break over several lines, with subsequent lines
+\# indented). If any archives contain several products inside a top-level
+\# directory, list the archive file name (i.e. the last part of the URL,
+\# normally with a .tar.gz suffix or similar) under 'nested-packages'.
+\# If any archives extract to a product directory with a version suffix, list
+\# the archive name under 'version-suffix-packages'.
+[productdistros]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.distros
+recipe = plone.recipe.distros
+urls =
+nested-packages =
+version-suffix-packages =
+
+[instance]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.zope2instance
+recipe = plone.recipe.zope2instance
+#if $zope2_install
+#if not $eggifiedzope
+zope2-location = ${zope2_install}
+#end if
+#else
+zope2-location = \${zope2:location}
+#end if
+user = ${zope_user}:${zope_password}
+http-address = ${http_port}
+#if $debug_mode == 'on'
+debug-mode = on
+#else
+\#debug-mode = on
+#end if
+#if $verbose_security == 'on'
+verbose-security = on
+#else
+\#verbose-security = on
+#end if
+#if $eggifiedzope
+blob-storage = var/blobstorage
+#end if
+\# If you want Zope to know about any additional eggs, list them here.
+\# This should include any development eggs you listed in develop-eggs above,
+\# e.g. eggs = Plone my.package
+eggs =
+#if $eggifiedzope
+ Zope2
+#end if
+#if $eggifiedplone
+ Plone
+ \${buildout:eggs}
+#end if
+#if $tarballs
+ \${buildout:eggs}
+ \${plone:eggs}
+#end if
+#if $z29tarballs
+ \${buildout:eggs}
+#end if
+#if $eggifiedzope
+environment-vars =
+ zope_i18n_compile_mo_files true
+#end if
+
+\# If you want to register ZCML slugs for any packages, list them here.
+\# e.g. zcml = my.package my.other.package
+zcml =
+
+products =
+ \${buildout:directory}/products
+ \${productdistros:location}
+#if $tarballs
+#if not $plone_products_install
+ \${plone:products}
+#else
+ ${plone_products_install}
+#end if
+#end if
+#if $z29tarballs
+#if not $plone_products_install
+ \${plone:location}
+#else
+ ${plone_products_install}
+#end if
+#end if
+
+[zopepy]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/zc.recipe.egg
+recipe = zc.recipe.egg
+eggs = \${instance:eggs}
+interpreter = zopepy
+#if not $eggifiedzope
+#if $zope2_install
+extra-paths = ${zope2_install}/lib/python
+#else
+extra-paths = \${zope2:location}/lib/python
+#end if
+#end if
+scripts = zopepy
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/products/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/products/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/products/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Old-style Zope products you are developing can be added here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_buildout/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.pt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.pt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.pt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+<dl class="portlet portlet${portlet_type_name}"
+ i18n:domain="${dotted_name}">
+
+ <dt class="portletHeader">
+ <span class="portletTopLeft"></span>
+ Header
+ <span class="portletTopRight"></span>
+ </dt>
+
+ <dd class="portletItem odd">
+ Body text
+ </dd>
+
+ <dd class="portletFooter">
+ <span class="portletBottomLeft"></span>
+ Footer
+ <span class="portletBottomRight"></span>
+ </dd>
+
+</dl>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/+portlet_filename+.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,110 @@
+from zope.interface import implements
+
+from plone.portlets.interfaces import IPortletDataProvider
+from plone.app.portlets.portlets import base
+
+\# TODO: If you define any fields for the portlet configuration schema below
+\# do not forget to uncomment the following import
+\#from zope import schema
+from zope.formlib import form
+
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+
+\# TODO: If you require i18n translation for any of your schema fields below,
+\# uncomment the following to import your package MessageFactory
+\#from ${dotted_name} import ${portlet_type_name}MessageFactory as _
+
+
+class I${portlet_type_name}(IPortletDataProvider):
+ """A portlet
+
+ It inherits from IPortletDataProvider because for this portlet, the
+ data that is being rendered and the portlet assignment itself are the
+ same.
+ """
+
+ # TODO: Add any zope.schema fields here to capture portlet configuration
+ # information. Alternatively, if there are no settings, leave this as an
+ # empty interface - see also notes around the add form and edit form
+ # below.
+
+ # some_field = schema.TextLine(title=_(u"Some field"),
+ # description=_(u"A field to use"),
+ # required=True)
+
+
+class Assignment(base.Assignment):
+ """Portlet assignment.
+
+ This is what is actually managed through the portlets UI and associated
+ with columns.
+ """
+
+ implements(I${portlet_type_name})
+
+ # TODO: Set default values for the configurable parameters here
+
+ # some_field = u""
+
+ # TODO: Add keyword parameters for configurable parameters here
+ # def __init__(self, some_field=u""):
+ # self.some_field = some_field
+
+ def __init__(self):
+ pass
+
+ @property
+ def title(self):
+ """This property is used to give the title of the portlet in the
+ "manage portlets" screen.
+ """
+ return "${portlet_name}"
+
+
+class Renderer(base.Renderer):
+ """Portlet renderer.
+
+ This is registered in configure.zcml. The referenced page template is
+ rendered, and the implicit variable 'view' will refer to an instance
+ of this class. Other methods can be added and referenced in the template.
+ """
+
+ render = ViewPageTemplateFile('${portlet_filename}.pt')
+
+
+class AddForm(base.AddForm):
+ """Portlet add form.
+
+ This is registered in configure.zcml. The form_fields variable tells
+ zope.formlib which fields to display. The create() method actually
+ constructs the assignment that is being added.
+ """
+ form_fields = form.Fields(I${portlet_type_name})
+
+ def create(self, data):
+ return Assignment(**data)
+
+
+# NOTE: If this portlet does not have any configurable parameters, you
+# can use the next AddForm implementation instead of the previous.
+
+# class AddForm(base.NullAddForm):
+# """Portlet add form.
+# """
+#
+# def create(self):
+# return Assignment()
+
+
+# NOTE: If this portlet does not have any configurable parameters, you
+# can remove the EditForm class definition and delete the editview
+# attribute from the <plone:portlet /> registration in configure.zcml
+
+
+class EditForm(base.EditForm):
+ """Portlet edit form.
+
+ This is registered with configure.zcml. The form_fields variable tells
+ zope.formlib which fields to display.
+ """
+ form_fields = form.Fields(I${portlet_type_name})
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+from zope.i18nmessageid import MessageFactory
+${portlet_type_name}MessageFactory = MessageFactory('${project}')
+
+#if str($zope2product) == 'True'
+
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,38 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+ xmlns:plone="http://namespaces.plone.org/plone"
+ i18n_domain="${dotted_name}">
+
+#if str($zope2product) == 'True'
+ <five:registerPackage package="." initialize=".initialize" />
+
+#end if
+ <genericsetup:registerProfile
+ name="default"
+ title="${portlet_name}"
+ directory="profiles/default"
+ description="${description}"
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+
+ <!-- Register the portlet -->
+
+ <!-- If the portlet has no configurable parameters, you can remove
+ the EditForm declaration in ${portlet_filename}.py and delete
+ the 'editview' attribute from this statement.
+ -->
+
+ <plone:portlet
+ name="${dotted_name}.${portlet_type_name}"
+ interface=".${portlet_filename}.I${portlet_type_name}"
+ assignment=".${portlet_filename}.Assignment"
+ view_permission="zope2.View"
+ edit_permission="cmf.ManagePortal"
+ renderer=".${portlet_filename}.Renderer"
+ addview=".${portlet_filename}.AddForm"
+ editview=".${portlet_filename}.EditForm"
+ />
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/metadata.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/metadata.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/metadata.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<metadata>
+ <version>1000</version>
+</metadata>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/portlets.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/portlets.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/profiles/default/portlets.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<portlets>
+
+ <!-- Portlet type registrations -->
+
+ <portlet
+ addview="${namespace_package}.${namespace_package2}.${package}.${portlet_type_name}"
+ title="${portlet_name}"
+ description="${description}"
+ />
+
+</portlets>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/base.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/base.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/base.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,45 @@
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+
+from Testing import ZopeTestCase as ztc
+
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import onsetup
+
+
+ at onsetup
+def setup_product():
+ """Set up additional products and ZCML required to test this product.
+
+ The @onsetup decorator causes the execution of this body to be deferred
+ until the setup of the Plone site testing layer.
+ """
+
+ # Load the ZCML configuration for this package and its dependencies
+
+ fiveconfigure.debug_mode = True
+ import ${dotted_name}
+ zcml.load_config('configure.zcml', ${dotted_name})
+ fiveconfigure.debug_mode = False
+
+ # We need to tell the testing framework that these products
+ # should be available. This can't happen until after we have loaded
+ # the ZCML.
+
+ ztc.installPackage('${dotted_name}')
+
+# The order here is important: We first call the deferred function and then
+# let PloneTestCase install it during Plone site setup
+
+setup_product()
+ptc.setupPloneSite(products=['${dotted_name}'])
+
+
+class TestCase(ptc.PloneTestCase):
+ """Base class used for test cases
+ """
+
+
+class FunctionalTestCase(ptc.FunctionalTestCase):
+ """Test case class used for functional (doc-)tests
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/test_portlet.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/test_portlet.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/tests/test_portlet.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,112 @@
+from zope.component import getUtility, getMultiAdapter
+
+from plone.portlets.interfaces import IPortletType
+from plone.portlets.interfaces import IPortletManager
+from plone.portlets.interfaces import IPortletAssignment
+from plone.portlets.interfaces import IPortletDataProvider
+from plone.portlets.interfaces import IPortletRenderer
+
+from plone.app.portlets.storage import PortletAssignmentMapping
+
+from ${dotted_name} import ${portlet_filename}
+
+from ${dotted_name}.tests.base import TestCase
+
+
+class TestPortlet(TestCase):
+
+ def afterSetUp(self):
+ self.setRoles(('Manager', ))
+
+ def test_portlet_type_registered(self):
+ portlet = getUtility(
+ IPortletType,
+ name='${dotted_name}.${portlet_type_name}')
+ self.assertEquals(portlet.addview,
+ '${dotted_name}.${portlet_type_name}')
+
+ def test_interfaces(self):
+ # TODO: Pass any keyword arguments to the Assignment constructor
+ portlet = ${portlet_filename}.Assignment()
+ self.failUnless(IPortletAssignment.providedBy(portlet))
+ self.failUnless(IPortletDataProvider.providedBy(portlet.data))
+
+ def test_invoke_add_view(self):
+ portlet = getUtility(
+ IPortletType,
+ name='${dotted_name}.${portlet_type_name}')
+ mapping = self.portal.restrictedTraverse(
+ '++contextportlets++plone.leftcolumn')
+ for m in mapping.keys():
+ del mapping[m]
+ addview = mapping.restrictedTraverse('+/' + portlet.addview)
+
+ # TODO: Pass a dictionary containing dummy form inputs from the add
+ # form.
+ # Note: if the portlet has a NullAddForm, simply call
+ # addview() instead of the next line.
+ addview.createAndAdd(data={})
+
+ self.assertEquals(len(mapping), 1)
+ self.failUnless(isinstance(mapping.values()[0],
+ ${portlet_filename}.Assignment))
+
+ def test_invoke_edit_view(self):
+ # NOTE: This test can be removed if the portlet has no edit form
+ mapping = PortletAssignmentMapping()
+ request = self.folder.REQUEST
+
+ mapping['foo'] = ${portlet_filename}.Assignment()
+ editview = getMultiAdapter((mapping['foo'], request), name='edit')
+ self.failUnless(isinstance(editview, ${portlet_filename}.EditForm))
+
+ def test_obtain_renderer(self):
+ context = self.folder
+ request = self.folder.REQUEST
+ view = self.folder.restrictedTraverse('@@plone')
+ manager = getUtility(IPortletManager, name='plone.rightcolumn',
+ context=self.portal)
+
+ # TODO: Pass any keyword arguments to the Assignment constructor
+ assignment = ${portlet_filename}.Assignment()
+
+ renderer = getMultiAdapter(
+ (context, request, view, manager, assignment), IPortletRenderer)
+ self.failUnless(isinstance(renderer, ${portlet_filename}.Renderer))
+
+
+class TestRenderer(TestCase):
+
+ def afterSetUp(self):
+ self.setRoles(('Manager', ))
+
+ def renderer(self, context=None, request=None, view=None, manager=None,
+ assignment=None):
+ context = context or self.folder
+ request = request or self.folder.REQUEST
+ view = view or self.folder.restrictedTraverse('@@plone')
+ manager = manager or getUtility(
+ IPortletManager, name='plone.rightcolumn', context=self.portal)
+
+ # TODO: Pass any default keyword arguments to the Assignment
+ # constructor.
+ assignment = assignment or ${portlet_filename}.Assignment()
+ return getMultiAdapter((context, request, view, manager, assignment),
+ IPortletRenderer)
+
+ def test_render(self):
+ # TODO: Pass any keyword arguments to the Assignment constructor.
+ r = self.renderer(context=self.portal,
+ assignment=${portlet_filename}.Assignment())
+ r = r.__of__(self.folder)
+ r.update()
+ #output = r.render()
+ # TODO: Test output
+
+
+def test_suite():
+ from unittest import TestSuite, makeSuite
+ suite = TestSuite()
+ suite.addTest(makeSuite(TestPortlet))
+ suite.addTest(makeSuite(TestRenderer))
+ return suite
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+${version}
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/INSTALL.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/INSTALL.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/INSTALL.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,40 @@
+#set $full_package_name = "%s.%s.%s" % ($namespace_package, $namespace_package2, $package)
+${project} Installation
+=======================
+
+ * When you're reading this you have probably already run
+ ``easy_install ${project}``. Find out how to install setuptools
+ (and EasyInstall) here:
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+ * Create a file called ``${project}-configure.zcml`` in the
+ ``/path/to/instance/etc/package-includes`` directory. The file
+ should only contain this::
+
+ <include package="${full_package_name}" />
+
+Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance
+recipe to manage your project, you can do this:
+
+ * Add ``${project}`` to the list of eggs to install, e.g.:
+
+ [buildout]
+ ...
+ eggs =
+ ...
+ ${project}
+
+ * Tell the plone.recipe.zope2instance recipe to install a ZCML slug:
+
+ [instance]
+ recipe = plone.recipe.zope2instance
+ ...
+ zcml =
+ ${full_package_name}
+
+ * Re-run buildout, e.g. with:
+
+ $ ./bin/buildout
+
+You can skip the ZCML slug if you are going to explicitly include the package
+from another package's configure.zcml file.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.GPL
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.GPL (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.GPL 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/docs/LICENSE.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+ ${project} is copyright $author
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_portlet/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,36 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Framework :: Plone",
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,67 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($include_doc) == 'True'
+ <!-- '$skinname' Zope 3 browser layer
+ Register views, viewlets and resources for this layer to make sure
+ they only apply to the '${skinname}' theme.
+ You can also use this layer to override default Plone browser views
+ and viewlets only within the '${skinname}' theme.
+ -->
+#else
+ <!-- '$skinname' Zope 3 browser layer -->
+#end if
+ <interface
+ interface=".interfaces.IThemeSpecific"
+ type="zope.publisher.interfaces.browser.IBrowserSkinType"
+ name="$skinname"
+ />
+
+ <!-- Viewlets registration -->
+#if str($include_doc) == 'True'
+ <!-- EXAMPLE (UNCOMMENT TO MAKE AVAILABLE):
+ <browser:viewlet
+ name="${namespace_package}.someviewlet"
+ manager="plone.app.layout.viewlets.interfaces.IPortalFooter"
+ class=".viewlets.MyViewlet"
+ layer=".interfaces.IThemeSpecific"
+ permission="zope2.View"
+ />
+ -->
+
+#end if
+ <!-- Zope 3 browser resources -->
+
+#if str($include_doc) == 'True'
+ <!-- Resource directory for images
+ See ${namespace_package}/${package}/browser/images/README.txt
+ for more information about registering images as Zope 3 browser
+ resources.
+ -->
+#else
+ <!-- Resource directory for images -->
+#end if
+ <browser:resourceDirectory
+ name="${namespace_package}.${package}.images"
+ directory="images"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+#if str($include_doc) == 'True'
+ <!-- Resource directory for stylesheets
+ See ${namespace_package}/${package}/browser/stylesheets/README.txt
+ for more information about registering stylesheets as Zope 3 browser
+ resources.
+ -->
+#else
+ <!-- Resource directory for stylesheets -->
+#end if
+ <browser:resourceDirectory
+ name="${namespace_package}.${package}.stylesheets"
+ directory="stylesheets"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/images/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,56 @@
+README for the 'browser/images/' directory
+==========================================
+
+This folder is a Zope 3 Resource Directory acting as a repository for images.
+
+Its declaration is located in 'browser/configure.zcml':
+
+ <!-- Resource directory for images -->
+ <browser:resourceDirectory
+ name="${namespace_package}.${package}.images"
+ directory="images"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+An image placed in this directory (e.g. 'logo.png') can be accessed from
+this relative URL:
+
+ "++resource++${namespace_package}.${package}.images/logo.png"
+
+Note that it might be better to register each of these resources separately if
+you want them to be overridable from zcml directives.
+
+The only way to override a resource in a resource directory is to override the
+entire directory (all elements have to be copied over).
+
+A Zope 3 browser resource declared like this in 'browser/configure.zcml':
+
+ <browser:resource
+ name="logo.png"
+ file="images/logo.png"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+can be accessed from this relative URL:
+
+ "++resource++logo.png"
+
+Notes
+-----
+
+* Whatever the way they are declared (in bulk inside a resource directory or
+ as separate resources), images registered as Zope 3 browser resources don't
+ have all the attributes that Zope 2 image objects have (i.e. the 'title'
+ property and the 'tag()' and 'get_size()' methods).
+ This means that if you want the html tag of your image to be auto-generated
+ (this is the case by default for the portal logo), you should store it in a
+ directory that is located in the 'skins/' folder of your package, registered
+ as a File System Directory View in the 'portal_skins' tool, and added to the
+ layers of your skin.
+
+* Customizing/overriding images that are originally accessed from the
+ 'portal_skins' tool (e.g. Plone default logo and icons) can be done inside
+ that tool only. There is no known way to do it with Zope 3 browser
+ resources.
+ Vice versa, there is no known (easy) way to override a Zope 3 browser
+ resource from a skin layer in 'portal_skins'.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/interfaces.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/interfaces.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/interfaces.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,11 @@
+from plone.theme.interfaces import IDefaultPloneLayer
+
+
+class IThemeSpecific(IDefaultPloneLayer):
+ """Marker interface that defines a Zope 3 browser layer.
+#if str($include_doc) == 'True'
+ If you need to register a viewlet only for the
+ "$skinname" theme, this interface must be its layer
+ (in $package/viewlets/configure.zcml).
+#end if
+ """
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,61 @@
+README for the 'browser/stylesheets/' directory
+===============================================
+
+This folder is a Zope 3 Resource Directory acting as a repository for
+stylesheets.
+
+Its declaration is located in 'browser/configure.zcml':
+
+ <!-- Resource directory for stylesheets -->
+ <browser:resourceDirectory
+ name="${namespace_package}.${package}.stylesheets"
+ directory="stylesheets"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+A stylesheet placed in this directory (e.g. 'main.css') can be accessed from
+this relative URL:
+
+ "++resource++${namespace_package}.${package}.stylesheets/main.css"
+
+Note that it might be better to register each of these resources separately if
+you want them to be overridable from zcml directives.
+
+The only way to override a resource in a resource directory is to override the
+entire directory (all elements have to be copied over).
+
+A Zope 3 browser resource declared like this in 'browser/configure.zcml':
+
+ <browser:resource
+ name="main.css"
+ file="stylesheets/main.css"
+ layer=".interfaces.IThemeSpecific"
+ />
+
+can be accessed from this relative URL:
+
+ "++resource++main.css"
+
+Notes
+-----
+
+* Stylesheets registered as Zope 3 resources might be flagged as not found in
+ the 'portal_css' tool if the layer they are registered for doesn't match the
+ default skin set in 'portal_skins'.
+ This can be confusing but it must be considered as a minor bug in the CSS
+ registry instead of a lack in the way Zope 3 resources are handled in
+ Zope 2.
+
+* There might be a way to interpret DTML from a Zope 3 resource view.
+ Although, if you need to use DTML for setting values in a stylesheet (the
+ same way as in default Plone stylesheets where values are read from
+ 'base_properties'), it is much easier to store it in a directory that is
+ located in the 'skins/' folder of your package, registered as a File System
+ Directory View in the 'portal_skins' tool, and added to the layers of your
+ skin.
+
+* Customizing/overriding stylesheets that are originally accessed from the
+ 'portal_skins' tool (e.g. Plone default stylesheets) can be done inside that
+ tool only. There is no known way to do it with Zope 3 browser resources.
+ Vice versa, there is no known way to override a Zope 3 browser resource from
+ a skin layer in 'portal_skins'.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/main.css_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/main.css_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/stylesheets/main.css_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+/* Stylesheet for the '$skinname' Plone theme */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlet.pt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlet.pt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlet.pt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,14 @@
+#if str($include_doc) == 'True'
+<!--
+ 'view' refers to the MyViewlet class in viewlets.py
+ If you do not need anything fancy where python code might help,
+ like just a viewlet that displays '<h1>Hello World</h1>',
+ then you can remove anything else from this page template, remove
+ viewlets.py and change the viewlet registration in configure.zcml:
+ replace
+ class=".viewlets.MyViewlet"
+ with
+ template="viewlet.pt"
+ -->
+#end if
+<div tal:content="view/computed_value|nothing"/>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlets.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlets.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/browser/viewlets.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,27 @@
+#if str($include_doc) == 'True'
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from plone.app.layout.viewlets.common import ViewletBase
+
+\# Sample code for a basic viewlet (In order to use it, you'll have to):
+\# - Un-comment the following useable piece of code (viewlet python class).
+\# - Rename the viewlet template file ('browser/viewlet.pt') and edit the
+\# following python code accordingly.
+\# - Edit the class and template to make them suit your needs.
+\# - Make sure your viewlet is correctly registered in 'browser/configure.zcml'.
+\# - If you need it to appear in a specific order inside its viewlet manager,
+\# edit 'profiles/default/viewlets.xml' accordingly.
+\# - Restart Zope.
+\# - If you edited any file in 'profiles/default/', reinstall your package.
+\# - Once you're happy with your viewlet implementation, remove any related
+\# (unwanted) inline documentation ;-p
+
+\#class MyViewlet(ViewletBase):
+\# render = ViewPageTemplateFile('viewlet.pt')
+\##
+
+\# def update(self):
+\# self.computed_value = 'any output'
+#else
+\#from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+\#from plone.app.layout.viewlets.common import ViewletBase
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:cmf="http://namespaces.zope.org/cmf"
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($zope2product) == 'True'
+ <five:registerPackage package="." initialize=".initialize" />
+#end if
+ <include package=".browser" />
+ <include file="skins.zcml" />
+ <include file="profiles.zcml" />
+ <i18n:registerTranslations directory="locales" />
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/locales/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,11 @@
+This directory will be the home for internationalizations for your theme
+package. For more information on internationalization please consult the
+following sources:
+
+http://plone.org/documentation/kb/product-skin-localization
+http://plone.org/documentation/kb/i18n-for-developers
+http://www.mattdorn.com/content/plone-i18n-a-brief-tutorial/
+http://grok.zope.org/documentation/how-to/how-to-internationalize-your-application
+http://maurits.vanrees.org/weblog/archive/2007/09/i18n-locales-and-plone-3.0
+http://n2.nabble.com/Recipe-for-overriding-translations-td3045492ef221724.html
+http://dev.plone.org/plone/wiki/TranslationGuidelines
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/+namespace_package+.+package+_various.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/+namespace_package+.+package+_various.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/+namespace_package+.+package+_various.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This file is used as a marker in setuphandlers.py.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/cssregistry.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_css tool. -->
+
+#end if
+<object name="portal_css">
+
+#if str($include_doc) == 'True'
+ <!-- Stylesheets that will be registered with the portal_css tool are defined
+ here. You can also specify values for existing resources if you need to
+ modify some of their properties.
+ Stylesheet elements accept these parameters:
+ - 'id' (required): it must respect the name of the css or DTML file
+ (case sensitive). '.dtml' suffixes must be ignored.
+ - 'expression' (optional - default: ''): a tal condition.
+ - 'media' (optional - default: ''): possible values: 'screen', 'print',
+ 'projection', 'handheld'...
+ - 'rel' (optional - default: 'stylesheet')
+ - 'title' (optional - default: '')
+ - 'rendering' (optional - default: 'import'): 'import', 'link' or
+ 'inline'.
+ - 'enabled' (optional - default: True): boolean
+ - 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+ - 'insert_before', 'insert_after' (optional - default: '') resource id
+ See registerStylesheet() arguments in
+ ResourceRegistries/tools/CSSRegistry.py for the latest list of all
+ available keys and default values.
+ -->
+#end if
+ <stylesheet title=""
+ id="++resource++${namespace_package}.${package}.stylesheets/main.css"
+ media="screen" rel="stylesheet" rendering="import"
+ cacheable="True" compression="safe" cookable="True"
+ enabled="1" expression=""/>
+
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/jsregistry.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_javascripts tool.
+ -->
+
+#end if
+<object name="portal_javascripts">
+
+#if str($include_doc) == 'True'
+ <!-- Javascript files that will be registered with the
+ portal_javascripts tool are defined here. You can also specify values
+ for existing resources if you need to modify some of their properties.
+ Javascript elements accept these parameters:
+ - 'id' (required): same rules as for stylesheets (see
+ 'cssregistry.xml').
+ - 'expression' (optional - default: ''): a tal condition.
+ - 'inline' (optional - default: False)
+ - 'enabled' (optional - default: True): boolean
+ - 'cookable' (optional - default: True): boolean (aka 'merging allowed')
+ See registerScript() arguments in ResourceRegistries/tools/JSRegistry.py
+ for the latest list of all available keys and default values.
+ -->
+<!-- EXAMPLE (UNCOMMENT TO MAKE AVAILABLE):
+ <javascript
+ id="++resource++${namespace_package}.${package}.javascripts/something.js"
+ cacheable="False" compression="safe" cookable="False"
+ enabled="True" expression="" inline="False"/>
+-->
+
+#end if
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/metadata.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<metadata>
+ <version>1000</version>
+</metadata>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/skins.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration for the portal_skins tool -->
+
+<!-- Change the value of these parameters to modify portal_skins behavior:
+ - allow_any: change it to True if you want users to be able to select the
+ skin to use from their personal preferences management page. In the
+ ZMI, this value is known as 'Skin flexibility'.
+ - cookie_persistence: change it to True if you want to make the skin cookie
+ persist indefinitely. In the ZMI, this value is known as 'Skin Cookie
+ persistence'.
+ -->
+#end if
+<object name="portal_skins" allow_any="False" cookie_persistence="False"
+ default_skin="$skinname">
+
+#if str($include_doc) == 'True'
+ <!-- This list registers the folders that are stored in the skins directory
+ of your product (on the filesystem) as Filesystem Directory Views within
+ the portal_skins tool, so that they become usable as skin layers.
+ -->
+#end if
+ <object name="${namespace_package}_${package}_custom_images"
+ meta_type="Filesystem Directory View"
+ directory="${namespace_package}.${package}:skins/${namespace_package}_${package}_custom_images"/>
+ <object name="${namespace_package}_${package}_custom_templates"
+ meta_type="Filesystem Directory View"
+ directory="${namespace_package}.${package}:skins/${namespace_package}_${package}_custom_templates"/>
+ <object name="${namespace_package}_${package}_styles"
+ meta_type="Filesystem Directory View"
+ directory="${namespace_package}.${package}:skins/${namespace_package}_${package}_styles"/>
+
+#if str($include_doc) == 'True'
+ <!-- A skin-path in this file corresponds to a Skin Selection in the
+ 'Properties' tab of the portal_skins tool, in the ZMI.
+ You can define for each new skin path the layers that it holds. A new
+ skin can be based on another existing one by using the 'based-on'
+ attribute.
+ The definition of a layer accepts these parameters:
+ - name: quite self explanatory, the name of the layer.
+ - insert-before: name of the layer before which it must be added.
+ - insert-after: name of the layer after which it must be added.
+ Note: insert-before (and -after) accepts the value "*" which means
+ "all".
+ -->
+#end if
+ <skin-path name="$skinname" based-on="$skinbase">
+ <layer name="${namespace_package}_${package}_custom_images"
+ insert-after="custom"/>
+ <layer name="${namespace_package}_${package}_custom_templates"
+ insert-after="${namespace_package}_${package}_custom_images"/>
+ <layer name="${namespace_package}_${package}_styles"
+ insert-after="${namespace_package}_${package}_custom_templates"/>
+ </skin-path>
+
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/viewlets.xml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/viewlets.xml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles/default/viewlets.xml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+#if str($include_doc) == 'True'
+<!-- This file holds the setup configuration of the viewlet managers
+ for the "$skinname" skin.
+ -->
+
+#end if
+<object>
+
+#if str($include_doc) == 'True'
+ <!-- Viewlets keep the same ordering than the default skin ('Plone Default'
+ out of the box).
+ You can specify skinname="*" if you want changes apply for all skins.
+ Using "True"" for the 'make-default' parameter will make the 'skinname'
+ value set as default skinname. Means the name of the skin that would be
+ used in case the viewlets ordering was not specified for the currently
+ used skin.
+ The 'based-on' attribute lets you inherit the viewlets ordering from an
+ existing skin.
+ -->
+ <order manager="plone.portalfooter" skinname="$skinname"
+ based-on="Plone Default">
+ <!-- The definition of a viewlet accepts these parameters:
+ - name: quite self explanatory, the name of the viewlet.
+ - insert-before: name of the viewlet before which it must be added or
+ moved.
+ - insert-after: name of the viewlet after which it must be added
+ or moved.
+ - remove: supported but rarely needed, removes the viewlet from the
+ ordering list (doesn't mean that it hides the viewlet).
+ Note: insert-before and -after accept the value "*" which means
+ "all".
+ -->
+<!-- EXAMPLE (UNCOMMENT TO MAKE AVAILABLE):
+ <viewlet name="${namespace_package}.someviewlet"
+ insert-before="*" />
+-->
+ </order>
+
+ <hidden manager="plone.portalheader" skinname="$skinname">
+<!-- EXAMPLE (UNCOMMENT TO MAKE AVAILABLE):
+ <viewlet name="plone.global_sections" />
+-->
+ </hidden>
+
+#end if
+</object>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/profiles.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,24 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+ i18n_domain="${namespace_package}.${package}">
+
+#if str($add_profile) == 'True'
+ <genericsetup:registerProfile
+ name="default"
+ title="$skinname"
+ directory="profiles/default"
+ description='Extension profile for the "${skinname}" Plone theme.'
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+
+ <genericsetup:importStep
+ name="${namespace_package}.${package}.various"
+ title="${skinname}: miscellaneous import steps"
+ description="Various import steps that are not handled by GS import/export handlers."
+ handler="${namespace_package}.${package}.setuphandlers.setupVarious">
+ <depends name="skins"/>
+ </genericsetup:importStep>
+#end if
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/setuphandlers.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/setuphandlers.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/setuphandlers.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,11 @@
+def setupVarious(context):
+
+ # Ordinarily, GenericSetup handlers check for the existence of XML files.
+ # Here, we are not parsing an XML file, but we use this text file as a
+ # flag to check that we actually meant for this import step to be run.
+ # The file is found in profiles/default.
+
+ if context.readDataFile('${namespace_package}.${package}_various.txt') is None:
+ return
+
+ # Add additional setup code here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_images/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+This folder holds Filesystem Image files that are registered for the
+'${skinname}' Skin Selection only.
+They act as replacement for the default Plone (or 3rd party products) ones.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_custom_templates/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+This folder holds Filesystem Page Template files that are registered for the
+'${skinname}' Skin Selection only.
+They act as replacement for the default Plone (or 3rd party products) ones.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/CONTENT.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/CONTENT.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/CONTENT.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+This folder holds stylesheet files that are registered for the
+'${skinname}' Skin Selection only.
+
+It is a repository for customizations of the default Plone stylesheets,
+as well as for package specific stylesheets.
+
+
+Note
+ Stylesheet files that don't use DTML can also stored in the 'browser'
+ folder and accessed as Zope 3 file resources.
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml file shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base_properties.props_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base_properties.props_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/base_properties.props_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+title:string=$skinname's color, font, logo and border defaults
+
+plone_skin:string=$skinname
+
+logoName:string=logo.jpg
+
+fontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+fontBaseSize:string=69%
+fontColor:string=Black
+fontSmallSize:string=85%
+
+backgroundColor:string=White
+
+linkColor:string=#436976
+linkActiveColor:string=Red
+linkVisitedColor:string=Purple
+
+borderWidth:string=1px
+borderStyle:string=solid
+borderStyleAnnotations:string=dashed
+
+globalBorderColor:string=#8cacbb
+globalBackgroundColor:string=#dee7ec
+globalFontColor:string=#436976
+
+headingFontFamily:string="Lucida Grande", Verdana, Lucida, Helvetica, Arial, sans-serif
+
+contentViewBorderColor:string=#74ae0b
+contentViewBackgroundColor:string=#cde2a7
+contentViewFontColor:string=#578308
+
+inputFontColor:string=Black
+
+textTransform:string=lowercase
+
+evenRowBackgroundColor:string=#eef3f5
+oddRowBackgroundColor:string=transparent
+
+notifyBorderColor:string=#ffa500
+notifyBackgroundColor:string=#ffce7b
+
+discreetColor:string=#76797c
+helpBackgroundColor:string=#ffffe1
+
+portalMinWidth:string=70em
+columnOneWidth:string=16em
+columnTwoWidth:string=16em
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/portlets.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/portlets.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/portlets.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml file shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/public.css.dtml
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/public.css.dtml (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins/+namespace_package+_+package+_styles/public.css.dtml 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+/*
+ This file is based on the ploneCustom.css.dtml file shipped with Plone.
+
+ <dtml-with base_properties> (do not remove this)
+ <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either)
+*/
+
+/* YOUR CSS RULES START HERE */
+
+
+
+/* YOUR CSS RULES STOP HERE */
+
+/* </dtml-with> */
+
+/* Latest version of the documentation on pre-defined properties from Plone
+ can be found in CMFPlone/skins/plone_styles/ploneCustom.css.dtml */
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/skins.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,18 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:cmf="http://namespaces.zope.org/cmf"
+ i18n_domain="${namespace_package}.${package}">
+
+ <!-- File System Directory Views registration -->
+ <cmf:registerDirectory name="${namespace_package}_${package}_custom_images"/>
+ <cmf:registerDirectory name="${namespace_package}_${package}_custom_templates"/>
+ <cmf:registerDirectory name="${namespace_package}_${package}_styles"/>
+
+#if str($include_doc) == 'True'
+ <!-- Note: This could also be done for all folders at once
+ by replacing the previous lines with this one:
+ <cmf:registerDirectory name="skins" directory="skins" recursive="True" />
+ -->
+
+#end if
+</configure>
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/version.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/version.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+namespace_package+/+package+/version.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+${version}
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+project+-configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+project+-configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/+project+-configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+<include package="${namespace_package}.${package}" />
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/MANIFEST.in_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/MANIFEST.in_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone3_theme/MANIFEST.in_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+recursive-include ${namespace_package} *
+global-exclude *pyc
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,173 @@
+================================
+Plone 4 buildout for developers
+================================
+
+.. contents ::
+
+Introduction
+------------
+
+`Buildout <http://www.buildout.org>`_ is a tool which automatically downloads, installs and configures Python software.
+Plone developers prefer uses buildout based installation method - it makes it easy to work with source code and developing your own Plone add-ons.
+
+For production site installations please use `standard Plone installer <http://plone.org/download>`_.
+
+Prerequisitements
+-----------------
+
+What you need in order to use developer buildout with Plone 4
+
+* Experience using command line tools
+
+* Experience using a text editor to work with configuration files (``buildout.cfg``)
+
+* GCC compiler suite to build native Python extensions (Zope contains C code for optimized parts)
+
+* Python 2.6 (other versions are *not* ok for Plone 4)
+
+* Python Imaging Library installed for your Python interpreter (more below)
+
+* Python `Distribute <http://pypi.python.org/pypi/distribute>`_ installation tool, provided by your operating system
+ or installed by hand
+
+Read below from operating system specific instructions how to install these dependencies.
+
+Features
+--------
+
+This buildout provides
+
+* Zope start up scripts (one instance)
+
+* ``paster`` command for creating Plone add-ons (different from system-wide installation)
+
+* `test <http://plone.org/documentation/manual/plone-community-developer-documentation/testing-and-debugging/unit-testing>`_ command for running automatic test suites
+
+* `i18ndude <http://pypi.python.org/pypi/i18ndude>`_ for managing text string translations in Python source code
+
+* `omelette <http://pypi.python.org/pypi/collective.recipe.omelette>`_ buildout recipe which makes Python egg source code more browseable by using symlinks
+
+* `mr.developer <http://pypi.python.org/pypi/mr.developer>`_ command for managing source code checkouts and updates with buildout repeatable manner
+
+* `collective.developermanual <http://plone.org/documentation/manual/plone-community-developer-documentation>`_ - community managed developer manual for Plone
+ in source code form, ready for contributions
+
+Creating Plone 4 buildout installation
+------------------------------------------
+
+Install ZopeSkel template package for your system-wide Python using Distribute::
+
+ easy_install ZopeSkel
+
+... or upgrade existing installation::
+
+ easy_install -U ZopeSkel
+
+You probably got here by running something like (replace *myplonefoldername* with the target folder where you want to Plone to be installed)::
+
+ zopeskel plone4_buildout myplonefoldername
+
+Now, you need to run (please see remarks regarding your operating system below)::
+
+ python bootstrap.py
+
+This will create ``bin`` folder and ``bin/buildout`` script. If you any time want to change Python interpreter
+associated with buildout, or you need to update ``buildout`` script itself to newer version please rerun ``bootsrap.py``.
+
+Now you can run buildout script which will download all Python packages
+(.egg files) and create ``parts/`` and ``var/`` folder structure ::
+
+ bin/buildout
+
+If this succesfully completes you can start buildout in foreground mode (Press *CTRL+C* to terminate)::
+
+ bin/instance fg
+
+Now you can login to your site
+
+ http://localhost:8080
+
+The default user is ``admin`` with password ``admin``.
+After initial start-up admin password is stored in Data.fs databse file and value in ``buildout.cfg`` is ignored.
+Please follow `these instructions to change admin password <http://manage.plone.org/documentation/kb/changing-the-admin-password>`_.
+
+Next steps
+----------
+
+Creating your first add-on
+==========================
+
+Plone 4 buildout comes with ``bin/paster`` command for creating Plone add-ons.
+
+.. note ::
+
+ When working with Plone add-ons, use paster command from buildout bin folder, not the system wide paster command.
+
+Create theme (applies for Plone 4 also)::
+
+ bin/zopeskel plone3_theme plonetheme.mythemeid
+
+Create Archetypes based content types package::
+
+ bin/zopeskel archetype mycompanyid.content
+
+Create other Plone customizations::
+
+ bin/zopeskel plone mycompanyid.mypackageid
+
+More info
+
+* `Instructions how to use Paster command to create your own add-ons <http://collective-docs.plone.org/tutorials/paste.html>`_
+
+Managing source code checkouts with buildout
+=============================================
+
+`mr.developer buildout extension <http://pypi.python.org/pypi/mr.developer>`_ command which can be used with buildout to manage your source code repositories
+*mr.developer* makes source code checkout from multiple repositores a repeatable task.
+
+Operating system specific instructions
+-------------------------------------------
+
+Ubuntu/Debian
+==============
+
+Tested for Ubuntu 10.10.
+
+Install prerequisitements::
+
+ sudo apt-get install python2.6 python-imaging wget build-essential python2.6-dev python-setuptools
+ easy_install ZopeSkel
+
+OSX
+====
+
+Install `OSX development tools (XCode) <http://developer.apple.com/>`_ from Apple.
+
+Install `Macports <http://www.macports.org/>`_.
+
+Then the following installs dependencies::
+
+ sudo port install python26 py26-pil py26-distribute wget
+ easy_install ZopeSkel
+
+When you run ``bootstrap.py``use the following command to make sure you are using Python interpreter from Macports::
+
+ python2.6 bootstrap.py
+
+Windows
+========
+
+Microsoft Windows systems is problematic because
+it does not provide to Microsoft Visual C compiler (commercial) which is
+required to build native Python extensions.
+
+Please read
+
+* http://plone.org/documentation/kb/using-buildout-on-windows
+
+Other
+-----
+
+The orignal copy of these instructions is available at
+
+* https://svn.plone.org/svn/collective/ZopeSkel/trunk/zopeskel/templates/plone4_buildout/README.txt
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+import urllib2
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="distribute", default=False,
+ help="Use Disribute rather than Setuptools.")
+
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.version is not None:
+ VERSION = '==%s' % options.version
+else:
+ VERSION = ''
+
+# We decided to always use distribute, make sure this is the default for us
+# USE_DISTRIBUTE = options.distribute
+USE_DISTRIBUTE = True
+args = args + ['bootstrap']
+
+to_reload = False
+try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ to_reload = True
+ raise ImportError
+except ImportError:
+ ez = {}
+ if USE_DISTRIBUTE:
+ setup_url = 'http://python-distribute.org/distribute_setup.py'
+ exec urllib2.urlopen(setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+ else:
+ ez_setup_url = 'http://peak.telecommunity.com/dist/ez_setup.py'
+ exec urllib2.urlopen(ez_setup_url).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ if to_reload:
+ reload(pkg_resources)
+ else:
+ import pkg_resources
+
+
+def quote(c):
+ if sys.platform == 'win32':
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+
+if USE_DISTRIBUTE:
+ requirement = 'distribute'
+else:
+ requirement = 'setuptools'
+
+pythonpath = ws.find(pkg_resources.Requirement.parse(requirement)).location
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout' + VERSION],
+ env=dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote(sys.executable),
+ '-c', quote(cmd), '-mqNxd', quote(tmpeggs), 'zc.buildout' + VERSION,
+ dict(os.environ,
+ PYTHONPATH=pythonpath),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,102 @@
+# buildout.cfg file for Plone 4 development work
+# - for production installations please use http://plone.org/download
+#
+# Each part has more information about its recipe on PyPi
+# http://pypi.python.org/pypi
+# ... just reach by the recipe name
+[buildout]
+parts =
+ instance
+ zopepy
+ i18ndude
+ zopeskel
+ test
+\# omelette
+
+extends =
+ http://dist.plone.org/release/${plone_version}/versions.cfg
+
+\# Add additional egg download sources here. dist.plone.org contains archives
+\# of Plone packages.
+find-links =
+ http://dist.plone.org/release/${plone_version}
+ http://dist.plone.org/thirdparty
+
+extensions =
+ mr.developer
+ buildout.dumppickedversions
+ buildout.threatlevel
+
+sources = sources
+
+versions = versions
+
+\# Reference any folders where you have Python egg source code under development here
+\# e.g.: develop = src/my.package
+\# If you are using the mr.developer extension and have the source code in a
+\# repository mr.developer will handle this automatically for you
+develop =
+
+
+\# Create bin/instance command to manage Zope start up and shutdown
+[instance]
+recipe = plone.recipe.zope2instance
+user = admin:admin
+http-address = 8080
+debug-mode = off
+verbose-security = on
+blob-storage = var/blobstorage
+
+eggs =
+ Plone
+
+\# Some pre-Plone 3.3 packages may need you to register the package name here in
+\# order their configure.zcml to be run (http://plone.org/products/plone/roadmap/247)
+\# - this is never required for packages in the Products namespace (Products.*)
+zcml =
+
+
+\# zopepy commands allows you to execute Python scripts using a PYTHONPATH
+\# including all the configured eggs
+[zopepy]
+recipe = zc.recipe.egg
+eggs = \${instance:eggs}
+interpreter = zopepy
+scripts = zopepy
+
+\# create bin/i18ndude command
+[i18ndude]
+unzip = true
+recipe = zc.recipe.egg
+eggs = i18ndude
+
+\# create bin/test command
+[test]
+recipe = zc.recipe.testrunner
+defaults = ['--auto-color', '--auto-progress']
+eggs =
+ \${instance:eggs}
+
+\# create ZopeSkel command
+[zopeskel]
+unzip = true
+recipe = zc.recipe.egg
+eggs =
+ ZopeSkel
+ \${instance:eggs}
+
+\# symlinks all Python source code to parts/omelette folder when buildout is run
+\# windows users will need to install additional software for this part to build
+\# correctly. See http://pypi.python.org/pypi/collective.recipe.omelette for
+\# relevant details.
+\# [omelette]
+\# recipe = collective.recipe.omelette
+\# eggs = \${instance:eggs}
+
+\# Put your mr.developer managed source code repositories here, see
+\# http://pypi.python.org/pypi/mr.developer for details on format for this part
+[sources]
+collective.developermanual = svn http://svn.plone.org/svn/collective/collective.developermanual
+
+\# Version pindowns for new style products go here - this section extends one provided in http://dist.plone.org/release/
+[versions]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone4_buildout/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+#
+
+#if str($zope2product) == 'True'
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+#end if
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ i18n_domain="${namespace_package}.${namespace_package2}.${package}">
+
+#if str($zope2product) == 'True'
+ <five:registerPackage package="." initialize=".initialize" />
+#end if
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,54 @@
+import unittest
+
+from zope.testing import doctestunit
+from zope.component import testing
+from Testing import ZopeTestCase as ztc
+
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import PloneSite
+ptc.setupPloneSite()
+
+import ${namespace_package}.${namespace_package2}.${package}
+
+class TestCase(ptc.PloneTestCase):
+ class layer(PloneSite):
+ @classmethod
+ def setUp(cls):
+ fiveconfigure.debug_mode = True
+ zcml.load_config('configure.zcml',
+ ${namespace_package}.${namespace_package2}.${package})
+ fiveconfigure.debug_mode = False
+
+ @classmethod
+ def tearDown(cls):
+ pass
+
+
+def test_suite():
+ return unittest.TestSuite([
+
+ \# Unit tests
+ \#doctestunit.DocFileSuite(
+ \# 'README.txt', package='${namespace_package}.${namespace_package2}.${package}',
+ \# setUp=testing.setUp, tearDown=testing.tearDown),
+
+ \#doctestunit.DocTestSuite(
+ \# module='${namespace_package}.${namespace_package2}.${package}.mymodule',
+ \# setUp=testing.setUp, tearDown=testing.tearDown),
+
+
+ \# Integration tests that use PloneTestCase
+ \#ztc.ZopeDocFileSuite(
+ \# 'README.txt', package='${namespace_package}.${namespace_package2}.${package}',
+ \# test_class=TestCase),
+
+ \#ztc.FunctionalDocFileSuite(
+ \# 'browser.txt', package='${namespace_package}.${namespace_package2}.${package}',
+ \# test_class=TestCase),
+
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/+namespace_package+/+namespace_package2+/+package+/version.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+${version}
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/INSTALL.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/INSTALL.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/INSTALL.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,52 @@
+#set $full_package_name = "%s.%s.%s" % ($namespace_package, $namespace_package2, $package)
+${project} Installation
+=======================
+
+ * When you're reading this you have probably already run
+ ``easy_install ${project}``. Find out how to install setuptools
+ (and EasyInstall) here:
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+#if str($zope2product) == 'True'
+ * Get `pythonproducts`_ and install it via::
+
+ python setup.py install --home /path/to/instance
+
+ into your Zope instance.
+
+#end if
+ * Create a file called ``${project}-configure.zcml`` in the
+ ``/path/to/instance/etc/package-includes`` directory. The file
+ should only contain this::
+
+ <include package="${full_package_name}" />
+
+#if str($zope2product) == 'True'
+.. _pythonproducts: http://plone.org/products/pythonproducts
+#end if
+
+Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance
+recipe to manage your project, you can do this:
+
+ * Add ``${project}`` to the list of eggs to install, e.g.:
+
+ [buildout]
+ ...
+ eggs =
+ ...
+ ${project}
+
+ * Tell the plone.recipe.zope2instance recipe to install a ZCML slug:
+
+ [instance]
+ recipe = plone.recipe.zope2instance
+ ...
+ zcml =
+ ${full_package_name}
+
+ * Re-run buildout, e.g. with:
+
+ $ ./bin/buildout
+
+You can skip the ZCML slug if you are going to explicitly include the package
+from another package's configure.zcml file.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.GPL
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.GPL (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.GPL 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/docs/LICENSE.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+ ${project} is copyright $author
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_app/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,36 @@
+from setuptools import setup, find_packages
+import os
+
+version = ${repr($version) or "0.0"}
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=open("README.txt").read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ "Framework :: Plone",
+ "Programming Language :: Python",
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,52 @@
+Plone hosting buildout
+======================
+
+Process control
+---------------
+
+All services are controlled using the supervisord_ process manager. Supervisord
+takes care of starting all daemons, restarting them when needed and can
+optionally provide a web interface allowing for easy remote management.
+
+To start supervisord starts its daemon ``bin/supervisord``. This will
+automatically start the ZEO server, Zope and, if enabled, Varnish. You
+start, stop and restart those via the ``bin/supervisorctl`` utility.
+
+To start all processes automatically on system boot it is necessary to
+start supervisord as part of the system boot process. This can easily
+be done by adding a crontab entry to the account used for your site::
+
+ # Automatically start the plone.org website
+ @reboot /srv/plone.org/bin/supervisord -c /srv/plone.org/etc/supervisord.conf
+
+.. _supervisord: http://www.supervisord.org/
+
+
+Log rotation
+------------
+
+This buildout includes a configuration for ``logrotate``, which is included
+in all common Linux distributions. To setup log rotation you will need to
+add an entry to the crontab entry for the account user for your site::
+
+ # Rotate plone.org logfiles at 06:00
+ 0 6 * * * /usr/sbin/logrotate --state /srv/plone.org/var/logrotate.status /srv/plone.org/etc/logrotate.conf
+
+
+Selecting product and package versions
+--------------------------------------
+
+For production environment it is generally a good idea to enforce
+use of specific, tested, versions of all packages and products. This
+can prevent unexpected surprises when updating a buildout environment
+or deploying it on another machine.
+
+For Zope2 products it is recommended to use a release tar or zip-archive.
+This can be installed using the *productdistros* section in ``buildout.cfg``.
+See `plone.recipe.distros`_ for more information.
+
+Packages can be pinned down in the *versions* section, also located in
+``buildout.cfg``.
+
+.. _plone.recipe.distros: http://pypi.python.org/pypi/plone.recipe.distros
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/base.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/base.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/base.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,93 @@
+[buildout]
+parts =
+ plone
+ zope2
+ productdistros
+ zeo
+ instance1
+ zopepy
+#if $proxy
+ varnish-build
+ varnish
+#end if
+ logrotate
+ supervisor
+find-links =
+ http://dist.plone.org
+ http://effbot.org/downloads
+eggs =
+develop =
+versions = versions
+
+[versions]
+plone.recipe.zope2instance = 3.6
+
+[plone]
+recipe = ${plone_recipe}
+#if $plone_recipe == "plone.recipe.plone25install"
+url = ${plone_url}
+#end if
+
+[zope2]
+recipe = plone.recipe.zope2install
+url = \${plone:zope2-url}
+
+[productdistros]
+recipe = plone.recipe.distros
+urls =
+nested-packages =
+version-suffix-packages =
+
+[zeo]
+recipe = plone.recipe.zope2zeoserver
+zope2-location = \${zope2:location}
+zeo-address = 127.0.0.1:${zeo_port}
+
+[instance1]
+recipe = plone.recipe.zope2instance
+zope2-location = \${zope2:location}
+debug-mode = off
+verbose-security = off
+zeo-client = True
+zeo-address = \${zeo:zeo-address}
+user = ${zope_user}:${zope_password}
+http-address = 127.0.0.1:${http_port}
+eggs =
+ \${buildout:eggs}
+ \${plone:eggs}
+ elementtree
+zcml =
+products =
+ \${buildout:directory}/products
+ \${productdistros:location}
+ \${plone:products}
+
+[zopepy]
+recipe = zc.recipe.egg
+eggs = \${instance1:eggs}
+interpreter = zopepy
+extra-paths = \${zope2:location}/lib/python
+scripts = zopepy
+
+#if $proxy
+[varnish-build]
+recipe = plone.recipe.varnish:build
+url = http://puzzle.dl.sourceforge.net/sourceforge/varnish/varnish-1.1.2.tar.gz
+
+[varnish]
+recipe = plone.recipe.varnish:instance
+backends = \${instance1:http-address}
+bind = 127.0.0.1:${proxy_port}
+cache-size = 512M
+#end if
+
+[logrotate]
+recipe = collective.recipe.template
+input = templates/logrotate.conf
+output = \${buildout:directory}/etc/logrotate.conf
+
+[supervisor]
+recipe = zc.recipe.egg
+eggs = supervisor
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 85041 2008-03-31 15:57:30Z andreasjung $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,25 @@
+# This is the zc.buildout configuration
+# For more information on managing your Plone instance using buildout please
+# see http://plone.org/documentation/tutorial/buildout
+
+[buildout]
+extends = base.cfg
+versions = versions
+eggs =
+develop =
+
+[versions]
+#if $plone_recipe == "plone.recipe.plone"
+${plone_recipe} = ${plone_recipe_version}
+#end if
+
+[productdistros]
+urls =
+nested-packages =
+version-suffix-packages =
+
+[instance1]
+eggs =
+ \${buildout:eggs}
+ \${plone:eggs}
+zcml =
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/etc/supervisord.conf_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/etc/supervisord.conf_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/etc/supervisord.conf_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,49 @@
+[unix_http_server]
+file=%(here)s/../var/supervisor.sock
+chmod=0600
+
+[supervisorctl]
+serverurl=unix://%(here)s/../var/supervisor.sock
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
+
+[supervisord]
+logfile=%(here)s/../var/log/supervisord.log
+logfile_maxbytes=5MB
+logfile_backups=10
+loglevel=info
+pidfile=%(here)s/../var/supervisord.pid ;
+childlogdir=%(here)s/../var/log
+nodaemon=false ; (start in foreground if true;default false)
+minfds=1024 ; (min. avail startup file descriptors;default 1024)
+minprocs=200 ; (min. avail process descriptors;default 200)
+directory=%(here)s
+
+[program:zeo]
+command = %(here)s/../bin/zeo fg
+autostart= true
+autorestart = true
+startsecs = 10
+priority = 100
+
+[program:instance1]
+command = %(here)s/../bin/instance1 console
+startsecs = 60
+priority = 2
+redirect_stderr = true
+autostart= true
+autorestart = true
+priority = 500
+
+[groups]
+programs = instance1
+
+#if $proxy
+[program:varnish]
+command = %(here)s/../bin/varnish -F
+autostart= true
+autorestart = true
+priority = 1000
+#end if
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/products/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/products/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/products/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Old-style Zope products you are developing can be added here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/templates/logrotate.conf
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/templates/logrotate.conf (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/templates/logrotate.conf 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+# This file is generated from templates/logrotate.conf.
+# Please do not edit the copy in etc/
+
+rotate 4
+weekly
+create
+compress
+delaycompress
+
+${buildout:directory}/var/log/zeo.log {
+ postrotate
+ ${buildout:bin-directory}/zeo logreopen
+ endscript
+}
+
+${buildout:directory}/var/log/instance1.log ${buildout:directory}/var/log/instance1-Z2.log {
+ sharedscripts
+ postrotate
+ /bin/kill -USR2 $(cat ${buildout:directory}/var/instance1.pid)
+ endscript
+}
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_hosting/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,44 @@
+Tests for ${namespace_package}.${namespace_package2}.${package}
+
+test setup
+----------
+
+ >>> from Testing.ZopeTestCase import user_password
+ >>> from Products.Five.testbrowser import Browser
+ >>> browser = Browser()
+
+Plugin setup
+------------
+
+ >>> acl_users_url = "%s/acl_users" % self.portal.absolute_url()
+ >>> browser.addHeader('Authorization', 'Basic %s:%s' % ('portal_owner', user_password))
+ >>> browser.open("%s/manage_main" % acl_users_url)
+ >>> browser.url
+ 'http://nohost/plone/acl_users/manage_main'
+ >>> form = browser.getForm(index=0)
+ >>> select = form.getControl(name=':action')
+
+${namespace_package}.${namespace_package2}.${package} should be in the list of installable plugins:
+
+ >>> '${multiplugin_name} Helper' in select.displayOptions
+ True
+
+and we can select it:
+
+ >>> select.getControl('${multiplugin_name} Helper').click()
+ >>> select.displayValue
+ ['${multiplugin_name} Helper']
+ >>> select.value
+ ['manage_addProduct/${namespace_package}.${namespace_package2}.${package}/manage_add_${package}_helper_form']
+
+we add '${multiplugin_name} Helper' to acl_users:
+
+ >>> from ${namespace_package}.${namespace_package2}.${package}.plugin import ${multiplugin_name}Helper
+ >>> myhelper = ${multiplugin_name}Helper('myplugin', '${multiplugin_name} Helper')
+ >>> self.portal.acl_users['myplugin'] = myhelper
+
+and so on. Continue your tests here
+
+ >>> 'ALL OK'
+ 'ALL OK'
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+import install
+
+install.register_${package}_plugin()
+
+def initialize(context):
+ """Initializer called when used as a Zope 2 product."""
+ install.register_${package}_plugin_class(context)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/add_plugin.zpt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/add_plugin.zpt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/add_plugin.zpt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,46 @@
+<h1 tal:replace="structure here/manage_page_header">Header</h1>
+
+<h2 tal:define="form_title string:Add ${package} Helper"
+ tal:replace="structure here/manage_form_title">Form Title</h2>
+
+<p class="form-help">
+SSL Basic Authentication for Pluggable Auth Service functionality.
+</p>
+
+<form action="manage_add_${package}_helper" method="post"
+ enctype="multipart/form-data">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Id
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-optional">
+ Title
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="title" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ </td>
+ <td align="left" valign="top">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit"
+ value=" Add " />
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="${namespace_package}.${namespace_package2}.${package}">
+
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/icon.gif
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/browser/icon.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/configure.zcml_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="${namespace_package}.${namespace_package2}.${package}">
+
+ <five:registerPackage package="." initialize=".initialize" />
+ <include package=".browser" />
+
+</configure>
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/install.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/install.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/install.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,39 @@
+from AccessControl.Permissions import manage_users
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PluggableAuthService import registerMultiPlugin
+
+import plugin
+
+manage_add_${package}_form = PageTemplateFile('browser/add_plugin',
+ globals(), __name__='manage_add_${package}_form' )
+
+
+def manage_add_${package}_helper( dispatcher, id, title=None, REQUEST=None ):
+ """Add an ${package} Helper to the PluggableAuthentication Service."""
+
+ sp = plugin.${multiplugin_name}Helper( id, title )
+ dispatcher._setObject( sp.getId(), sp )
+
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect( '%s/manage_workspace'
+ '?manage_tabs_message='
+ '${package}Helper+added.'
+ % dispatcher.absolute_url() )
+
+
+def register_${package}_plugin():
+ try:
+ registerMultiPlugin(plugin.${multiplugin_name}Helper.meta_type)
+ except RuntimeError:
+ # make refresh users happy
+ pass
+
+
+def register_${package}_plugin_class(context):
+ context.registerClass(plugin.${multiplugin_name}Helper,
+ permission = manage_users,
+ constructors = (manage_add_${package}_form,
+ manage_add_${package}_helper),
+ visibility = None,
+ icon='browser/icon.gif'
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/interface.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/interface.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/interface.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,5 @@
+from Products.PluggableAuthService import interfaces
+
+class I${multiplugin_name}Helper(# -*- implemented plugins -*-
+ ):
+ """interface for ${multiplugin_name}Helper."""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugin.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugin.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugin.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+"""Class: ${multiplugin_name}Helper
+"""
+
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from App.class_init import default__class_init__ as InitializeClass
+
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+
+import interface
+import plugins
+
+class ${multiplugin_name}Helper( # -*- implemented plugins -*-
+ ):
+ """Multi-plugin
+
+ """
+
+ meta_type = '${package} Helper'
+ security = ClassSecurityInfo()
+
+ def __init__( self, id, title=None ):
+ self._setId( id )
+ self.title = title
+
+
+
+classImplements(${multiplugin_name}Helper, interface.I${multiplugin_name}Helper)
+
+InitializeClass( ${multiplugin_name}Helper )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/plugins/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+# -*- implemented plugins -*-
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/+namespace_package+/+namespace_package2+/+package+/tests.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,40 @@
+import unittest
+
+from zope.testing import doctestunit
+from zope.component import testing
+from Testing import ZopeTestCase as ztc
+
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import PloneSite
+ptc.setupPloneSite()
+
+import ${namespace_package}.${namespace_package2}.${package}
+
+class TestCase(ptc.PloneTestCase):
+ class layer(PloneSite):
+ @classmethod
+ def setUp(cls):
+ fiveconfigure.debug_mode = True
+ zcml.load_config('configure.zcml',
+ ${namespace_package}.${namespace_package2}.${package})
+ fiveconfigure.debug_mode = False
+
+ @classmethod
+ def tearDown(cls):
+ pass
+
+
+def test_suite():
+ return unittest.TestSuite([
+
+ ztc.FunctionalDocFileSuite(
+ 'README.txt', package='${namespace_package}.${namespace_package2}.${package}',
+ test_class=TestCase),
+
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CHANGES.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CHANGES.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CHANGES.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+#set $header_text = "%s (xxxx-xx-xx)" % $version or "0.0.0"
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+- Created recipe with ZopeSkel
+ [${$author or $empty}].
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CONTRIBUTORS.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CONTRIBUTORS.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/CONTRIBUTORS.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+${$author or $empty}, Author
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/INSTALL.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/INSTALL.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/INSTALL.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,42 @@
+#set $full_package_name = "%s.%s.%s" % ($namespace_package, $namespace_package2, $package)
+#set $header_text = "%s Installation" % $project
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+* When you're reading this you have probably already run
+ ``easy_install ${project}``. Find out how to install setuptools
+ (and EasyInstall) here:
+ http://peak.telecommunity.com/DevCenter/EasyInstall
+
+* Create a file called ``${project}-configure.zcml`` in the
+ ``/path/to/instance/etc/package-includes`` directory. The file
+ should only contain this:
+
+ <include package="${full_package_name}" />
+
+Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance
+recipe to manage your project, you can do this:
+
+* Add ``${full_package_name}`` to the list of eggs to install, e.g.:
+
+ [buildout]
+ ...
+ eggs =
+ ...
+ ${full_package_name}
+
+* Tell the plone.recipe.zope2instance recipe to install a ZCML slug:
+
+ [instance]
+ recipe = plone.recipe.zope2instance
+ ...
+ zcml =
+ ${full_package_name}
+
+* Re-run buildout, e.g. with:
+
+ $ ./bin/buildout
+
+You can skip the ZCML slug if you are going to explicitly include the package
+from another package's configure.zcml file.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.GPL
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.GPL (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.GPL 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/LICENSE.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+ ${project} is copyright $author
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/docs/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+.. contents::
+
+.. Note!
+ -----
+ Update the following URLs to point to your:
+
+ - code repository
+ - bug tracker
+ - questions/comments feedback mail
+ (do not set a real mail, to avoid spams)
+
+ Or remove it if not used.
+
+- Code repository: http://svn.somewhere.com/...
+- Questions and comments to somemailing_list
+- Report bugs at http://bug.somewhere.com/..
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/plone_pas/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+"""
+This module contains the tool of $project
+"""
+import os
+from setuptools import setup, find_packages
+
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+version = ${repr($version) or "0.0.0"}
+
+long_description = (
+ read('docs', 'README.txt')
+ + '\n' +
+ 'Change history\n'
+ '**************\n'
+ + '\n' +
+ read('docs', 'CHANGES.txt')
+ + '\n' +
+ 'Detailed Documentation\n'
+ '**********************\n'
+ + '\n' +
+ read(${repr($namespace_package)},
+ ${repr($namespace_package2)},
+ ${repr($package)}, 'README.txt')
+ + '\n' +
+ 'Contributors\n'
+ '************\n'
+ + '\n' +
+ read('docs', 'CONTRIBUTORS.txt')
+ + '\n' +
+ 'Download\n'
+ '********\n')
+
+tests_require = ['zope.testing']
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=long_description,
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ 'Framework :: Plone',
+ 'Intended Audience :: Developers',
+ #from zopeskel.base import LICENSE_CATEGORIES
+ #if $license_name.strip() in $LICENSE_CATEGORIES
+ $repr($LICENSE_CATEGORIES[$license_name.strip()]),
+ #end if
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=['setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ tests_require=tests_require,
+ extras_require=dict(tests=tests_require),
+ test_suite='$namespace_package.$namespace_package2.${package}.tests.test_docs.test_suite',
+ entry_points="""
+ # -*- entry_points -*-
+
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
+ setup_requires=["PasteScript"],
+ paster_plugins=["ZopeSkel"],
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,61 @@
+Supported options
+=================
+
+The recipe supports the following options:
+
+.. Note to recipe author!
+ ----------------------
+ For each option the recipe uses you should include a description
+ about the purpose of the option, the format and semantics of the
+ values it accepts, whether it is mandatory or optional and what the
+ default value is if it is omitted.
+
+option1
+ Description for ``option1``...
+
+option2
+ Description for ``option2``...
+
+
+Example usage
+=============
+
+.. Note to recipe author!
+ ----------------------
+ zc.buildout provides a nice testing environment which makes it
+ relatively easy to write doctests that both demonstrate the use of
+ the recipe and test it.
+ You can find examples of recipe doctests from the PyPI, e.g.
+
+ http://pypi.python.org/pypi/zc.recipe.egg
+
+ The PyPI page for zc.buildout contains documentation about the test
+ environment.
+
+ http://pypi.python.org/pypi/zc.buildout#testing-support
+
+ Below is a skeleton doctest that you can start with when building
+ your own tests.
+
+We'll start by creating a buildout that uses the recipe::
+
+ >>> write('buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = test1
+ ...
+ ... [test1]
+ ... recipe = $project
+ ... option1 = %(foo)s
+ ... option2 = %(bar)s
+ ... """ % { 'foo' : 'value1', 'bar' : 'value2'})
+
+Running the buildout gives us::
+
+ >>> print 'start', system(buildout)
+ start...
+ Installing test1.
+ Unused options for test1: 'option2' 'option1'.
+ <BLANKLINE>
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+"""Recipe $package"""
+
+class Recipe(object):
+ """zc.buildout recipe"""
+
+ def __init__(self, buildout, name, options):
+ self.buildout, self.name, self.options = buildout, name, options
+
+ def install(self):
+ """Installer"""
+ # XXX Implement recipe functionality here
+
+ # Return files that were created by the recipe. The buildout
+ # will remove all returned files upon reinstall.
+ return tuple()
+
+ def update(self):
+ """Updater"""
+ pass
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+# package
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/test_docs.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/test_docs.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/+package+/tests/test_docs.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+"""
+Doctest runner for ${repr($project)}.
+"""
+__docformat__ = 'restructuredtext'
+
+import unittest
+import zc.buildout.tests
+import zc.buildout.testing
+
+from zope.testing import doctest, renormalizing
+
+optionflags = (doctest.ELLIPSIS |
+ doctest.NORMALIZE_WHITESPACE |
+ doctest.REPORT_ONLY_FIRST_FAILURE)
+
+def setUp(test):
+ zc.buildout.testing.buildoutSetUp(test)
+
+ # Install the recipe in develop mode
+ zc.buildout.testing.install_develop('$project', test)
+
+ # Install any other recipes that should be available in the tests
+ #zc.buildout.testing.install('collective.recipe.foobar', test)
+
+def test_suite():
+ suite = unittest.TestSuite((
+ doctest.DocFileSuite(
+ '../README.txt',
+ setUp=setUp,
+ tearDown=zc.buildout.testing.buildoutTearDown,
+ optionflags=optionflags,
+ checker=renormalizing.RENormalizing([
+ # If want to clean up the doctest output you
+ # can register additional regexp normalizers
+ # here. The format is a two-tuple with the RE
+ # as the first item and the replacement as the
+ # second item, e.g.
+ # (re.compile('my-[rR]eg[eE]ps'), 'my-regexps')
+ zc.buildout.testing.normalize_path,
+ ]),
+ ),
+ ))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/+namespace_package2+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/__init__.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/__init__.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/+namespace_package+/__init__.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CHANGES.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CHANGES.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CHANGES.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+#set $header_text = "%s (xxxx-xx-xx)" % ($version or "0.0.0",)
+#set $header_line = "-" * len($header_text)
+$header_text
+$header_line
+
+- Created recipe with ZopeSkel
+ [${$author or $empty}]
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CONTRIBUTORS.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CONTRIBUTORS.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/CONTRIBUTORS.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+${$author or $empty}, Author
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/README.txt_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/README.txt_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/README.txt_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,17 @@
+.. contents::
+
+.. Note to recipe author!
+ ---------------------
+ Update the following URLs to point to your:
+
+ - code repository
+ - bug tracker
+ - questions/comments feedback mail
+ (do not set a real mail, to avoid spams)
+
+ Or remove it if not used.
+
+- Code repository: http://svn.somewhere.com/...
+- Questions and comments to somemailing_list
+- Report bugs at http://bug.somewhere.com/..
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 85041 2008-03-31 15:57:30Z andreasjung $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,8 @@
+[buildout]
+develop = .
+parts = test
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = ${project} [tests]
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/setup.py_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/setup.py_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/recipe/setup.py_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+"""
+This module contains the tool of $project
+"""
+import os
+from setuptools import setup, find_packages
+
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+version = ${repr($version) or "0.0.0"}
+
+long_description = (
+ read('README.txt')
+ + '\n' +
+ 'Detailed Documentation\n'
+ '**********************\n'
+ + '\n' +
+ read(${repr($namespace_package)}, ${repr($namespace_package2)}, ${repr($package)}, 'README.txt')
+ + '\n' +
+ 'Contributors\n'
+ '************\n'
+ + '\n' +
+ read('CONTRIBUTORS.txt')
+ + '\n' +
+ 'Change history\n'
+ '**************\n'
+ + '\n' +
+ read('CHANGES.txt')
+ + '\n' +
+ 'Download\n'
+ '********\n')
+
+entry_point = '$namespace_package.$namespace_package2.${package}:Recipe'
+entry_points = {"zc.buildout": ["default = %s" % entry_point]}
+
+tests_require = ['zope.testing', 'zc.buildout']
+
+setup(name=${repr($project)},
+ version=version,
+ description="${description or None}",
+ long_description=long_description,
+ # Get more strings from
+ # http://pypi.python.org/pypi?:action=list_classifiers
+ classifiers=[
+ 'Framework :: Buildout',
+ 'Intended Audience :: Developers',
+ 'Topic :: Software Development :: Build Tools',
+ #from zopeskel.base import LICENSE_CATEGORIES
+ #if $license_name.strip() in $LICENSE_CATEGORIES
+ $repr($LICENSE_CATEGORIES[$license_name.strip()]),
+ #end if
+ ],
+ keywords=${repr($keywords) or $empty},
+ author=${repr($author) or $empty},
+ author_email=${repr($author_email) or $empty},
+ url=${repr($url) or $empty},
+ license=${repr($license_name) or $empty},
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['$namespace_package', '$namespace_package.$namespace_package2'],
+ include_package_data=True,
+ zip_safe=${repr(bool($zip_safe)) or False},
+ install_requires=['setuptools',
+ 'zc.buildout'
+ # -*- Extra requirements: -*-
+ ],
+ tests_require=tests_require,
+ extras_require=dict(tests=tests_require),
+ test_suite='$namespace_package.$namespace_package2.${package}.tests.test_docs.test_suite',
+ entry_points=entry_points,
+ )
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,262 @@
+=======================
+Using a custom buildout
+=======================
+
+Note: If you are using Windows, please see below.
+
+You probably got here by running something like:
+
+ $ paster create -t silva_buildout
+
+Now, you need to run, using python 2.4:
+
+ $ python bootstrap.py
+
+This will install zc.buildout for you.
+
+To create an instance immediately, run:
+
+ $ bin/buildout
+
+This will install Silva for you, as well as other dependencies, create
+a new Zope 2 installation (unless you specified an existing one when
+you ran "paster create"), and create a new Zope instance configured
+with these products.
+
+You can start your Zope instance by running:
+
+ $ bin/instance start
+
+or, to run in foreground mode:
+
+ $ bin/instance fg
+
+To run unit tests, you can use:
+
+ $ bin/instance test -s my.package
+
+
+Using a different Python installation
+--------------------------------------
+
+Buildout will use your system Python installation by default. However, Zope
+2.10 (and by extension, Silva) will only work with Python 2.4. You can verify
+which version of Python you have, by running:
+
+ $ python -V
+
+If that is not a 2.4 version, you need to install Python 2.4 from
+http://python.org. If you wish to keep another version as your main system
+Python, edit buildout.cfg and add an 'executable' option to the "[buildout]"
+section, pointing to a python interpreter binary:
+
+ [buildout]
+ ...
+ executable = /path/to/python
+
+
+Working with buildout.cfg
+-------------------------
+
+You can change any option in buildout.cfg and re-run bin/buildout to reflect
+the changes. This may delete things inside the 'parts' directory, but should
+keep your Data.fs and source files intact.
+
+To save time, you can run buildout in "offline" (-o) and non-updating (-N)
+mode, which will prevent it from downloading things and checking for new
+versions online:
+
+ $ bin/buildout -Nov
+
+
+Developing old-style products
+-----------------------------
+
+If you are developing old-style Zope 2 products (not eggs) then you can do so
+by placing the product code in the top-level 'products' directory. This is
+analogous to the 'Products/' directory inside a normal Zope 2 instance and is
+scanned on start-up for new products.
+
+Depending on a new egg
+----------------------
+
+If you want to use a new egg that is in the Python Package Index, all you need
+to do is to add it to the "eggs" option under the main "[buildout]" section:
+
+ [buildout]
+ ...
+ eggs +=
+ my.package
+
+If it's listed somewhere else than the Python Package Index, you can add a link
+telling buildout where to find it in the 'find-links' option:
+
+ [buildout]
+ ...
+ find-links +=
+ http://some.host.com/packages
+
+Using existing old-style products
+---------------------------------
+
+If you are using an old-style (non-egg) product, you can either add it as an
+automatically downloaded archive or put it in the top-level "products" folder.
+The former is probably better, because it means you can redistribute your
+buildout.cfg more easily:
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://infrae.com/download/someproduct/releases/1.3/someproduct-1.3.tar.gz
+
+If someproduct-1.3.tar.gz extracts into several products inside a top-level
+directory, e.g. SomeProduct-1.3/PartOne and SomeProduct-1.3/PartTwo, then
+add it as a "nested package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://infrae.com/download/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ nested-packages =
+ someproduct-1.3.tar.gz
+
+Alternatively, if it extracts to a directory which contains the version
+number, add it as a "version suffix package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://infrae.com/download/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ version-suffix-packages =
+ someproduct-1.3.tar.gz
+
+You can also track products by adding a new bundle checkout part. It
+doesn't strictly have to be an svn bundle at all, any svn location will do,
+and cvs is also supported:
+
+ [buildout]
+ ...
+ parts +=
+ myproduct
+ productdistros
+
+Note that "myproduct" comes before the "instance" part. You then
+need to add a new section to buildout.cfg:
+
+ [myproduct]
+ recipe = plone.recipe.bundlecheckout
+ url = http://svn.plone.org/svn/collective/myproduct/trunk
+
+Finally, you need to tell Zope to find this new checkout and add it to its
+list of directories that are scanned for products:
+
+ [instance]
+ ...
+ products +=
+ ${myproduct:location}
+ ${productdistros:location}
+
+Without this last step, the "myproduct" part is simply managing an svn
+checkout and could potentially be used for something else instead.
+
+=============
+Using Windows
+=============
+
+To use buildout on Windows, you will need to install a few dependencies which
+other platforms manage on their own.
+
+Here are the steps you need to follow (thanks to Hanno Schlichting for these):
+
+Python (http://python.org)
+--------------------------
+
+ - Download and install Python 2.4.4 using the Windows installer from
+ http://www.python.org/ftp/python/2.4.4/python-2.4.4.msi
+ Select 'Install for all users' and it will put Python into the
+ "C:\Python24" folder by default.
+
+ - You also want the pywin32 extensions available from
+ http://downloads.sourceforge.net/pywin32/pywin32-210.win32-py2.4.exe?modtime=1159009237&big_mirror=0
+
+ - If you develop Zope based applications you will usually only need Python 2.4
+ at the moment, so it's easiest to put the Python binary on the systems PATH,
+ so you don't need to specify its location manually each time you call it.
+
+ Thus, put "C:\Python24" and "C:\Python24\Scripts" onto the PATH. You can
+ find the PATH definition in the control panel under system preferences on
+ the advanced tab at the bottom. The button is called environment variables.
+ You want to add it at the end of the already existing PATH in the system
+ section. Paths are separated by a semicolons.
+
+ - You can test if this was successful by opening a new shell (cmd) and type
+ in 'python -V'. It should report version 2.4.4 (or whichever version you
+ installed).
+
+ Opening a new shell can be done quickly by using the key combination
+ 'Windows-r' or if you are using Parallels on a Mac 'Apple-r'. Type in 'cmd'
+ into the popup box that opens up and hit enter.
+
+
+Subversion (http://subversion.tigris.org)
+-----------------------------------------
+
+ - Download the nice installer from
+ http://subversion.tigris.org/files/documents/15/35379/svn-1.4.2-setup.exe
+
+ - Run the installer. It defaults to installing into
+ "C:\Program Files\Subversion".
+
+ - Now put the install locations bin subfolder (for example
+ "C:\Program Files\Subversion\bin") on your system PATH in the same way you
+ put Python on it.
+
+ - Open a new shell again and type in: 'svn --version' it should report
+ version 1.4.2 or newer.
+
+
+MinGW (http://www.mingw.org/)
+-----------------------------
+
+ This is a native port of the gcc compiler and its dependencies for Windows.
+ There are other approaches enabling you to compile Python C extensions on
+ Windows including Cygwin and using the official Microsoft C compiler, but this
+ is a lightweight approach that uses only freely available tools. As
+ it's used by a lot of people chances are high it will work for you and there's
+ plenty of documentation out there to help you in troubleshooting problems.
+
+ - Download the MinGW installer from
+ http://downloads.sourceforge.net/mingw/MinGW-5.1.3.exe?modtime=1168794334&big_mirror=1
+
+ - The installer will ask you which options you would like to install. Choose
+ base and make here. It will install into "C:\MinGW" by default. The install
+ might take some time as it's getting files from sourceforge.net and you
+ might need to hit 'retry' a couple of times.
+
+ - Now put the install location's bin subfolder (for example "C:\MinGW\bin") on
+ your system PATH in the same way you put Python on it.
+
+ - Test this again by typing in: 'gcc --version' on a newly opened shell and
+ it should report version 3.4.2 or newer.
+
+
+Configure Distutils to use MinGW
+--------------------------------
+
+ Some general information are available from
+ http://www.mingw.org/MinGWiki/index.php/Python%20extensions for example but
+ you don't need to read them all.
+
+ - Create a file called 'distutils.cfg' in "C:\Python24\Lib\distutils". Open it
+ with a text editor ('notepad distutils.cfg') and fill in the following lines:
+
+ [build]
+ compiler=mingw32
+
+ This will tell distutils to use MinGW as the default compiler, so you don't
+ need to specify it manually using "--compiler=mingw32" while calling a
+ package's setup.py with a command that involves building C extensions. This
+ is extremely useful if the build command is written down in a buildout
+ recipe where you cannot change the options without hacking the recipe
+ itself. The z2c.recipe.zope2install used in ploneout is one such example.
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 74790 2008-10-31 20:59:38Z jjmojojjmojo $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,35 @@
+[buildout]
+#if not $zope2_install
+parts -=
+ zope2
+#end if
+
+extends =
+ https://svn.infrae.com/buildout/silva/${silva_distribution}.cfg
+
+\# Reference any eggs you are developing here, one per line
+\# e.g.: develop = src/my.package
+develop =
+
+[instance]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.zope2instance
+recipe = plone.recipe.zope2instance
+#if $zope2_install
+zope2-location = ${zope2_install}
+#else
+zope2-location = \${zope2:location}
+#end if
+user = ${zope_user}:${zope_password}
+http-address = ${http_port}
+#if $debug_mode == 'on'
+debug-mode = on
+#else
+\#debug-mode = on
+#end if
+#if $verbose_security == 'on'
+verbose-security = on
+#else
+\#verbose-security = on
+#end if
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/products/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/products/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/products/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Old-style Zope products you are developing can be added here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/silva_buildout/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,285 @@
+=======================
+Using a custom buildout
+=======================
+
+Using a different Python installation
+--------------------------------------
+
+Buildout will use your system Python installation by default. However, Zope
+2.10 (and by extension, Plone) will only work with Python 2.4. You can verify
+which version of Python you have, by running:
+
+ $ python -V
+
+If that is not a 2.4 version, you need to install Python 2.4 from
+http://python.org. If you wish to keep another version as your main system
+Python, edit buildout.cfg and add an 'executable' option to the "[buildout]"
+section, pointing to a python interpreter binary:
+
+ [buildout]
+ ...
+ executable = /path/to/python
+
+Working with buildout.cfg
+-------------------------
+
+You can change any option in buildout.cfg and re-run bin/buildout to reflect
+the changes. This may delete things inside the 'parts' directory, but should
+keep your Data.fs and source files intact.
+
+To save time, you can run buildout in "offline" (-o) and non-updating (-N)
+mode, which will prevent it from downloading things and checking for new
+versions online:
+
+ $ bin/buildout -Nov
+
+Creating new eggs
+-----------------
+
+New packages you are working on (but which are not yet released as eggs and
+uploaded to the Python Package Index, aka PYPI) should be placed in src. You can do:
+
+ $ cd src/
+ $ paster create -t plone my.package
+
+Use "paster create --list-templates" to see all available templates. Answer
+the questions and you will get a new egg. Then tell buildout about your egg
+by editing buildout.cfg and adding your source directory to 'develop':
+
+ [buildout]
+ ...
+ develop =
+ src/my.package
+
+You can list multiple packages here, separated by whitespace or indented
+newlines.
+
+You probably also want the Zope instance to know about the package. Add its
+package name to the list of eggs in the "[instance]" section, or under the
+main "[buildout]" section:
+
+ [instance]
+ ...
+ eggs =
+ ${buildout:eggs}
+ ${plone:eggs}
+ my.package
+
+Leave the ${buildout:eggs} part in place - it tells the instance to use the
+eggs that buildout will have downloaded from the Python Package Index
+previously.
+
+If you also require a ZCML slug for your package, buildout can create one
+automatically. Just add the package to the 'zcml' option:
+
+ [instance]
+ ...
+ zcml =
+ my.package
+
+When you are finished, re-run buildout. Offline, non-updating mode should
+suffice:
+
+ $ bin/buildout -Nov
+
+Developing old-style products
+-----------------------------
+
+If you are developing old-style Zope 2 products (not eggs) then you can do so
+by placing the product code in the top-level 'products' directory. This is
+analogous to the 'Products/' directory inside a normal Zope 2 instance and is
+scanned on start-up for new products.
+
+Depending on a new egg
+----------------------
+
+If you want to use a new egg that is in the Python Package Index, all you need
+to do is to add it to the "eggs" option under the main "[buildout]" section:
+
+ [buildout]
+ ...
+ eggs =
+ my.package
+
+If it's listed somewhere else than the Python Package Index, you can add a link
+telling buildout where to find it in the 'find-links' option:
+
+ [buildout]
+ ...
+ find-links =
+ http://dist.plone.org
+ http://download.zope.org/distribution/
+ http://effbot.org/downloads
+ http://some.host.com/packages
+
+Using existing old-style products
+---------------------------------
+
+If you are using an old-style (non-egg) product, you can either add it as an
+automatically downloaded archive or put it in the top-level "products" folder.
+The former is probably better, because it means you can redistribute your
+buildout.cfg more easily:
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+
+If someproduct-1.3.tar.gz extracts into several products inside a top-level
+directory, e.g. SomeProduct-1.3/PartOne and SomeProduct-1.3/PartTwo, then
+add it as a "nested package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ nested-packages =
+ someproduct-1.3.tar.gz
+
+Alternatively, if it extracts to a directory which contains the version
+number, add it as a "version suffix package":
+
+ [productdistros]
+ recipe = plone.recipe.distros
+ urls =
+ http://plone.org/products/someproduct/releases/1.3/someproduct-1.3.tar.gz
+ version-suffix-packages =
+ someproduct-1.3.tar.gz
+
+You can also track products by adding a new bundle checkout part. It
+doesn't strictly have to be an svn bundle at all, any svn location will do,
+and cvs is also supported:
+
+ [buildout]
+ ...
+ parts =
+ zope2
+ productdistros
+ myproduct
+ instance
+ zopepy
+
+Note that "myproduct" comes before the "instance" part. You then
+need to add a new section to buildout.cfg:
+
+ [myproduct]
+ recipe = plone.recipe.bundlecheckout
+ url = http://svn.plone.org/svn/collective/myproduct/trunk
+
+Finally, you need to tell Zope to find this new checkout and add it to its
+list of directories that are scanned for products:
+
+ [instance]
+ ...
+ products =
+ ${buildout:directory}/products
+ ${productdistros:location}
+ ${plonebundle:location}
+ ${myproduct:location}
+
+Without this last step, the "myproduct" part is simply managing an svn
+checkout and could potentially be used for something else instead.
+
+=============
+Using Windows
+=============
+
+To use buildout on Windows, you will need to install a few dependencies which
+other platforms manage on their own.
+
+Here are the steps you need to follow (thanks to Hanno Schlichting for these):
+
+Python (http://python.org)
+--------------------------
+
+ - Download and install Python 2.4.4 using the Windows installer from
+ http://www.python.org/ftp/python/2.4.4/python-2.4.4.msi
+ Select 'Install for all users' and it will put Python into the
+ "C:\Python24" folder by default.
+
+ - You also want the pywin32 extensions available from
+ http://downloads.sourceforge.net/pywin32/pywin32-210.win32-py2.4.exe?modtime=1159009237&big_mirror=0
+
+ - And as a last step you want to download the Python imaging library available
+ from http://effbot.org/downloads/PIL-1.1.6.win32-py2.4.exe
+
+ - If you develop Zope based applications you will usually only need Python 2.4
+ at the moment, so it's easiest to put the Python binary on the systems PATH,
+ so you don't need to specify its location manually each time you call it.
+
+ Thus, put "C:\Python24" and "C:\Python24\Scripts" onto the PATH. You can
+ find the PATH definition in the control panel under system preferences on
+ the advanced tab at the bottom. The button is called environment variables.
+ You want to add it at the end of the already existing PATH in the system
+ section. Paths are separated by a semicolons.
+
+ - You can test if this was successful by opening a new shell (cmd) and type
+ in 'python -V'. It should report version 2.4.4 (or whichever version you
+ installed).
+
+ Opening a new shell can be done quickly by using the key combination
+ 'Windows-r' or if you are using Parallels on a Mac 'Apple-r'. Type in 'cmd'
+ into the popup box that opens up and hit enter.
+
+
+Subversion (http://subversion.tigris.org)
+-----------------------------------------
+
+ - Download the nice installer from
+ http://subversion.tigris.org/files/documents/15/35379/svn-1.4.2-setup.exe
+
+ - Run the installer. It defaults to installing into
+ "C:\Program Files\Subversion".
+
+ - Now put the install locations bin subfolder (for example
+ "C:\Program Files\Subversion\bin") on your system PATH in the same way you
+ put Python on it.
+
+ - Open a new shell again and type in: 'svn --version' it should report
+ version 1.4.2 or newer.
+
+
+MinGW (http://www.mingw.org/)
+-----------------------------
+
+ This is a native port of the gcc compiler and its dependencies for Windows.
+ There are other approaches enabling you to compile Python C extensions on
+ Windows including Cygwin and using the official Microsoft C compiler, but this
+ is a lightweight approach that uses only freely available tools. As
+ it's used by a lot of people chances are high it will work for you and there's
+ plenty of documentation out there to help you in troubleshooting problems.
+
+ - Download the MinGW installer from
+ http://downloads.sourceforge.net/mingw/MinGW-5.1.3.exe?modtime=1168794334&big_mirror=1
+
+ - The installer will ask you which options you would like to install. Choose
+ base and make here. It will install into "C:\MinGW" by default. The install
+ might take some time as it's getting files from sourceforge.net and you
+ might need to hit 'retry' a couple of times.
+
+ - Now put the install location's bin subfolder (for example "C:\MinGW\bin") on
+ your system PATH in the same way you put Python on it.
+
+ - Test this again by typing in: 'gcc --version' on a newly opened shell and
+ it should report version 3.4.2 or newer.
+
+
+Configure Distutils to use MinGW
+--------------------------------
+
+ Some general information are available from
+ http://www.mingw.org/MinGWiki/index.php/Python%20extensions for example but
+ you don't need to read them all.
+
+ - Create a file called 'distutils.cfg' in "C:\Python24\Lib\distutils". Open it
+ with a text editor ('notepad distutils.cfg') and fill in the following lines:
+
+ [build]
+ compiler=mingw32
+
+ This will tell distutils to use MinGW as the default compiler, so you don't
+ need to specify it manually using "--compiler=mingw32" while calling a
+ package's setup.py with a command that involves building C extensions. This
+ is extremely useful if the build command is written down in a buildout
+ recipe where you cannot change the options without hacking the recipe
+ itself. The z2c.recipe.zope2install used in ploneout is one such example.
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/bootstrap.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/bootstrap.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/bootstrap.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 85041 2008-03-31 15:57:30Z andreasjung $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/buildout.cfg_tmpl
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/buildout.cfg_tmpl (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/buildout.cfg_tmpl 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,94 @@
+[buildout]
+parts =
+#if not $zope2_install
+ zope2
+#end if
+ productdistros
+ instance
+ zopepy
+
+\# Add additional egg download sources here.
+find-links =
+ http://download.zope.org/ppix/
+ http://download.zope.org/distribution/
+ http://effbot.org/downloads
+
+\# Add additional eggs here
+eggs =
+
+\# Reference any eggs you are developing here, one per line
+\# e.g.: develop = src/my.package
+develop =
+
+#if not $zope2_install
+[zope2]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.zope2install
+recipe = plone.recipe.zope2install
+url = http://www.zope.org/Products/Zope/${zope2_version}/Zope-${zope2_version}-final.tgz
+#end if
+
+\# Use this section to download additional old-style products.
+\# List any number of URLs for product tarballs under URLs (separate
+\# with whitespace, or break over several lines, with subsequent lines
+\# indented). If any archives contain several products inside a top-level
+\# directory, list the archive file name (i.e. the last part of the URL,
+\# normally with a .tar.gz suffix or similar) under 'nested-packages'.
+\# If any archives extract to a product directory with a version suffix, list
+\# the archive name under 'version-suffix-packages'.
+[productdistros]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.distros
+recipe = plone.recipe.distros
+urls =
+nested-packages =
+version-suffix-packages =
+
+[instance]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/plone.recipe.zope2instance
+recipe = plone.recipe.zope2instance
+#if $zope2_install
+zope2-location = ${zope2_install}
+#else
+zope2-location = \${zope2:location}
+#end if
+user = ${zope_user}:${zope_password}
+http-address = ${http_port}
+#if $debug_mode == 'on'
+debug-mode = on
+#else
+\#debug-mode = on
+#end if
+#if $verbose_security == 'on'
+verbose-security = on
+#else
+\#verbose-security = on
+#end if
+
+\# If you want Zope to know about any additional eggs, list them here.
+\# This should include any development eggs you listed in develop-eggs above,
+\# e.g. eggs = \${buildout:eggs} \${plone:eggs} my.package
+eggs =
+ \${buildout:eggs}
+
+\# If you want to register ZCML slugs for any packages, list them here.
+\# e.g. zcml = my.package my.other.package
+zcml =
+
+products =
+ \${buildout:directory}/products
+ \${productdistros:location}
+
+[zopepy]
+\# For more information on this step and configuration options see:
+\# http://pypi.python.org/pypi/zc.recipe.egg
+recipe = zc.recipe.egg
+eggs = \${instance:eggs}
+interpreter = zopepy
+#if $zope2_install
+extra-paths = ${zope2_install}/lib/python
+#else
+extra-paths = \${zope2:location}/lib/python
+#end if
+scripts = zopepy
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/products/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/products/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/products/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Old-style Zope products you are developing can be added here
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/templates/zope2_buildout/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,2 @@
+# package
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_all.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_all.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_all.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,21 @@
+import unittest
+
+from zopeskel.tests.test_zopeskeldocs import test_suite as doc_test_suite
+from zopeskel.tests.test_base import test_suite as base_test_suite
+from zopeskel.tests.test_vars import test_suite as vars_test_suite
+from zopeskel.tests.test_zopeskel_script import test_suite as script_test_suite
+
+def test_suite():
+ """ it appears that the order here makes a difference, ensure that doc_test_suite
+ is always added last
+ """
+ suite = unittest.TestSuite([
+ base_test_suite(),
+ vars_test_suite(),
+ script_test_suite(),
+ doc_test_suite(),
+ ])
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_base.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_base.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_base.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,157 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+
+from paste.script.command import get_commands
+
+from zopeskel.base import BaseTemplate, get_var
+from zopeskel.vars import var, BooleanVar, StringVar, TextVar, DottedVar
+from zopeskel.vars import EXPERT, EASY
+from zopeskel.archetype import Archetype
+from zopeskel.plone import Plone
+from zopeskel.basic_namespace import BasicNamespace
+
+class test_base_template(unittest.TestCase):
+ """ test for methods on the base template class
+ """
+ def setUp(self):
+ """ set up some basics for the coming tests
+ """
+ self.vars = [
+ var('basic_var', 'This is a basic variable',
+ title="Basic Title", default="foo",
+ modes=(EXPERT, EASY)),
+ BooleanVar('bool_var', 'This is a boolean variable',
+ title="Boolean Title", default=False, page='Main',
+ modes=(EASY)),
+ StringVar('str_var', 'This is a string variable',
+ title="String Title", default="string", page='Carl',
+ modes=(EXPERT)),
+ TextVar('txt_var', 'This is a text variable', page='Martin',
+ title="Text Title", default="text",
+ modes=()),
+ DottedVar('dot_var', 'This is a dotted variable',
+ title="Dotted Title", default="dotted.variable")
+ ]
+ self.template = BaseTemplate('my_name')
+ create = get_commands()['create'].load()
+ command = create('create')
+ command.parse_args(['-t','archetype'])
+ self.command = command
+
+ def test_filter_for_modes(self):
+ """ _filter_for_modes should return a dictionary of var names to
+ be hidden from view dependent on the running mode of zopeskel
+ and the modes property of each variable
+ """
+ easy_vars = [var.name for var in self.vars
+ if EASY not in var.modes]
+ expert_vars = [var.name for var in self.vars
+ if EXPERT not in var.modes]
+
+ expert_mode = EASY
+ hidden = self.template._filter_for_modes(expert_mode, self.vars)
+
+ self.assertEqual(len(hidden), 2)
+ for varname in hidden.keys():
+ self.failUnless(varname in easy_vars,
+ "missing easy var: %s" % varname)
+
+ expert_mode = EXPERT
+ hidden = self.template._filter_for_modes(expert_mode, self.vars)
+
+ self.assertEqual(len(hidden), 2)
+ for varname in hidden.keys():
+ self.failUnless(varname in expert_vars,
+ "missing expert var: %s" % varname)
+
+ def test_get_vars(self):
+ """ get_vars is not a method of BaseTemplate, but we've got a nice set
+ of variables all set up in here, so let's use it
+ """
+ var = get_var(self.vars, 'basic_var')
+ self.assertEqual(var.name, 'basic_var')
+ self.assertEqual(var.title, 'Basic Title')
+ self.assertEqual(var.description, 'This is a basic variable')
+ self.assertEqual(var.modes, (EXPERT, EASY))
+ self.assertEqual(var.default, 'foo')
+
+ def test_pages(self):
+ """ pagaes divide questions for a template into discreet sets for web GUI
+ """
+ class MyTemplate(BaseTemplate):
+ vars = BaseTemplate.vars + self.vars
+
+ template = MyTemplate('some_name')
+ pages = template.pages
+ self.assertEqual(len(pages), 4)
+
+ page = pages.pop(0)
+ self.assertEqual(page['name'], 'Begin')
+ questions = page['vars']
+ self.assertEqual(len(questions), 1)
+ self.assertEqual(questions[0].name, 'expert_mode')
+ page = pages.pop(0)
+ self.assertEqual(page['name'], 'Main')
+ questions = page['vars']
+ self.assertEqual(len(questions), 3)
+ self.assertEqual(questions[0].name, 'basic_var')
+ self.assertEqual(questions[1].name, 'bool_var')
+ self.assertEqual(questions[2].name, 'dot_var')
+
+ page = pages.pop(0)
+ self.assertEqual(page['name'], 'Carl')
+ questions = page['vars']
+ self.assertEqual(len(questions), 1)
+ self.assertEqual(questions[0].name, 'str_var')
+
+ page = pages.pop(0)
+ self.assertEqual(page['name'], 'Martin')
+ questions = page['vars']
+ self.assertEqual(len(questions), 1)
+ self.assertEqual(questions[0].name, 'txt_var')
+
+ def test_get_position_in_stack(self):
+ """ verify that the position of a template can be reliably found
+ """
+ stack = self.template.get_template_stack(self.command)
+ self.assertRaises(ValueError, self.template.get_position_in_stack, stack)
+
+ new_template = Archetype('joe')
+ self.assertEqual(new_template.get_position_in_stack(stack), len(stack)-1)
+
+ def test_get_template_stack(self):
+ """ verify that running this command against a create command
+ with the argument '-t archetype' returns the expected vals
+ """
+ stack = self.template.get_template_stack(self.command)
+ self.assertEqual(len(stack), 3)
+ self.failIf(self.template.__class__ in
+ [t.__class__ for t in stack], "%s" % stack)
+ new_template = Archetype('joe')
+ self.failUnless(new_template.__class__ in
+ [t.__class__ for t in stack], "%s" % stack)
+
+ for c in [t.__class__ for t in stack]:
+ self.failUnless(isinstance(new_template, c),
+ "%s does not appear to be a subclass of %s" % (new_template, c))
+
+ def test_should_print_subcommands(self):
+ """ If a template has subcommands, they should be printed after the template runs
+ """
+ n_template = BasicNamespace('tom')
+ p_template = Plone('bob')
+ a_template = Archetype('joe')
+
+ self.failIf(n_template.should_print_subcommands(self.command))
+ self.failIf(p_template.should_print_subcommands(self.command))
+ self.failUnless(a_template.should_print_subcommands(self.command))
+
+def test_suite():
+ suite = unittest.TestSuite([
+ unittest.makeSuite(test_base_template),
+ ])
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_vars.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_vars.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_vars.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+import sys
+from zopeskel.vars import var, BooleanVar, StringVar, TextVar, DottedVar,\
+ OnOffVar, IntVar, BoundedIntVar
+from zopeskel.vars import ValidationException
+
+class test_var(unittest.TestCase):
+ """ test that there is no default implementation of the validation method
+ """
+ def setUp(self):
+ self.var = var('name', 'description')
+
+ def testValidation(self):
+ """ the validation method should raise a ValidationException
+ """
+ try:
+ self.var.validate('foo')
+ except NotImplementedError:
+ pass
+ else:
+ self.fail("The validation method should not be implemented on the basic var class")
+
+ def testPrettyDescription(self):
+ """ pretty_description should return a nice combination of title or name
+ and description
+ """
+ self.assertEqual(self.var.pretty_description(), 'name (description)')
+
+ self.var.title = 'title'
+ self.assertEqual(self.var.pretty_description(), 'title (description)')
+
+ def testFurtherHelp(self):
+ """ further_help will return the extensive help string set for a var
+ or a default 'nothing to see here' string
+ """
+ default = "Sorry, no further help is available for name\n"
+ self.assertEqual(self.var.further_help(), default)
+
+ self.var.help = "I'm a little help text, short and stout"
+ self.assertEqual(self.var.further_help(),
+ "I'm a little help text, short and stout")
+
+
+class test_BooleanVar(unittest.TestCase):
+ """ verify functionality of the BooleanVar variable class
+ """
+ def setUp(self):
+ self.bvar = BooleanVar('name', 'description')
+
+ def testValidation(self):
+ """ check to see that various inputs result in a Boolean Value
+ """
+ for val in ('f','F','n','N','false',0):
+ self.failIf(self.bvar.validate(val))
+
+ for val in ('t','T','y','Y','true',1):
+ self.failUnless(self.bvar.validate(val))
+
+ self.assertRaises(ValidationException, self.bvar.validate, 'humpty-dumpty')
+
+
+class test_OnOffVar(unittest.TestCase):
+ """ verify functionality of the OnOffVar variable class
+ """
+ def setUp(self):
+ self.ovar = OnOffVar('name', 'description')
+
+ def testValidation(self):
+ """ check to see that various inputs result in a Boolean Value
+ """
+ for val in ('f','F','n','N','false',0,'off'):
+ self.assertEqual(self.ovar.validate(val), 'off')
+
+ for val in ('t','T','y','Y','true',1,'on'):
+ self.assertEqual(self.ovar.validate(val), 'on')
+
+ self.assertRaises(ValidationException, self.ovar.validate, 'lunchbox')
+
+
+class test_IntVar(unittest.TestCase):
+ """ verify functionality of the IntVar variable class
+ """
+ def setUp(self):
+ self.ivar = IntVar('name', 'description')
+
+ def testValidation(self):
+ """ an IntVar should take values that can be cast to an integer,
+ any other value should raise a ValidationException
+ """
+ self.assertEqual(1, self.ivar.validate(1))
+ self.assertEqual(1, self.ivar.validate(1.9))
+ self.assertEqual(1, self.ivar.validate('1'))
+
+ self.assertRaises(ValidationException, self.ivar.validate, 'one')
+
+
+class test_BoundedIntVar(unittest.TestCase):
+ """ verify functionality of the BoundedIntVar variable class
+ """
+ def setUp(self):
+ self.bivar = BoundedIntVar('name','description', min=3, max=10)
+ self.defaultminvar = BoundedIntVar('name', 'description', max=10)
+ self.defaultmaxvar = BoundedIntVar('name', 'description', min=3)
+ self.max = sys.maxint
+ self.min = -self.max-1
+
+ def testValidation(self):
+ """ A BoundedIntVar should take values between min and max (inclusive)
+ If max is not provided, default to sys.maxint
+ if min is not provided, default to -sys.maxint-1
+ """
+ self.assertEqual(4, self.bivar.validate(4))
+ self.assertEqual(5, self.bivar.validate(5.9))
+ self.assertEqual(6, self.bivar.validate('6'))
+
+ self.assertRaises(ValidationException, self.bivar.validate, 'four')
+ self.assertRaises(ValidationException, self.bivar.validate, 1)
+ self.assertRaises(ValidationException, self.bivar.validate, 11)
+
+ self.assertEqual(self.max, self.defaultmaxvar.validate(self.max))
+ self.assertEqual(self.min, self.defaultminvar.validate(self.min))
+
+
+class test_StringVar(unittest.TestCase):
+ """ verify functionality of the StringVar variable class
+ """
+ def setUp(self):
+ self.svar = StringVar('name', 'description')
+
+ def testValidation(self):
+ """ check to see that validation returns appropriate values:
+ string should have no spaces at front or back
+ unicode strings and regular strings should pass through unchanged
+ non-string values raise validation errors
+ """
+ val = 'george'
+ self.assertEqual(val, self.svar.validate(val))
+
+ val = u'george'
+ self.assertEqual(val, self.svar.validate(val))
+
+ val = ' hello '
+ validated = self.svar.validate(val)
+ self.assertNotEqual(validated[0], ' ')
+ self.assertNotEqual(validated[-1], ' ')
+ self.failUnless(validated in val)
+
+ for val in (0, True):
+ self.assertRaises(ValidationException, self.svar.validate, val)
+
+
+class test_TextVar(unittest.TestCase):
+ """ verify functionality of the TextVar variable class
+ """
+ def setUp(self):
+ self.tvar = TextVar('name', 'description')
+
+ def testValidation(self):
+ """ we will test this more thoroughly when it does something useful that
+ is different than the above.
+ """
+ pass
+
+
+class test_DottedVar(unittest.TestCase):
+ def setUp(self):
+ self.dvar = DottedVar('name', 'description')
+
+ def testValidation(self):
+ """ all parts of a dotted name must be valid python identifiers
+ """
+ for val in ('this.package', '_foo_.bar', '__class__.__name__'):
+ self.assertEquals(val, self.dvar.validate(val))
+
+ for val in ('ham-and-eggs.yummy', 'spam.yucky!'):
+ self.assertRaises(ValidationException, self.dvar.validate, val)
+
+
+def test_suite():
+ suite = unittest.TestSuite([
+ unittest.makeSuite(test_var),
+ unittest.makeSuite(test_BooleanVar),
+ unittest.makeSuite(test_OnOffVar),
+ unittest.makeSuite(test_IntVar),
+ unittest.makeSuite(test_BoundedIntVar),
+ unittest.makeSuite(test_StringVar),
+ unittest.makeSuite(test_TextVar),
+ unittest.makeSuite(test_DottedVar),
+ ])
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskel_script.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskel_script.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskel_script.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+import sys
+import StringIO
+
+from zopeskel.zopeskel_script import checkdots, process_args, run, DESCRIPTION
+from zopeskel.ui import list_sorted_templates
+
+
+def capture_stdout(function):
+ def _capture_stdout(*args, **kw):
+ newout = StringIO.StringIO()
+ oldout = sys.stdout
+ sys.stdout = newout
+ try:
+ function(*args, **kw)
+ finally:
+ sys.stdout = oldout
+ newout.seek(0)
+ return newout.read()
+ return _capture_stdout
+
+run = capture_stdout(run)
+
+class test_zopeskel(unittest.TestCase):
+ """Tests for ZopeSkel script.
+ """
+
+ def test_checkdots_none(self):
+ """Verify that checkdots works with templates without ndots hint."""
+
+ class FauxTemplate: pass
+ t = FauxTemplate()
+
+ checkdots(t, "anything is legal; not a package")
+
+ def test_checkdots_two(self):
+ """Verify that checkdots validates templates with ndots hint."""
+
+ class FauxTemplate: pass
+ t = FauxTemplate()
+
+ t.ndots = 2
+
+ self.assertRaises(ValueError, checkdots, t, "nodots")
+ self.assertRaises(ValueError, checkdots, t, "one.dot")
+ self.assertRaises(ValueError, checkdots, t, "three.dots.in.this")
+ self.assertRaises(ValueError, checkdots, t, "two.dots.but not legal")
+
+ checkdots(t, "two.dots.legal")
+
+ def test_process_args(self):
+ """Ensure that process_args correctly processes command-line arguments"""
+ oldargv = sys.argv
+
+ sys.argv = ['zopskel']
+ self.assertRaises(SyntaxError, process_args)
+
+ sys.argv.append('archetype')
+ processed = process_args()
+ self.failUnlessEqual(processed[0], 'archetype')
+ self.failIf(processed[1])
+ self.failIf(processed[2])
+
+ sys.argv.append('my.project')
+ processed = process_args()
+ self.failUnlessEqual(processed[0], 'archetype')
+ self.failUnlessEqual(processed[1], 'my.project')
+ self.failIf(processed[2])
+
+ sys.argv.append('--bob=kate')
+ processed = process_args()
+ self.failUnlessEqual(processed[0], 'archetype')
+ self.failUnlessEqual(processed[1], 'my.project')
+ self.failUnlessEqual(processed[2]['--bob'], 'kate')
+
+ # process_args will allow us to skip the project name argument
+ sys.argv.pop(2)
+ processed = process_args()
+ self.failUnlessEqual(processed[0], 'archetype')
+ self.failIf(processed[1])
+ self.failUnlessEqual(processed[2]['--bob'], 'kate')
+
+ # providing arguments in '-name val' form is _not_ allowed
+ sys.argv = ['zopeskel', 'archetype', 'my.project', '-bob', 'kate']
+ self.assertRaises(SyntaxError, process_args)
+
+ # the --svn-repository argument is _not_ allowed in any form
+ sys.argv = sys.argv[:3] + ['--svn-repository=svn://svn.junk.org/svn/blah']
+ self.assertRaises(SyntaxError, process_args)
+
+ sys.argv[3] = 'svn-repository=svn://svn.junk.org/svn/blah'
+ self.assertRaises(SyntaxError, process_args)
+
+ # providing args in a '-name val' format is not supported
+ sys.argv = sys.argv[:3] + ['bob', 'kate']
+ self.assertRaises(SyntaxError, process_args)
+
+ sys.argv = oldargv
+
+ def test_script_errors(self):
+ """Verify that the run method catches errors correctly"""
+ oldargv = sys.argv
+
+ # non-existent templates are not caught until in 'run'
+ sys.argv = ['zopeskel', 'no-template', 'my.package']
+ output = run()
+ self.failUnless('ERROR: No such template' in output)
+
+ # calling the script with no arguments at all prints usage
+ sys.argv = sys.argv[:1]
+ output = run()
+ self.failUnless('Usage:' in output)
+
+ sys.argv = oldargv
+
+ def test_script_features(self):
+ """Verify that the help features of the script function correctly"""
+ oldargv = sys.argv
+
+ # --help produces the DESCRIPTION string
+ sys.argv = ['zopeskel', '--help']
+ output = run()
+ self.failUnless(DESCRIPTION in output, '--help produces incorrect output: %s' % output)
+
+ # --list produces a verbose list of all templates by category
+ sys.argv = ['zopeskel', '--list']
+ output = run()
+ cats = list_sorted_templates()
+ catnames = cats.keys()
+ templates = sum(cats.values(), [])
+ tempnames = [t['name'] for t in templates]
+ tempsums = [t['summary'] for t in templates]
+ for cat in catnames:
+ self.failUnless(cat in output, '%s not in --list output' % cat)
+ for tname in tempnames:
+ self.failUnless(tname in output, '%s not in --list output' % tname)
+ for summary in tempsums:
+ self.failUnless(summary in output, '%s not in --list output' % summary)
+
+ # --make-config-file produces a config file with headings for each template
+ sys.argv = ['zopeskel', '--make-config-file']
+ output = run()
+ for theading in ['[' + name + ']' for name in tempnames]:
+ self.failUnless(theading in output, '%s does not appear in .zopeskel' % theading)
+
+ # --version should output a version number. make sure it finds something
+ sys.argv = ['zopeskel', '--version']
+ output = run()
+ self.failIf('unable' in output)
+
+ sys.argv = oldargv
+
+
+
+
+
+def test_suite():
+ suite = unittest.TestSuite([
+ unittest.makeSuite(test_zopeskel)])
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskeldocs.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskeldocs.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/tests/test_zopeskeldocs.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,173 @@
+# -*- coding: utf-8 -*-
+"""
+Grabs the tests in doctest
+"""
+__docformat__ = 'restructuredtext'
+
+import unittest
+import doctest
+import sys
+import os
+import shutil
+import popen2
+import tempfile
+
+from zope.testing import doctest
+
+current_dir = os.path.abspath(os.path.dirname(__file__))
+
+def rmdir(*args):
+ dirname = os.path.join(*args)
+ if os.path.isdir(dirname):
+ shutil.rmtree(dirname)
+
+
+def paster(cmd):
+ print "paster %s" % cmd
+ from paste.script import command
+ #the overwite option for the create command defaults to True
+ #but in the paste.script.command it defaults to False.
+ #so we fixe it here
+ if 'create' in cmd:
+ cmd += " --overwrite=1"
+ args = cmd.split()
+ options, args = command.parser.parse_args(args)
+ options.base_parser = command.parser
+ command.system_plugins.extend(options.plugins or [])
+ commands = command.get_commands()
+ command_name = args[0]
+ if command_name not in commands:
+ command = command.NotFoundCommand
+ else:
+ command = commands[command_name].load()
+ runner = command(command_name)
+ runner.run(args[1:])
+
+
+def read_sh(cmd):
+ _cmd = cmd
+ old = sys.stdout
+ child_stdout_and_stderr, child_stdin = popen2.popen4(_cmd)
+ child_stdin.close()
+ return child_stdout_and_stderr.read()
+
+
+def ls(*args):
+ dirname = os.path.join(*args)
+ if os.path.isdir(dirname):
+ filenames = os.listdir(dirname)
+ for filename in sorted(filenames):
+ # Depending on how pristine your testing env is, the
+ # Paster/PasteScript eggs may end up here; this ins't
+ # very predictable. Hide them.
+ if filename.endswith('.egg'):
+ continue
+ print filename
+ else:
+ print 'No directory named %s' % dirname
+
+
+def cd(*args):
+ dirname = os.path.join(*args)
+ os.chdir(dirname)
+
+
+def config(filename):
+ return os.path.join(current_dir, filename)
+
+
+def cat(*args):
+ filename = os.path.join(*args)
+ if os.path.isfile(filename):
+ print open(filename).read()
+ else:
+ print 'No file named %s' % filename
+
+
+def touch(*args, **kwargs):
+ filename = os.path.join(*args)
+ open(filename, 'w').write(kwargs.get('data',''))
+
+
+class ZopeSkelLayer:
+
+ temp_dir = None
+
+ @classmethod
+ def testSetUp(self):
+ self.temp_dir = tempfile.mkdtemp()
+ cd(self.temp_dir)
+
+ @classmethod
+ def testTearDown(self):
+ shutil.rmtree(self.temp_dir, ignore_errors=True)
+ self.temp_dir = None
+
+ from pkg_resources import working_set as ws
+ #cleanup entries in the working set
+ for k, v in ws.by_key.items():
+ if not os.path.exists(v.location):
+ del ws.by_key[k]
+
+ for i in reversed(range(len(ws.entries))):
+ if not os.path.exists(ws.entries[i]):
+ del ws.entries[i]
+
+ sys.path = ws.entries[:]
+
+def testSetUp(test):
+ test.temp_dir = tempfile.mkdtemp()
+ cd(test.temp_dir)
+
+def testTearDown(test):
+ shutil.rmtree(test.temp_dir, ignore_errors=True)
+ test.temp_dir = None
+
+ from pkg_resources import working_set as ws
+ #cleanup entries in the working set
+ for k, v in ws.by_key.items():
+ if not os.path.exists(v.location):
+ del ws.by_key[k]
+
+ for i in reversed(range(len(ws.entries))):
+ if not os.path.exists(ws.entries[i]):
+ del ws.entries[i]
+
+ sys.path = ws.entries[:]
+
+def doc_suite(test_dir, setUp=testSetUp, tearDown=testTearDown, globs=None):
+ """Returns a test suite, based on doctests found in /docs."""
+ suite = []
+ if globs is None:
+ globs = globals()
+
+ flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE |
+ doctest.REPORT_ONLY_FIRST_FAILURE)
+
+ package_dir = os.path.split(test_dir)[0]
+ if package_dir not in sys.path:
+ sys.path.append(package_dir)
+
+ doctest_dir = os.path.join(package_dir, 'docs')
+
+ # filtering files on extension
+ docs = [os.path.join(doctest_dir, doc) for doc in
+ os.listdir(doctest_dir) if doc.endswith('.txt')]
+
+ for test in docs:
+ suite.append(doctest.DocFileSuite(test, optionflags=flags,
+ globs=globs, setUp=setUp,
+ tearDown=tearDown,
+ module_relative=False))
+
+ return unittest.TestSuite(suite)
+
+def test_suite():
+ """returns the test suite"""
+ suite = doc_suite(current_dir)
+ suite.layer = ZopeSkelLayer
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/ui.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/ui.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/ui.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,60 @@
+"""
+Module containing some common UI components that are useful for all user
+interfaces, ie the console and the web interfaces.
+"""
+import pkg_resources
+
+from zopeskel.base import BaseTemplate
+
+# These are the "common" templates; they will be listed in a separate
+# list for new users. Please be conservative about adding new
+# templates to this list--we don't want it to be overwhelming.
+# Users also see the "non-common" templates, just in a different
+# listing; this is where things like PAS plugins, special hosting,
+# Silva, etc., should remain.
+
+def list_sorted_templates(filter_group=False):
+ """
+ Returns a dictionary of template lists by category. Key is the category
+ name, value is a list of templates.
+
+ If "filter_group" is True, then this explictly filters to
+ things provided by the ZopeSkel package--thereby hiding any
+ templates the user may have on their system that sit on top
+ of zopeskel's base classes. This is required in places where
+ we want to generate canonical documents, and don't want to
+ accidentally include things from the machine it's being run
+ on.
+ """
+
+ cats = {}
+ # grab a list of all paster create template entry points
+ if filter_group:
+ t_e_ps = pkg_resources.get_entry_map(
+ 'zopeskel')['paste.paster_create_template'].values()
+ else:
+ t_e_ps = pkg_resources.iter_entry_points('paste.paster_create_template')
+ templates = []
+ for entry in t_e_ps:
+ try:
+ # We only want our templates in this list
+ template = entry.load()
+ if issubclass(template, BaseTemplate):
+ templates.append(
+ { 'name': entry.name,
+ 'summary': template.summary,
+ 'class': template,
+ 'category': getattr(template, 'category', 'Uncategorized'),
+ 'help': getattr(template, 'help', "").strip(),
+ 'entry':entry,
+ } )
+ except Exception, e:
+ # We will not be stopped!
+ print 'Warning: could not load entry point %s (%s: %s)' % (
+ entry.name, e.__class__.__name__, e)
+ templates.sort(key=lambda x: x['name'])
+
+ for entry in templates:
+ cats.setdefault(entry['category'], []).append(entry)
+
+ return cats
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/vars.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/vars.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/vars.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,203 @@
+import sys
+from paste.script.templates import var as base_var
+
+
+##########################################################################
+# Mode constants
+
+# keep these lowercased, as choicesvars are lowercased
+
+EXPERT = 'expert'
+EASY = 'easy'
+ALL = 'all'
+
+##########################################################################
+# Variable classes
+
+class ValidationException(ValueError):
+ """Invalid value provided for variable."""
+
+
+class var(base_var):
+
+ _default_widget = 'string'
+
+ def __init__(self, name, description,
+ default='', should_echo=True,
+ title=None, help=None, widget=None,
+ modes=(EASY, EXPERT), page='Main'):
+ self.name = name
+ self.description = description
+ self.default = default
+ self.should_echo = should_echo
+ self.title = title
+ self.help = help
+ if not widget:
+ self.widget = self._default_widget
+ else:
+ self.widget = widget
+ self.modes = modes
+ self.page = page
+
+ def pretty_description(self):
+ title = getattr(self, 'title', self.name) or self.name
+
+ if self.description:
+ return '%s (%s)' % (title, self.description)
+ else:
+ return title
+
+ def further_help(self):
+ """ return the help string for this class or inform user that none is
+ available
+ """
+ no_help = "Sorry, no further help is available for %s\n" % self.name
+ return self.help and self.help or no_help
+
+ def validate(self, value):
+ raise NotImplementedError
+
+
+class BooleanVar(var):
+ _default_widget = 'boolean'
+
+ def validate(self, value):
+ #Get rid of bonus whitespace
+ if isinstance(value, basestring):
+ value = value.strip().lower()
+
+ #Map special cases to correct values.
+ if value in ['t', 'y', 'yes', 'true', 1]:
+ value = True
+ elif value in ['f','n','no', 'false', 0]:
+ value = False
+
+ if type(value) != bool:
+ raise ValidationException("Not a valid boolean value: %s" % value)
+
+ return value
+
+
+class StringVar(var):
+ """Single string values."""
+
+ _default_widget = 'string'
+
+ def validate(self, value):
+ if not isinstance(value, basestring):
+ raise ValidationException("Not a string value: %s" % value)
+
+ value = value.strip()
+
+ return value
+
+class StringChoiceVar(var):
+ """Choice of strings."""
+
+ _default_widget = 'select'
+
+ def __init__(self, *args, **kwargs):
+ self.choices = kwargs['choices']
+ del kwargs['choices']
+ super(StringChoiceVar, self).__init__(*args, **kwargs)
+
+ def validate(self, value):
+ value = value.strip().lower()
+ if not value in self.choices:
+ raise ValidationException("Not a valid value: %s" % value)
+
+ return value
+
+class TextVar(StringVar):
+ """Multi-line values."""
+
+ _default_widget = 'text'
+
+
+class OnOffVar(StringVar):
+ """'On' or 'Off' text values."""
+
+ _default_widget = 'onoff'
+
+ def validate(self, value):
+ #Get rid of bonus whitespace
+ if isinstance(value, basestring):
+ value = value.strip().lower()
+
+ #Map special cases to correct values.
+ if value in ['t', 'y', 'yes', 'true', 1, 'on']:
+ value = 'on'
+ elif value in ['f','n','no', 'false', 0, 'off']:
+ value = 'off'
+ else:
+ raise ValidationException("Not a valid on/off value: %s" % value)
+
+ return value
+
+
+class IntVar(var):
+ """Integer values"""
+
+ _default_widget = 'string'
+
+ def validate(self, value):
+ try:
+ value = int(value)
+ except ValueError:
+ raise ValidationException("Not a valid int: %s" % value)
+
+ return value
+
+
+MAXINT = sys.maxint
+MININT = -MAXINT-1
+class BoundedIntVar(IntVar):
+ """Integer values with allowed maximum and minimum values"""
+
+ def __init__(self, *args, **kwargs):
+ if 'min' in kwargs:
+ self.min = kwargs.pop('min')
+ else:
+ self.min = MININT
+
+ if 'max' in kwargs:
+ self.max = kwargs.pop('max')
+ else:
+ self.max = MAXINT
+
+ super(BoundedIntVar, self).__init__(*args, **kwargs)
+
+ def validate(self, value):
+ # first validate that value is an integer
+ try:
+ val = super(BoundedIntVar, self).validate(value)
+ except ValidationException, e:
+ raise e
+
+ if not self.min <= val <= self.max:
+ msg = "%d does not fall within allowed bounds: %d:%d"
+ raise ValidationException(msg % (val, self.min, self.max))
+
+ return val
+
+
+class DottedVar(var):
+ """Variable for 'dotted Python name', eg, 'foo.bar.baz'"""
+
+ _default_widget = 'string'
+
+ def validate(self, value):
+ if not isinstance(value, basestring):
+ raise ValidationException("Not a string value: %s" % value)
+ value = value.strip()
+
+ names = value.split(".")
+ for name in names:
+ # Check if Python identifier, http://code.activestate.com/recipes/413487/
+ try:
+ class test(object): __slots__ = [name]
+ except TypeError:
+ raise ValidationException("Not a valid Python dotted name: %s ('%s' is not an identifier)" % (value, name))
+
+ return value
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zope2_buildout.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zope2_buildout.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zope2_buildout.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,51 @@
+import copy
+
+from zopeskel import abstract_buildout
+from zopeskel.base import var, EASY, EXPERT
+from zopeskel.vars import StringVar
+
+
+class Zope2Buildout(abstract_buildout.AbstractBuildout):
+ _template_dir = 'templates/zope2_buildout'
+ summary = "A buildout for a blank (non-Silva, non-Plone) Zope 2 instance"
+ help = """
+This template creates a buildout that does not contain Plone or Silva
+information. It is intended for people using Zope 2 directly. If you
+would like to use Plone or Silva, you should use the appropriate buildouts.
+"""
+ post_run_msg = """
+Generation finished.
+
+You probably want to run python bootstrap.py and then edit
+buildout.cfg before running bin/buildout -v".
+
+See README.txt for details.
+"""
+ required_templates = []
+ use_cheetah = True
+
+ vars = copy.deepcopy(abstract_buildout.AbstractBuildout.vars)
+ vars.extend([
+ abstract_buildout.VAR_Z2_INSTALL,
+ StringVar(
+ 'zope2_version',
+ title='Zope 2 Version',
+ description='Version of Zope 2 to fetch, if needed',
+ modes=(EASY, EXPERT),
+ page='Main',
+ default='2.11.1',
+ help="""
+If a version of Zope needs to be pulled down, this option lets you
+specify the version.
+"""
+ ),
+ abstract_buildout.VAR_ZOPE_USER,
+ abstract_buildout.VAR_ZOPE_PASSWD,
+ abstract_buildout.VAR_HTTP,
+ abstract_buildout.VAR_DEBUG_MODE,
+ abstract_buildout.VAR_VERBOSE_SEC,
+ ]
+ )
+
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zopeskel_script.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zopeskel_script.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/ZopeSkel-2.19-py2.6.egg/zopeskel/zopeskel_script.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,399 @@
+import sys
+import pkg_resources
+from cStringIO import StringIO
+from textwrap import TextWrapper
+from zopeskel.base import wrap_help_paras
+from paste.script.command import get_commands
+
+from zopeskel.ui import list_sorted_templates
+
+USAGE = """
+Usage:
+
+ zopeskel <template> <output-name> [var1=value] ... [varN=value]
+
+ zopeskel --help Full help
+ zopeskel --list List template verbosely, with details
+ zopeskel --make-config-file Output .zopeskel prefs file
+ zopeskel --version Print installed version
+
+%s
+Warning: use of the --svn-repository argument is not allowed with this script
+
+For further help information, please invoke this script with the
+option "--help".
+"""
+
+DESCRIPTION = """
+This script allows you to create basic skeletons for plone and zope
+products and buildouts based on best-practice templates.
+
+It is a wrapper around PasteScript ("paster"), providing an easier
+syntax for invoking and better help.
+
+
+Invoking this script
+--------------------
+
+Basic usage::
+
+ zopeskel <template>
+
+(To get a list of the templates, run the script without any arguments;
+for a verbose list with full descriptions, run the ``zopeskel --list``)
+
+For example::
+
+ zopeskel archetypes
+
+To create an Archetypes-based product for Plone. This will prompt you
+for the name of your product, and for other information about it.
+
+If you to specify your output name (resulting product, egg, or buildout,
+depending on the template being used), you can also do so::
+
+ zopeskel <template> <output-name>
+
+For example::
+
+ zopeskel archetypes Products.Example
+
+In addition, you can pass variables to this that would be requested
+by that template, and these will then be used. This is an advanced
+feature mostly useful for scripted use of this::
+
+ zopeskel archetypes Products.Example author_email=joel at joelburton.com
+
+(You can specify as many of these as you want, in name=value pairs.
+To get the list of variables that a template expects, you can ask for
+this with ``paster create -t <template-name> --list-variables``).
+
+
+Interactive Help
+----------------
+
+While being prompted on each question, you can enter with a single
+question mark to receive interactive help for that question.
+
+For example::
+
+ Description (One-line description of the project) ['']: ?
+
+ | This should be a single-line description of your project. It will
+ | be used in the egg's setup.py, and, for Zope/Plone projects, may be
+ | used in the GenericSetup profile description.
+
+
+Providing defaults
+------------------
+
+It is also possible to set up default values to be used for any template by
+creating a file called ``.zopeskel`` in your home directory. This file
+should be in INI format.
+
+For example, our ``$HOME/.zopeskel`` could contain::
+
+ [DEFAULT]
+ author_email = joel at joelburton.com
+ license_name = GPL
+ master_keywords = my common keywords here
+
+ [plone3_theme]
+ empty_styles = False
+ license_name = BSD
+ keywords = %(master_keywords)s additional keywords
+
+You can generate a starter .zopeskel file by running this script with
+the --make-config-file option. This output can be redirected into
+your ``.zopeskel`` file::
+
+ bin/zopeskel --make-config-file > /path/to/home/.zopeskel
+
+Notes:
+
+1) "empty_styles" applies only to themes; we can make this setting
+ in the template-specific section of this file. This setting will
+ not be used for other templates.
+
+2) For a common setting, like our email address, we can set this in
+ a section called DEFAULT; settings made in this section are used
+ for all templates.
+
+3) We can make a setting in DEFAULT and then override it for a
+ particular template. In this example, we might generally prefer the GPL,
+ but issue our themes under the BSD license.
+
+4) You can refer to variables from the same section or from the
+ DEFAULT section using Python string formatting. In this example,
+ we have a common set of keywords set in DEFAULT and extend it
+ for the theming template by referring to the master list.
+
+
+Differences from the 'paster create' command
+--------------------------------------------
+
+1) The --svn-repository argument that can be provided to 'paster create' is not
+ allowed when using the zopeskel script. It will raise an error. The reasons
+ for this are discussed at length in the zopeskel mailing list and in the
+ zopeskel issue tracker:
+ http://plone.org/products/zopeskel/issues/34
+ http://plone.org/products/zopeskel/issues/35
+
+ If this argument is desired, the user should revert to calling 'paster create'
+ directly. However, be warned that buildout templates will not work with the
+ argument due to assumptions in the base paster code.
+
+
+Questions
+---------
+
+If you have further questions about the usage of bin/zopeskel, please feel
+free to post your questions to the zopeskel mailing list or jump onto the
+plone IRC channel (#plone) at irc.freenode.net.
+
+
+To see the templates supported, run this script without any options.
+For a verbose listing with help, use ``zopeskel --list``.
+"""
+
+DOT_HELP = {
+ 0: """
+This template expects a project name with no dots in it (a simple
+Python package name, like 'foo').
+""",
+ 1: """
+This template expects a project name with 1 dot in it (a 'basic
+namespace', like 'foo.bar').
+""",
+ 2: """
+This template expects a project name with 2 dots in it (a 'nested
+namespace', like 'foo.bar.baz').
+"""
+}
+
+def checkdots(template, name):
+ """Check if project name appears legal, given template requirements.
+
+ Templates can provide number of namespaces they expect (provided
+ in 'ndots' attributes for number-of-dots in name). This checks that
+ provided project name is has correct number of namespaces and that
+ each part is a legal Python identifier.
+ """
+
+ ndots = getattr(template, 'ndots', None)
+ if ndots is None: return # No validation possible
+
+ cdots = name.count(".")
+ if ndots != cdots:
+ raise ValueError(
+ "Project name expected %i dots, supplied '%s' has %i dots" % (
+ ndots, name, cdots))
+ for part in name.split("."):
+ # Check if Python identifier, http://code.activestate.com/recipes/413487/
+ try:
+ class test(object): __slots__ = [part]
+ except TypeError:
+ raise ValueError(
+ "Not a valid Python dotted name: %s ('%s' is not an identifier)" % (name, part))
+
+
+
+def usage():
+ templates = list_printable_templates()
+ print USAGE % templates
+
+def show_help():
+ print DESCRIPTION
+
+def show_version():
+ try:
+ dist = pkg_resources.get_distribution('zopeskel')
+ print dist.version
+ except pkg_resources.DistributionNotFound:
+ print 'unable to identify zopeskel version'
+
+def list_verbose():
+ """List templates verbosely, with full help."""
+
+ textwrapper = TextWrapper(
+ initial_indent=" ", subsequent_indent=" ")
+ cats = list_sorted_templates()
+
+ for title, items in cats.items():
+ print "\n"+ title
+ print "-" * len(title)
+ for temp in items:
+ print "\n%s: %s\n" % (temp['name'], temp['summary'])
+ if temp['help']:
+ wrap_help_paras(textwrapper, temp['help'])
+ print
+
+
+def list_printable_templates():
+ """
+ Printable list of all templates, sorted into two categories.
+ """
+
+ s = StringIO()
+
+ cats = list_sorted_templates()
+ templates = sum(cats.values(), []) # flatten into single list
+ max_name = max([len(x['name']) for x in templates])
+
+ for title, items in cats.items():
+ print >>s, "\n%s\n" % title
+ for entry in items:
+ print >>s, "| %s:%s %s\n" % (
+ entry['name'],
+ ' '*(max_name-len(entry['name'])),
+ entry['summary']),
+
+ s.seek(0)
+ return s.read()
+
+
+def generate_dotzopeskel():
+ """Make an example .zopeskel file for user."""
+
+ cats = list_sorted_templates()
+ print """
+
+# This file can contain preferences for zopeskel.
+# To do so, uncomment the lines that look like:
+# variable_name = Default Value
+
+[DEFAULT]
+"""
+ for temp in sum(cats.values(), []):
+ print "\n[%(name)s]\n" % temp
+ tempc = temp['entry'].load()
+ for var in tempc.vars:
+ if hasattr(var, 'pretty_description'):
+ print "# %s" % var.pretty_description()
+ print "# %s = %s\n" % ( var.name, var.default )
+
+def process_args():
+ """ return a tuple of template_name, output_name and everything else
+
+ everything else will be returned as a dictionary of key/value pairs
+ """
+ args = sys.argv[1:]
+ try:
+ template_name = args.pop(0)
+ except IndexError:
+ raise SyntaxError('No template name provided')
+ output_name = None
+ others = {}
+ for arg in args:
+ eq_index = arg.find('=')
+ if eq_index == -1 and not output_name:
+ output_name = arg
+ elif eq_index > 0:
+ key, val = arg.split('=')
+ # the --svn-repository argument to paster does some things that cause
+ # it to be pretty much incompatible with zopeskel. See the following
+ # zopeskel issues:
+ # http://plone.org/products/zopeskel/issues/35
+ # http://plone.org/products/zopeskel/issues/34
+ # For this reason, we are going to disallow using the --svn-repository
+ # argument when using the zopeskel wrapper. Those who wish to use it
+ # can still do so by going back to paster, with the caveat that there
+ # are some templates (particularly the buildout ones) for which the
+ # argument will always throw errors (at least until the problems are
+ # fixed upstream in paster itself).
+ if 'svn-repository' in key:
+ msg = 'for a number of reasons, the --svn-repository argument '
+ msg += 'is not allowed with the zopeskel script. '
+ msg += "Try --help for more information"
+ raise SyntaxError(msg)
+ others[key] = val
+ else:
+ raise SyntaxError(arg)
+
+
+
+ return template_name, output_name, others
+
+def run():
+ """ """
+
+ if "--help" in sys.argv:
+ show_help()
+ return
+
+ if "--make-config-file" in sys.argv:
+ generate_dotzopeskel()
+ return
+
+ if "--list" in sys.argv:
+ list_verbose()
+ return
+
+ if "--version" in sys.argv:
+ show_version()
+ return
+
+ if len(sys.argv) == 1:
+ usage()
+ return
+
+ try:
+ template_name, output_name, opts = process_args()
+ except SyntaxError, e:
+ usage()
+ print "ERROR: There was a problem with your arguments: %s\n" % e
+ return
+
+ rez = pkg_resources.iter_entry_points(
+ 'paste.paster_create_template',
+ template_name)
+ rez = list(rez)
+ if not rez:
+ usage()
+ print "ERROR: No such template: %s\n" % template_name
+ return
+
+ template = rez[0].load()
+
+ print "\n%s: %s" % (template_name, template.summary)
+ help = getattr(template, 'help', None)
+ if help:
+ print template.help
+
+ create = get_commands()['create'].load()
+
+ command = create('create')
+
+ if output_name:
+ try:
+ checkdots(template, output_name)
+ except ValueError, e:
+ print "ERROR: %s\n" % e
+ return
+
+ else:
+ ndots = getattr(template, 'ndots', None)
+ help = DOT_HELP.get(ndots)
+
+ while True:
+ if help: print help
+ try:
+ output_name = command.challenge("Enter project name")
+ checkdots(template, output_name)
+ except ValueError, e:
+ print "\nERROR: %s" % e
+ else:
+ break
+
+
+ print """
+If at any point, you need additional help for a question, you can enter
+'?' and press RETURN.
+"""
+
+ optslist = [ '%s=%s' % (k,v) for k, v in opts.items() ]
+ if output_name is not None:
+ optslist.insert(0, output_name)
+ command.run( [ '-q', '-t', template_name ] + optslist )
+
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/easy-install.pth
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/easy-install.pth (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/easy-install.pth 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,9 @@
+import sys; sys.__plen = len(sys.path)
+./setuptools-0.6c11-py2.6.egg
+./pip-0.7.2-py2.6.egg
+./ZopeSkel-2.19-py2.6.egg
+./Cheetah-2.2.1-py2.6-linux-x86_64.egg
+./PasteScript-1.7.3-py2.6.egg
+./PasteDeploy-1.3.4-py2.6.egg
+./Paste-1.7.5.1-py2.6.egg
+import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/PKG-INFO
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/PKG-INFO (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/PKG-INFO 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,310 @@
+Metadata-Version: 1.0
+Name: pip
+Version: 0.7.2
+Summary: pip installs packages. Python packages. An easy_install replacement
+Home-page: http://pip.openplans.org
+Author: The Open Planning Project
+Author-email: python-virtualenv at groups.google.com
+License: MIT
+Description: The main website for pip is `pip.openplans.org
+ <http://pip.openplans.org>`_. You can also install
+ the `in-development version <http://bitbucket.org/ianb/pip/get/tip.gz#egg=pip-dev>`_
+ of pip with ``easy_install pip==dev``.
+
+
+ Introduction
+ ------------
+
+ pip is a replacement for `easy_install
+ <http://peak.telecommunity.com/DevCenter/EasyInstall>`_. It uses mostly the
+ same techniques for finding packages, so packages that were made
+ easy_installable should be pip-installable as well.
+
+ pip is meant to improve on easy_install. Some of the improvements:
+
+ * All packages are downloaded before installation. Partially-completed
+ installation doesn't occur as a result.
+
+ * Care is taken to present useful output on the console.
+
+ * The reasons for actions are kept track of. For instance, if a package is
+ being installed, pip keeps track of why that package was required.
+
+ * Error messages should be useful.
+
+ * The code is relatively concise and cohesive, making it easier to use
+ programmatically.
+
+ * Packages don't have to be installed as egg archives, they can be installed
+ flat (while keeping the egg metadata).
+
+ * Native support for other version control systems (Git, Mercurial and Bazaar)
+
+ * Uninstallation of packages.
+
+ * Simple to define fixed sets of requirements and reliably reproduce a
+ set of packages.
+
+ pip is complementary with `virtualenv
+ <http://pypi.python.org/pypi/virtualenv>`_, and it is encouraged that you use
+ virtualenv to isolate your installation.
+
+ Community
+ ---------
+
+ The homepage for pip is temporarily located `on PyPI
+ <http://pypi.python.org/pypi/pip>`_ -- a more proper homepage will
+ follow. Bugs can go on the `pip issue tracker
+ <http://bitbucket.org/ianb/pip/issues/>`_. Discussion should happen on the
+ `virtualenv email group
+ <http://groups.google.com/group/python-virtualenv?hl=en>`_.
+
+ Differences From easy_install
+ -----------------------------
+
+ pip cannot install some packages. Specifically:
+
+ * It cannot install from eggs. It only installs from source. (In the future it would be good if it could install binaries from Windows ``.exe`` or ``.msi`` -- binary install on other platforms is not a priority.)
+
+ * It doesn't understand Setuptools extras (like ``package[test]``). This should
+ be added eventually.
+
+ * It is incompatible with some packages that customize distutils or setuptools
+ in their ``setup.py`` files.
+
+ * Maybe it doesn't work on Windows. At least, the author doesn't test on
+ Windows often.
+
+ * It also has some extra features. Extra features the author thinks are great.
+
+ Uninstall
+ ---------
+
+ pip is able to uninstall most installed packages with ``pip uninstall
+ package-name``.
+
+ Known exceptions include pure-distutils packages installed with
+ ``python setup.py install`` (such packages leave behind no metadata allowing
+ determination of what files were installed), and script wrappers installed
+ by develop-installs (``python setup.py develop``).
+
+ pip also performs an automatic uninstall of an old version of a package
+ before upgrading to a newer version, so outdated files (and egg-info data)
+ from conflicting versions aren't left hanging around to cause trouble. The
+ old version of the package is automatically restored if the new version
+ fails to download or install.
+
+ .. _`requirements file`:
+
+ Requirements Files
+ ------------------
+
+ When installing software, and Python packages in particular, it's common that
+ you get a lot of libraries installed. You just did ``easy_install MyPackage``
+ and you get a dozen packages. Each of these packages has its own version.
+
+ Maybe you ran that installation and it works. Great! Will it keep working?
+ Did you have to provide special options to get it to find everything? Did you
+ have to install a bunch of other optional pieces? Most of all, will you be able
+ to do it again? Requirements files give you a way to create an *environment*:
+ a *set* of packages that work together.
+
+ If you've ever tried to setup an application on a new system, or with slightly
+ updated pieces, and had it fail, pip requirements are for you. If you
+ haven't had this problem then you will eventually, so pip requirements are
+ for you too -- requirements make explicit, repeatable installation of packages.
+
+ So what are requirements files? They are very simple: lists of packages to
+ install. Instead of running something like ``pip MyApp`` and getting
+ whatever libraries come along, you can create a requirements file something like::
+
+ MyApp
+ Framework==0.9.4
+ Library>=0.2
+
+ Then, regardless of what MyApp lists in ``setup.py``, you'll get a
+ specific version of Framework (0.9.4) and at least the 0.2 version of
+ Library. (You might think you could list these specific versions in
+ MyApp's ``setup.py`` -- but if you do that you'll have to edit MyApp
+ if you want to try a new version of Framework, or release a new
+ version of MyApp if you determine that Library 0.3 doesn't work with
+ your application.) You can also add optional libraries and support
+ tools that MyApp doesn't strictly require, giving people a set of
+ recommended libraries.
+
+ You can also include "editable" packages -- packages that are checked out from
+ Subversion, Git, Mercurial and Bazaar. These are just like using the ``-e``
+ option to pip. They look like::
+
+ -e svn+http://myrepo/svn/MyApp#egg=MyApp
+
+ You have to start the URL with ``svn+`` (``git+``, ``hg+`` or ``bzr+``), and
+ you have to include ``#egg=Package`` so pip knows what to expect at that URL.
+ You can also include ``@rev`` in the URL, e.g., ``@275`` to check out
+ revision 275.
+
+ Requirement files are mostly *flat*. Maybe ``MyApp`` requires
+ ``Framework``, and ``Framework`` requires ``Library``. I encourage
+ you to still list all these in a single requirement file; it is the
+ nature of Python programs that there are implicit bindings *directly*
+ between MyApp and Library. For instance, Framework might expose one
+ of Library's objects, and so if Library is updated it might directly
+ break MyApp. If that happens you can update the requirements file to
+ force an earlier version of Library, and you can do that without
+ having to re-release MyApp at all.
+
+ Read the `requirements file format <requirement-format.html>`_ to
+ learn about other features.
+
+ Freezing Requirements
+ ---------------------
+
+ So you have a working set of packages, and you want to be able to install them
+ elsewhere. `Requirements files`_ let you install exact versions, but it won't
+ tell you what all the exact versions are.
+
+ To create a new requirements file from a known working environment, use::
+
+ $ pip freeze > stable-req.txt
+
+ This will write a listing of *all* installed libraries to ``stable-req.txt``
+ with exact versions for every library. You may want to edit the file down after
+ generating (e.g., to eliminate unnecessary libraries), but it'll give you a
+ stable starting point for constructing your requirements file.
+
+ You can also give it an existing requirements file, and it will use that as a
+ sort of template for the new file. So if you do::
+
+ $ pip freeze -r devel-req.txt > stable-req.txt
+
+ it will keep the packages listed in ``devel-req.txt`` in order and preserve
+ comments.
+
+ Bundles
+ -------
+
+ Another way to distribute a set of libraries is a bundle format (specific to
+ pip). This format is not stable at this time (there simply hasn't been
+ any feedback, nor a great deal of thought). A bundle file contains all the
+ source for your package, and you can have pip install them all together.
+ Once you have the bundle file further network access won't be necessary. To
+ build a bundle file, do::
+
+ $ pip bundle MyApp.pybundle MyApp
+
+ (Using a `requirements file`_ would be wise.) Then someone else can get the
+ file ``MyApp.pybundle`` and run::
+
+ $ pip install MyApp.pybundle
+
+ This is *not* a binary format. This only packages source. If you have binary
+ packages, then the person who installs the files will have to have a compiler,
+ any necessary headers installed, etc. Binary packages are hard, this is
+ relatively easy.
+
+ Using pip with virtualenv
+ -------------------------
+
+ pip is most nutritious when used with `virtualenv
+ <http://pypi.python.org/pypi/virtualenv>`_. One of the reasons pip
+ doesn't install "multi-version" eggs is that virtualenv removes much of the need
+ for it.
+
+ pip does not have to be installed to use it, you can run ``python
+ path/to/pip.py`` and it will work. This is intended to avoid the
+ bootstrapping problem of installation. You can also run pip inside
+ any virtualenv environment, like::
+
+ $ virtualenv new-env/
+ ... creates new-env/ ...
+ $ pip install -E new-env/ MyPackage
+
+ This is exactly equivalent to::
+
+ $ ./new-env/bin/python path/to/pip.py install MyPackage
+
+ Except, if you have ``virtualenv`` installed and the path ``new-env/``
+ doesn't exist, then a new virtualenv will be created.
+
+ pip also has two advanced features for working with virtualenvs -- both of
+ which activated by defining a variable in your environment.
+
+ To tell pip to only run if there is a virtualenv currently activated,
+ and to bail if not, use::
+
+ export PIP_REQUIRE_VIRTUALENV=true
+
+ To tell pip to automatically use the currently active virtualenv::
+
+ export PIP_RESPECT_VIRTUALENV=true
+
+ Providing an environment with ``-E`` will be ignored.
+
+ Using pip with virtualenvwrapper
+ ---------------------------------
+
+ If you are using `virtualenvwrapper
+ <http://www.doughellmann.com/projects/virtualenvwrapper/>`_, you might
+ want pip to automatically create its virtualenvs in your
+ ``$WORKON_HOME``.
+
+ You can tell pip to do so by defining ``PIP_VIRTUALENV_BASE`` in your
+ environment and setting it to the same value as that of
+ ``$WORKON_HOME``.
+
+ Do so by adding the line::
+
+ export PIP_VIRTUALENV_BASE=$WORKON_HOME
+
+ in your .bashrc under the line starting with ``export WORKON_HOME``.
+
+ Using pip with buildout
+ -----------------------
+
+ If you are using `zc.buildout
+ <http://pypi.python.org/pypi/zc.buildout>`_ you should look at
+ `gp.recipe.pip <http://pypi.python.org/pypi/gp.recipe.pip>`_ as an
+ option to use pip and virtualenv in your buildouts.
+
+ Command line completion
+ -----------------------
+
+ pip comes with support for command line completion in bash and zsh and
+ allows you tab complete commands and options. To enable it you simply
+ need copy the required shell script to the your shell startup file
+ (e.g. ``.profile`` or ``.zprofile``) by running the special ``completion``
+ command, e.g. for bash::
+
+ $ pip completion --bash >> ~/.profile
+
+ And for zsh::
+
+ $ pip completion --zsh >> ~/.zprofile
+
+ Alternatively, you can use the result of the ``completion`` command
+ directly with the eval function of you shell, e.g. by adding::
+
+ eval `pip completion --bash`
+
+ to your startup file.
+
+ Searching for packages
+ ----------------------
+
+ pip can search the `Python Package Index <http://pypi.python.org/pypi>`_ (PyPI)
+ for packages using the ``pip search`` command. To search, run::
+
+ $ pip search "query"
+
+ The query will be used to search the names and summaries of all packages
+ indexed.
+
+ pip searches http://pypi.python.org/pypi by default but alternative indexes
+ can be searched by using the ``--index`` flag.
+
+Keywords: easy_install distutils setuptools egg virtualenv
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: Software Development :: Build Tools
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/SOURCES.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/SOURCES.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/SOURCES.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,42 @@
+MANIFEST.in
+setup.cfg
+setup.py
+docs/branches.txt
+docs/configuration.txt
+docs/index.txt
+docs/license.txt
+docs/news.txt
+docs/requirement-format.txt
+pip/__init__.py
+pip/backwardcompat.py
+pip/basecommand.py
+pip/baseparser.py
+pip/exceptions.py
+pip/index.py
+pip/locations.py
+pip/log.py
+pip/req.py
+pip/runner.py
+pip/util.py
+pip/venv.py
+pip.egg-info/PKG-INFO
+pip.egg-info/SOURCES.txt
+pip.egg-info/dependency_links.txt
+pip.egg-info/entry_points.txt
+pip.egg-info/not-zip-safe
+pip.egg-info/top_level.txt
+pip/commands/__init__.py
+pip/commands/bundle.py
+pip/commands/completion.py
+pip/commands/freeze.py
+pip/commands/help.py
+pip/commands/install.py
+pip/commands/search.py
+pip/commands/uninstall.py
+pip/commands/unzip.py
+pip/commands/zip.py
+pip/vcs/__init__.py
+pip/vcs/bazaar.py
+pip/vcs/git.py
+pip/vcs/mercurial.py
+pip/vcs/subversion.py
\ No newline at end of file
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/dependency_links.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/dependency_links.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/dependency_links.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/entry_points.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/entry_points.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/entry_points.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,3 @@
+[console_scripts]
+pip = pip:main
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/not-zip-safe
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/not-zip-safe (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/not-zip-safe 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/top_level.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/top_level.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/top_level.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+pip
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+import sys
+import os
+import optparse
+import subprocess
+import re
+from pip.log import logger
+from pip.baseparser import parser
+from pip.exceptions import InstallationError
+from pip.basecommand import command_dict, load_command, load_all_commands
+from pip.vcs import vcs, get_src_requirement, import_vcs_support
+from pip.util import get_installed_distributions
+
+def autocomplete():
+ """Command and option completion for the main option parser (and options)
+ and its subcommands (and options).
+
+ Enable by sourcing one of the completion shell scripts (bash or zsh).
+ """
+ # Don't complete if user hasn't sourced bash_completion file.
+ if not os.environ.has_key('PIP_AUTO_COMPLETE'):
+ return
+ cwords = os.environ['COMP_WORDS'].split()[1:]
+ cword = int(os.environ['COMP_CWORD'])
+ try:
+ current = cwords[cword-1]
+ except IndexError:
+ current = ''
+ load_all_commands()
+ subcommands = [cmd for cmd, cls in command_dict.items() if not cls.hidden]
+ options = []
+ # subcommand
+ try:
+ subcommand_name = [w for w in cwords if w in subcommands][0]
+ except IndexError:
+ subcommand_name = None
+ # subcommand options
+ if subcommand_name:
+ # special case: 'help' subcommand has no options
+ if subcommand_name == 'help':
+ sys.exit(1)
+ # special case: list locally installed dists for uninstall command
+ if subcommand_name == 'uninstall' and not current.startswith('-'):
+ installed = []
+ lc = current.lower()
+ for dist in get_installed_distributions(local_only=True):
+ if dist.key.startswith(lc) and dist.key not in cwords[1:]:
+ installed.append(dist.key)
+ # if there are no dists installed, fall back to option completion
+ if installed:
+ for dist in installed:
+ print dist
+ sys.exit(1)
+ subcommand = command_dict.get(subcommand_name)
+ options += [(opt.get_opt_string(), opt.nargs)
+ for opt in subcommand.parser.option_list
+ if opt.help != optparse.SUPPRESS_HELP]
+ # filter out previously specified options from available options
+ prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
+ options = filter(lambda (x, v): x not in prev_opts, options)
+ # filter options by current input
+ options = [(k, v) for k, v in options if k.startswith(current)]
+ for option in options:
+ opt_label = option[0]
+ # append '=' to options which require args
+ if option[1]:
+ opt_label += '='
+ print opt_label
+ else:
+ # show options of main parser only when necessary
+ if current.startswith('-') or current.startswith('--'):
+ subcommands += [opt.get_opt_string()
+ for opt in parser.option_list
+ if opt.help != optparse.SUPPRESS_HELP]
+ print ' '.join(filter(lambda x: x.startswith(current), subcommands))
+ sys.exit(1)
+
+def main(initial_args=None):
+ if initial_args is None:
+ initial_args = sys.argv[1:]
+ autocomplete()
+ options, args = parser.parse_args(initial_args)
+ if options.help and not args:
+ args = ['help']
+ if not args:
+ parser.error('You must give a command (use "pip help" see a list of commands)')
+ command = args[0].lower()
+ load_command(command)
+ ## FIXME: search for a command match?
+ if command not in command_dict:
+ parser.error('No command by the name %(script)s %(arg)s\n (maybe you meant "%(script)s install %(arg)s")'
+ % dict(script=os.path.basename(sys.argv[0]), arg=command))
+ command = command_dict[command]
+ return command.main(initial_args, args[1:], options)
+
+
+############################################################
+## Writing freeze files
+
+
+class FrozenRequirement(object):
+
+ def __init__(self, name, req, editable, comments=()):
+ self.name = name
+ self.req = req
+ self.editable = editable
+ self.comments = comments
+
+ _rev_re = re.compile(r'-r(\d+)$')
+ _date_re = re.compile(r'-(20\d\d\d\d\d\d)$')
+
+ @classmethod
+ def from_dist(cls, dist, dependency_links, find_tags=False):
+ location = os.path.normcase(os.path.abspath(dist.location))
+ comments = []
+ if vcs.get_backend_name(location):
+ editable = True
+ req = get_src_requirement(dist, location, find_tags)
+ if req is None:
+ logger.warn('Could not determine repository location of %s' % location)
+ comments.append('## !! Could not determine repository location')
+ req = dist.as_requirement()
+ editable = False
+ else:
+ editable = False
+ req = dist.as_requirement()
+ specs = req.specs
+ assert len(specs) == 1 and specs[0][0] == '=='
+ version = specs[0][1]
+ ver_match = cls._rev_re.search(version)
+ date_match = cls._date_re.search(version)
+ if ver_match or date_match:
+ svn_backend = vcs.get_backend('svn')
+ if svn_backend:
+ svn_location = svn_backend(
+ ).get_location(dist, dependency_links)
+ if not svn_location:
+ logger.warn(
+ 'Warning: cannot find svn location for %s' % req)
+ comments.append('## FIXME: could not find svn URL in dependency_links for this package:')
+ else:
+ comments.append('# Installing as editable to satisfy requirement %s:' % req)
+ if ver_match:
+ rev = ver_match.group(1)
+ else:
+ rev = '{%s}' % date_match.group(1)
+ editable = True
+ req = 'svn+%s@%s#egg=%s' % (svn_location, rev, cls.egg_name(dist))
+ return cls(dist.project_name, req, editable, comments)
+
+ @staticmethod
+ def egg_name(dist):
+ name = dist.egg_name()
+ match = re.search(r'-py\d\.\d$', name)
+ if match:
+ name = name[:match.start()]
+ return name
+
+ def __str__(self):
+ req = self.req
+ if self.editable:
+ req = '-e %s' % req
+ return '\n'.join(list(self.comments)+[str(req)])+'\n'
+
+############################################################
+## Requirement files
+
+
+def call_subprocess(cmd, show_stdout=True,
+ filter_stdout=None, cwd=None,
+ raise_on_returncode=True,
+ command_level=logger.DEBUG, command_desc=None,
+ extra_environ=None):
+ if command_desc is None:
+ cmd_parts = []
+ for part in cmd:
+ if ' ' in part or '\n' in part or '"' in part or "'" in part:
+ part = '"%s"' % part.replace('"', '\\"')
+ cmd_parts.append(part)
+ command_desc = ' '.join(cmd_parts)
+ if show_stdout:
+ stdout = None
+ else:
+ stdout = subprocess.PIPE
+ logger.log(command_level, "Running command %s" % command_desc)
+ env = os.environ.copy()
+ if extra_environ:
+ env.update(extra_environ)
+ try:
+ proc = subprocess.Popen(
+ cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
+ cwd=cwd, env=env)
+ except Exception, e:
+ logger.fatal(
+ "Error %s while executing command %s" % (e, command_desc))
+ raise
+ all_output = []
+ if stdout is not None:
+ stdout = proc.stdout
+ while 1:
+ line = stdout.readline()
+ if not line:
+ break
+ line = line.rstrip()
+ all_output.append(line + '\n')
+ if filter_stdout:
+ level = filter_stdout(line)
+ if isinstance(level, tuple):
+ level, line = level
+ logger.log(level, line)
+ if not logger.stdout_level_matches(level):
+ logger.show_progress()
+ else:
+ logger.info(line)
+ else:
+ returned_stdout, returned_stderr = proc.communicate()
+ all_output = [returned_stdout or '']
+ proc.wait()
+ if proc.returncode:
+ if raise_on_returncode:
+ if all_output:
+ logger.notify('Complete output from command %s:' % command_desc)
+ logger.notify('\n'.join(all_output) + '\n----------------------------------------')
+ raise InstallationError(
+ "Command %s failed with error code %s"
+ % (command_desc, proc.returncode))
+ else:
+ logger.warn(
+ "Command %s had error code %s"
+ % (command_desc, proc.returncode))
+ if stdout is not None:
+ return ''.join(all_output)
+
+import_vcs_support()
+
+if __name__ == '__main__':
+ exit = main()
+ if exit:
+ sys.exit(exit)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,22 @@
+"""Stuff that isn't in some old versions of Python"""
+
+__all__ = ['any', 'WindowsError', 'md5']
+
+try:
+ WindowsError = WindowsError
+except NameError:
+ WindowsError = None
+try:
+ from hashlib import md5
+except ImportError:
+ import md5 as md5_module
+ md5 = md5_module.new
+
+try:
+ any = any
+except NameError:
+ def any(seq):
+ for item in seq:
+ if item:
+ return True
+ return False
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,221 @@
+"""Base Command class, and related routines"""
+
+import sys
+import os
+import socket
+import urllib2
+import urllib
+from cStringIO import StringIO
+import traceback
+import time
+from pip.log import logger
+from pip.baseparser import parser, ConfigOptionParser, UpdatingDefaultsHelpFormatter
+from pip.exceptions import BadCommand, InstallationError, UninstallationError
+from pip.venv import restart_in_venv
+
+__all__ = ['command_dict', 'Command', 'load_all_commands',
+ 'load_command', 'command_names']
+
+command_dict = {}
+
+class Command(object):
+ name = None
+ usage = None
+ hidden = False
+ def __init__(self):
+ assert self.name
+ self.parser = ConfigOptionParser(
+ usage=self.usage,
+ prog='%s %s' % (sys.argv[0], self.name),
+ version=parser.version,
+ formatter=UpdatingDefaultsHelpFormatter(),
+ name=self.name)
+ for option in parser.option_list:
+ if not option.dest or option.dest == 'help':
+ # -h, --version, etc
+ continue
+ self.parser.add_option(option)
+ command_dict[self.name] = self
+
+ def merge_options(self, initial_options, options):
+ # Make sure we have all global options carried over
+ for attr in ['log', 'venv', 'proxy', 'venv_base', 'require_venv',
+ 'respect_venv', 'log_explicit_levels', 'log_file',
+ 'timeout', 'default_vcs', 'skip_requirements_regex']:
+ setattr(options, attr, getattr(initial_options, attr) or getattr(options, attr))
+ options.quiet += initial_options.quiet
+ options.verbose += initial_options.verbose
+
+ def setup_logging(self):
+ pass
+
+ def main(self, complete_args, args, initial_options):
+ options, args = self.parser.parse_args(args)
+ self.merge_options(initial_options, options)
+
+ level = 1 # Notify
+ level += options.verbose
+ level -= options.quiet
+ level = logger.level_for_integer(4-level)
+ complete_log = []
+ logger.consumers.extend(
+ [(level, sys.stdout),
+ (logger.DEBUG, complete_log.append)])
+ if options.log_explicit_levels:
+ logger.explicit_levels = True
+
+ self.setup_logging()
+
+ if options.require_venv and not options.venv:
+ # If a venv is required check if it can really be found
+ if not os.environ.get('VIRTUAL_ENV'):
+ logger.fatal('Could not find an activated virtualenv (required).')
+ sys.exit(3)
+ # Automatically install in currently activated venv if required
+ options.respect_venv = True
+
+ if args and args[-1] == '___VENV_RESTART___':
+ ## FIXME: We don't do anything this this value yet:
+ venv_location = args[-2]
+ args = args[:-2]
+ options.venv = None
+ else:
+ # If given the option to respect the activated environment
+ # check if no venv is given as a command line parameter
+ if options.respect_venv and os.environ.get('VIRTUAL_ENV'):
+ if options.venv and os.path.exists(options.venv):
+ # Make sure command line venv and environmental are the same
+ if (os.path.realpath(os.path.expanduser(options.venv)) !=
+ os.path.realpath(os.environ.get('VIRTUAL_ENV'))):
+ logger.fatal("Given virtualenv (%s) doesn't match "
+ "currently activated virtualenv (%s)."
+ % (options.venv, os.environ.get('VIRTUAL_ENV')))
+ sys.exit(3)
+ else:
+ options.venv = os.environ.get('VIRTUAL_ENV')
+ logger.info('Using already activated environment %s' % options.venv)
+ if options.venv:
+ logger.info('Running in environment %s' % options.venv)
+ site_packages=False
+ if options.site_packages:
+ site_packages=True
+ restart_in_venv(options.venv, options.venv_base, site_packages,
+ complete_args)
+ # restart_in_venv should actually never return, but for clarity...
+ return
+
+ ## FIXME: not sure if this sure come before or after venv restart
+ if options.log:
+ log_fp = open_logfile(options.log, 'a')
+ logger.consumers.append((logger.DEBUG, log_fp))
+ else:
+ log_fp = None
+
+ socket.setdefaulttimeout(options.timeout or None)
+
+ setup_proxy_handler(options.proxy)
+
+ exit = 0
+ try:
+ self.run(options, args)
+ except (InstallationError, UninstallationError), e:
+ logger.fatal(str(e))
+ logger.info('Exception information:\n%s' % format_exc())
+ exit = 1
+ except BadCommand, e:
+ logger.fatal(str(e))
+ logger.info('Exception information:\n%s' % format_exc())
+ exit = 1
+ except:
+ logger.fatal('Exception:\n%s' % format_exc())
+ exit = 2
+
+ if log_fp is not None:
+ log_fp.close()
+ if exit:
+ log_fn = options.log_file
+ text = '\n'.join(complete_log)
+ logger.fatal('Storing complete log in %s' % log_fn)
+ log_fp = open_logfile(log_fn, 'w')
+ log_fp.write(text)
+ log_fp.close()
+ return exit
+
+## FIXME: should get moved somewhere else:
+def setup_proxy_handler(proxystr=''):
+ """Set the proxy handler given the option passed on the command
+ line. If an empty string is passed it looks at the HTTP_PROXY
+ environment variable. """
+ proxy = get_proxy(proxystr)
+ if proxy:
+ proxy_support = urllib2.ProxyHandler({"http": proxy, "ftp": proxy})
+ opener = urllib2.build_opener(proxy_support, urllib2.CacheFTPHandler)
+ urllib2.install_opener(opener)
+
+def get_proxy(proxystr=''):
+ """Get the proxy given the option passed on the command line. If an
+ empty string is passed it looks at the HTTP_PROXY environment
+ variable."""
+ if not proxystr:
+ proxystr = os.environ.get('HTTP_PROXY', '')
+ if proxystr:
+ if '@' in proxystr:
+ user_password, server_port = proxystr.split('@', 1)
+ if ':' in user_password:
+ user, password = user_password.split(':', 1)
+ else:
+ user = user_password
+ import getpass
+ prompt = 'Password for %s@%s: ' % (user, server_port)
+ password = urllib.quote(getpass.getpass(prompt))
+ return '%s:%s@%s' % (user, password, server_port)
+ else:
+ return proxystr
+ else:
+ return None
+
+def format_exc(exc_info=None):
+ if exc_info is None:
+ exc_info = sys.exc_info()
+ out = StringIO()
+ traceback.print_exception(*exc_info, **dict(file=out))
+ return out.getvalue()
+
+def open_logfile(filename, mode='a'):
+ """Open the named log file in append mode.
+
+ If the file already exists, a separator will also be printed to
+ the file to separate past activity from current activity.
+ """
+ filename = os.path.expanduser(filename)
+ filename = os.path.abspath(filename)
+ dirname = os.path.dirname(filename)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ exists = os.path.exists(filename)
+ log_fp = open(filename, mode)
+ if exists:
+ print >> log_fp, '-'*60
+ print >> log_fp, '%s run on %s' % (sys.argv[0], time.strftime('%c'))
+ return log_fp
+
+def load_command(name):
+ full_name = 'pip.commands.%s' % name
+ if full_name in sys.modules:
+ return
+ try:
+ __import__(full_name)
+ except ImportError:
+ pass
+
+def load_all_commands():
+ for name in command_names():
+ load_command(name)
+
+def command_names():
+ dir = os.path.join(os.path.dirname(__file__), 'commands')
+ names = []
+ for name in os.listdir(dir):
+ if name.endswith('.py') and os.path.isfile(os.path.join(dir, name)):
+ names.append(os.path.splitext(name)[0])
+ return names
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,223 @@
+"""Base option parser setup"""
+
+import sys
+import optparse
+import pkg_resources
+import ConfigParser
+import os
+from distutils.util import strtobool
+from pip.locations import default_config_file, default_log_file
+
+class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
+ """Custom help formatter for use in ConfigOptionParser that updates
+ the defaults before expanding them, allowing them to show up correctly
+ in the help listing"""
+
+ def expand_default(self, option):
+ if self.parser is not None:
+ self.parser.update_defaults(self.parser.defaults)
+ return optparse.IndentedHelpFormatter.expand_default(self, option)
+
+
+class ConfigOptionParser(optparse.OptionParser):
+ """Custom option parser which updates its defaults by by checking the
+ configuration files and environmental variables"""
+
+ def __init__(self, *args, **kwargs):
+ self.config = ConfigParser.RawConfigParser()
+ self.name = kwargs.pop('name')
+ self.files = self.get_config_files()
+ self.config.read(self.files)
+ assert self.name
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+
+ def get_config_files(self):
+ config_file = os.environ.get('PIP_CONFIG_FILE', False)
+ if config_file and os.path.exists(config_file):
+ return [config_file]
+ return [default_config_file]
+
+ def update_defaults(self, defaults):
+ """Updates the given defaults with values from the config files and
+ the environ. Does a little special handling for certain types of
+ options (lists)."""
+ # Then go and look for the other sources of configuration:
+ config = {}
+ # 1. config files
+ for section in ('global', self.name):
+ config.update(dict(self.get_config_section(section)))
+ # 2. environmental variables
+ config.update(dict(self.get_environ_vars()))
+ # Then set the options with those values
+ for key, val in config.iteritems():
+ key = key.replace('_', '-')
+ if not key.startswith('--'):
+ key = '--%s' % key # only prefer long opts
+ option = self.get_option(key)
+ if option is not None:
+ # ignore empty values
+ if not val:
+ continue
+ # handle multiline configs
+ if option.action == 'append':
+ val = val.split()
+ else:
+ option.nargs = 1
+ if option.action in ('store_true', 'store_false', 'count'):
+ val = strtobool(val)
+ try:
+ val = option.convert_value(key, val)
+ except optparse.OptionValueError, e:
+ print ("An error occured during configuration: %s" % e)
+ sys.exit(3)
+ defaults[option.dest] = val
+ return defaults
+
+ def get_config_section(self, name):
+ """Get a section of a configuration"""
+ if self.config.has_section(name):
+ return self.config.items(name)
+ return []
+
+ def get_environ_vars(self, prefix='PIP_'):
+ """Returns a generator with all environmental vars with prefix PIP_"""
+ for key, val in os.environ.iteritems():
+ if key.startswith(prefix):
+ yield (key.replace(prefix, '').lower(), val)
+
+ def get_default_values(self):
+ """Overridding to make updating the defaults after instantiation of
+ the option parser possible, update_defaults() does the dirty work."""
+ if not self.process_default_values:
+ # Old, pre-Optik 1.5 behaviour.
+ return optparse.Values(self.defaults)
+
+ defaults = self.update_defaults(self.defaults.copy()) # ours
+ for option in self._get_all_options():
+ default = defaults.get(option.dest)
+ if isinstance(default, basestring):
+ opt_str = option.get_opt_string()
+ defaults[option.dest] = option.check_value(opt_str, default)
+ return optparse.Values(defaults)
+
+try:
+ pip_dist = pkg_resources.get_distribution('pip')
+ version = '%s from %s (python %s)' % (
+ pip_dist, pip_dist.location, sys.version[:3])
+except pkg_resources.DistributionNotFound:
+ # when running pip.py without installing
+ version=None
+
+parser = ConfigOptionParser(
+ usage='%prog COMMAND [OPTIONS]',
+ version=version,
+ add_help_option=False,
+ formatter=UpdatingDefaultsHelpFormatter(),
+ name='global')
+
+parser.add_option(
+ '-h', '--help',
+ dest='help',
+ action='store_true',
+ help='Show help')
+parser.add_option(
+ '-E', '--environment',
+ dest='venv',
+ metavar='DIR',
+ help='virtualenv environment to run pip in (either give the '
+ 'interpreter or the environment base directory)')
+parser.add_option(
+ '-s', '--enable-site-packages',
+ dest='site_packages',
+ action='store_true',
+ help='Include site-packages in virtualenv if one is to be '
+ 'created. Ignored if --environment is not used or '
+ 'the virtualenv already exists.')
+parser.add_option(
+ # Defines a default root directory for virtualenvs, relative
+ # virtualenvs names/paths are considered relative to it.
+ '--virtualenv-base',
+ dest='venv_base',
+ type='str',
+ default='',
+ help=optparse.SUPPRESS_HELP)
+parser.add_option(
+ # Run only if inside a virtualenv, bail if not.
+ '--require-virtualenv', '--require-venv',
+ dest='require_venv',
+ action='store_true',
+ default=False,
+ help=optparse.SUPPRESS_HELP)
+parser.add_option(
+ # Use automatically an activated virtualenv instead of installing
+ # globally. -E will be ignored if used.
+ '--respect-virtualenv', '--respect-venv',
+ dest='respect_venv',
+ action='store_true',
+ default=False,
+ help=optparse.SUPPRESS_HELP)
+
+parser.add_option(
+ '-v', '--verbose',
+ dest='verbose',
+ action='count',
+ default=0,
+ help='Give more output')
+parser.add_option(
+ '-q', '--quiet',
+ dest='quiet',
+ action='count',
+ default=0,
+ help='Give less output')
+parser.add_option(
+ '--log',
+ dest='log',
+ metavar='FILENAME',
+ help='Log file where a complete (maximum verbosity) record will be kept')
+parser.add_option(
+ # Writes the log levels explicitely to the log'
+ '--log-explicit-levels',
+ dest='log_explicit_levels',
+ action='store_true',
+ default=False,
+ help=optparse.SUPPRESS_HELP)
+parser.add_option(
+ # The default log file
+ '--local-log', '--log-file',
+ dest='log_file',
+ metavar='FILENAME',
+ default=default_log_file,
+ help=optparse.SUPPRESS_HELP)
+
+parser.add_option(
+ '--proxy',
+ dest='proxy',
+ type='str',
+ default='',
+ help="Specify a proxy in the form user:passwd at proxy.server:port. "
+ "Note that the user:password@ is optional and required only if you "
+ "are behind an authenticated proxy. If you provide "
+ "user at proxy.server:port then you will be prompted for a password.")
+parser.add_option(
+ '--timeout', '--default-timeout',
+ metavar='SECONDS',
+ dest='timeout',
+ type='float',
+ default=15,
+ help='Set the socket timeout (default %default seconds)')
+parser.add_option(
+ # The default version control system for editables, e.g. 'svn'
+ '--default-vcs',
+ dest='default_vcs',
+ type='str',
+ default='',
+ help=optparse.SUPPRESS_HELP)
+parser.add_option(
+ # A regex to be used to skip requirements
+ '--skip-requirements-regex',
+ dest='skip_requirements_regex',
+ type='str',
+ default='',
+ help=optparse.SUPPRESS_HELP)
+
+parser.disable_interspersed_args()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+#
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,31 @@
+from pip.locations import build_prefix, src_prefix
+from pip.util import display_path, backup_dir
+from pip.log import logger
+from pip.exceptions import InstallationError
+from pip.commands.install import InstallCommand
+
+class BundleCommand(InstallCommand):
+ name = 'bundle'
+ usage = '%prog [OPTIONS] BUNDLE_NAME.pybundle PACKAGE_NAMES...'
+ summary = 'Create pybundles (archives containing multiple packages)'
+ bundle = True
+
+ def __init__(self):
+ super(BundleCommand, self).__init__()
+
+ def run(self, options, args):
+ if not args:
+ raise InstallationError('You must give a bundle filename')
+ if not options.build_dir:
+ options.build_dir = backup_dir(build_prefix, '-bundle')
+ if not options.src_dir:
+ options.src_dir = backup_dir(src_prefix, '-bundle')
+ # We have to get everything when creating a bundle:
+ options.ignore_installed = True
+ logger.notify('Putting temporary build files in %s and source/develop files in %s'
+ % (display_path(options.build_dir), display_path(options.src_dir)))
+ self.bundle_filename = args.pop(0)
+ requirement_set = super(BundleCommand, self).run(options, args)
+ return requirement_set
+
+BundleCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,60 @@
+import sys
+from pip.basecommand import Command
+
+BASE_COMPLETION = """
+# pip %(shell)s completion start%(script)s# pip %(shell)s completion end
+"""
+
+COMPLETION_SCRIPTS = {
+ 'bash': """
+_pip_completion()
+{
+ COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\
+ COMP_CWORD=$COMP_CWORD \\
+ PIP_AUTO_COMPLETE=1 $1 ) )
+}
+complete -o default -F _pip_completion pip
+""", 'zsh': """
+function _pip_completion {
+ local words cword
+ read -Ac words
+ read -cn cword
+ reply=( $( COMP_WORDS="$words[*]" \\
+ COMP_CWORD=$(( cword-1 )) \\
+ PIP_AUTO_COMPLETE=1 $words[1] ) )
+}
+compctl -K _pip_completion pip
+"""
+}
+
+class CompletionCommand(Command):
+ name = 'completion'
+ summary = 'A helper command to be used for command completion'
+ hidden = True
+
+ def __init__(self):
+ super(CompletionCommand, self).__init__()
+ self.parser.add_option(
+ '--bash', '-b',
+ action='store_const',
+ const='bash',
+ dest='shell',
+ help='Emit completion code for bash')
+ self.parser.add_option(
+ '--zsh', '-z',
+ action='store_const',
+ const='zsh',
+ dest='shell',
+ help='Emit completion code for zsh')
+
+ def run(self, options, args):
+ """Prints the completion code of the given shell"""
+ shells = COMPLETION_SCRIPTS.keys()
+ shell_options = ['--'+shell for shell in sorted(shells)]
+ if options.shell in shells:
+ script = COMPLETION_SCRIPTS.get(options.shell, '')
+ print BASE_COMPLETION % {'script': script, 'shell': options.shell}
+ else:
+ sys.stderr.write('ERROR: You must pass %s\n' % ' or '.join(shell_options))
+
+CompletionCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,107 @@
+import re
+import sys
+import pkg_resources
+import pip
+from pip.req import InstallRequirement
+from pip.log import logger
+from pip.basecommand import Command
+from pip.util import get_installed_distributions
+
+class FreezeCommand(Command):
+ name = 'freeze'
+ usage = '%prog [OPTIONS]'
+ summary = 'Output all currently installed packages (exact versions) to stdout'
+
+ def __init__(self):
+ super(FreezeCommand, self).__init__()
+ self.parser.add_option(
+ '-r', '--requirement',
+ dest='requirement',
+ action='store',
+ default=None,
+ metavar='FILENAME',
+ help='Use the given requirements file as a hint about how to generate the new frozen requirements')
+ self.parser.add_option(
+ '-f', '--find-links',
+ dest='find_links',
+ action='append',
+ default=[],
+ metavar='URL',
+ help='URL for finding packages, which will be added to the frozen requirements file')
+ self.parser.add_option(
+ '-l', '--local',
+ dest='local',
+ action='store_true',
+ default=False,
+ help='If in a virtualenv, do not report globally-installed packages')
+
+ def setup_logging(self):
+ logger.move_stdout_to_stderr()
+
+ def run(self, options, args):
+ requirement = options.requirement
+ find_links = options.find_links or []
+ local_only = options.local
+ ## FIXME: Obviously this should be settable:
+ find_tags = False
+ skip_match = None
+
+ skip_regex = options.skip_requirements_regex
+ if skip_regex:
+ skip_match = re.compile(skip_regex)
+
+ dependency_links = []
+
+ f = sys.stdout
+
+ for dist in pkg_resources.working_set:
+ if dist.has_metadata('dependency_links.txt'):
+ dependency_links.extend(dist.get_metadata_lines('dependency_links.txt'))
+ for link in find_links:
+ if '#egg=' in link:
+ dependency_links.append(link)
+ for link in find_links:
+ f.write('-f %s\n' % link)
+ installations = {}
+ for dist in get_installed_distributions(local_only=local_only):
+ req = pip.FrozenRequirement.from_dist(dist, dependency_links, find_tags=find_tags)
+ installations[req.name] = req
+ if requirement:
+ req_f = open(requirement)
+ for line in req_f:
+ if not line.strip() or line.strip().startswith('#'):
+ f.write(line)
+ continue
+ if skip_match and skip_match.search(line):
+ f.write(line)
+ continue
+ elif line.startswith('-e') or line.startswith('--editable'):
+ if line.startswith('-e'):
+ line = line[2:].strip()
+ else:
+ line = line[len('--editable'):].strip().lstrip('=')
+ line_req = InstallRequirement.from_editable(line, default_vcs=options.default_vcs)
+ elif (line.startswith('-r') or line.startswith('--requirement')
+ or line.startswith('-Z') or line.startswith('--always-unzip')
+ or line.startswith('-f') or line.startswith('-i')
+ or line.startswith('--extra-index-url')):
+ f.write(line)
+ continue
+ else:
+ line_req = InstallRequirement.from_line(line)
+ if not line_req.name:
+ logger.notify("Skipping line because it's not clear what it would install: %s"
+ % line.strip())
+ logger.notify(" (add #egg=PackageName to the URL to avoid this warning)")
+ continue
+ if line_req.name not in installations:
+ logger.warn("Requirement file contains %s, but that package is not installed"
+ % line.strip())
+ continue
+ f.write(str(installations[line_req.name]))
+ del installations[line_req.name]
+ f.write('## The following requirements were added by pip --freeze:\n')
+ for installation in sorted(installations.values(), key=lambda x: x.name):
+ f.write(str(installation))
+
+FreezeCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,30 @@
+from pip.basecommand import Command, command_dict, load_all_commands
+from pip.exceptions import InstallationError
+from pip.baseparser import parser
+
+class HelpCommand(Command):
+ name = 'help'
+ usage = '%prog'
+ summary = 'Show available commands'
+
+ def run(self, options, args):
+ load_all_commands()
+ if args:
+ ## FIXME: handle errors better here
+ command = args[0]
+ if command not in command_dict:
+ raise InstallationError('No command with the name: %s' % command)
+ command = command_dict[command]
+ command.parser.print_help()
+ return
+ parser.print_help()
+ print
+ print 'Commands available:'
+ commands = list(set(command_dict.values()))
+ commands.sort(key=lambda x: x.name)
+ for command in commands:
+ if command.hidden:
+ continue
+ print ' %s: %s' % (command.name, command.summary)
+
+HelpCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,183 @@
+import os
+from pip.req import InstallRequirement, RequirementSet
+from pip.req import parse_requirements
+from pip.log import logger
+from pip.locations import build_prefix, src_prefix
+from pip.basecommand import Command
+from pip.index import PackageFinder
+
+class InstallCommand(Command):
+ name = 'install'
+ usage = '%prog [OPTIONS] PACKAGE_NAMES...'
+ summary = 'Install packages'
+ bundle = False
+
+ def __init__(self):
+ super(InstallCommand, self).__init__()
+ self.parser.add_option(
+ '-e', '--editable',
+ dest='editables',
+ action='append',
+ default=[],
+ metavar='VCS+REPOS_URL[@REV]#egg=PACKAGE',
+ help='Install a package directly from a checkout. Source will be checked '
+ 'out into src/PACKAGE (lower-case) and installed in-place (using '
+ 'setup.py develop). You can run this on an existing directory/checkout (like '
+ 'pip install -e src/mycheckout). This option may be provided multiple times. '
+ 'Possible values for VCS are: svn, git, hg and bzr.')
+ self.parser.add_option(
+ '-r', '--requirement',
+ dest='requirements',
+ action='append',
+ default=[],
+ metavar='FILENAME',
+ help='Install all the packages listed in the given requirements file. '
+ 'This option can be used multiple times.')
+ self.parser.add_option(
+ '-f', '--find-links',
+ dest='find_links',
+ action='append',
+ default=[],
+ metavar='URL',
+ help='URL to look for packages at')
+ self.parser.add_option(
+ '-i', '--index-url', '--pypi-url',
+ dest='index_url',
+ metavar='URL',
+ default='http://pypi.python.org/simple',
+ help='Base URL of Python Package Index (default %default)')
+ self.parser.add_option(
+ '--extra-index-url',
+ dest='extra_index_urls',
+ metavar='URL',
+ action='append',
+ default=[],
+ help='Extra URLs of package indexes to use in addition to --index-url')
+ self.parser.add_option(
+ '--no-index',
+ dest='no_index',
+ action='store_true',
+ default=False,
+ help='Ignore package index (only looking at --find-links URLs instead)')
+
+ self.parser.add_option(
+ '-b', '--build', '--build-dir', '--build-directory',
+ dest='build_dir',
+ metavar='DIR',
+ default=None,
+ help='Unpack packages into DIR (default %s) and build from there' % build_prefix)
+ self.parser.add_option(
+ '-d', '--download', '--download-dir', '--download-directory',
+ dest='download_dir',
+ metavar='DIR',
+ default=None,
+ help='Download packages into DIR instead of installing them')
+ self.parser.add_option(
+ '--download-cache',
+ dest='download_cache',
+ metavar='DIR',
+ default=None,
+ help='Cache downloaded packages in DIR')
+ self.parser.add_option(
+ '--src', '--source', '--source-dir', '--source-directory',
+ dest='src_dir',
+ metavar='DIR',
+ default=None,
+ help='Check out --editable packages into DIR (default %s)' % src_prefix)
+
+ self.parser.add_option(
+ '-U', '--upgrade',
+ dest='upgrade',
+ action='store_true',
+ help='Upgrade all packages to the newest available version')
+ self.parser.add_option(
+ '-I', '--ignore-installed',
+ dest='ignore_installed',
+ action='store_true',
+ help='Ignore the installed packages (reinstalling instead)')
+ self.parser.add_option(
+ '--no-deps', '--no-dependencies',
+ dest='ignore_dependencies',
+ action='store_true',
+ default=False,
+ help='Ignore package dependencies')
+ self.parser.add_option(
+ '--no-install',
+ dest='no_install',
+ action='store_true',
+ help="Download and unpack all packages, but don't actually install them")
+ self.parser.add_option(
+ '--no-download',
+ dest='no_download',
+ action="store_true",
+ help="Don't download any packages, just install the ones already downloaded "
+ "(completes an install run with --no-install)")
+
+ self.parser.add_option(
+ '--install-option',
+ dest='install_options',
+ action='append',
+ help="Extra arguments to be supplied to the setup.py install "
+ "command (use like --install-option=\"--install-scripts=/usr/local/bin\"). "
+ "Use multiple --install-option options to pass multiple options to setup.py install. "
+ "If you are using an option with a directory path, be sure to use absolute path.")
+
+ def run(self, options, args):
+ if not options.build_dir:
+ options.build_dir = build_prefix
+ if not options.src_dir:
+ options.src_dir = src_prefix
+ if options.download_dir:
+ options.no_install = True
+ options.ignore_installed = True
+ options.build_dir = os.path.abspath(options.build_dir)
+ options.src_dir = os.path.abspath(options.src_dir)
+ install_options = options.install_options or []
+ index_urls = [options.index_url] + options.extra_index_urls
+ if options.no_index:
+ logger.notify('Ignoring indexes: %s' % ','.join(index_urls))
+ index_urls = []
+ finder = PackageFinder(
+ find_links=options.find_links,
+ index_urls=index_urls)
+ requirement_set = RequirementSet(
+ build_dir=options.build_dir,
+ src_dir=options.src_dir,
+ download_dir=options.download_dir,
+ download_cache=options.download_cache,
+ upgrade=options.upgrade,
+ ignore_installed=options.ignore_installed,
+ ignore_dependencies=options.ignore_dependencies)
+ for name in args:
+ requirement_set.add_requirement(
+ InstallRequirement.from_line(name, None))
+ for name in options.editables:
+ requirement_set.add_requirement(
+ InstallRequirement.from_editable(name, default_vcs=options.default_vcs))
+ for filename in options.requirements:
+ for req in parse_requirements(filename, finder=finder, options=options):
+ requirement_set.add_requirement(req)
+ if not options.no_download:
+ requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
+ else:
+ requirement_set.locate_files()
+ if not options.no_install and not self.bundle:
+ requirement_set.install(install_options)
+ installed = ' '.join([req.name for req in
+ requirement_set.successfully_installed])
+ if installed:
+ logger.notify('Successfully installed %s' % installed)
+ elif not self.bundle:
+ downloaded = ' '.join([req.name for req in
+ requirement_set.successfully_downloaded])
+ if downloaded:
+ logger.notify('Successfully downloaded %s' % downloaded)
+ elif self.bundle:
+ requirement_set.create_bundle(self.bundle_filename)
+ logger.notify('Created bundle in %s' % self.bundle_filename)
+ # Clean up
+ if not options.no_install:
+ requirement_set.cleanup_files(bundle=self.bundle)
+ return requirement_set
+
+InstallCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,109 @@
+import sys
+import xmlrpclib
+import textwrap
+import pkg_resources
+from pip.basecommand import Command
+from pip.util import get_terminal_size
+from pip.log import logger
+from distutils.version import StrictVersion, LooseVersion
+
+class SearchCommand(Command):
+ name = 'search'
+ usage = '%prog QUERY'
+ summary = 'Search PyPI'
+
+ def __init__(self):
+ super(SearchCommand, self).__init__()
+ self.parser.add_option(
+ '--index',
+ dest='index',
+ metavar='URL',
+ default='http://pypi.python.org/pypi',
+ help='Base URL of Python Package Index (default %default)')
+
+ def run(self, options, args):
+ if not args:
+ logger.warn('ERROR: Missing required argument (search query).')
+ return
+ query = ' '.join(args)
+ index_url = options.index
+
+ pypi_hits = self.search(query, index_url)
+ hits = transform_hits(pypi_hits)
+
+ terminal_width = None
+ if sys.stdout.isatty():
+ terminal_width = get_terminal_size()[0]
+
+ print_results(hits, terminal_width=terminal_width)
+
+ def search(self, query, index_url):
+ pypi = xmlrpclib.ServerProxy(index_url)
+ hits = pypi.search({'name': query, 'summary': query}, 'or')
+ return hits
+
+def transform_hits(hits):
+ """
+ The list from pypi is really a list of versions. We want a list of
+ packages with the list of versions stored inline. This converts the
+ list from pypi into one we can use.
+ """
+ packages = {}
+ for hit in hits:
+ name = hit['name']
+ summary = hit['summary']
+ version = hit['version']
+ score = hit['_pypi_ordering']
+
+ if name not in packages.keys():
+ packages[name] = {'name': name, 'summary': summary, 'versions': [version], 'score': score}
+ else:
+ packages[name]['versions'].append(version)
+
+ # if this is the highest version, replace summary and score
+ if version == highest_version(packages[name]['versions']):
+ packages[name]['summary'] = summary
+ packages[name]['score'] = score
+
+ # each record has a unique name now, so we will convert the dict into a list sorted by score
+ package_list = sorted(packages.values(), lambda x, y: cmp(y['score'], x['score']))
+ return package_list
+
+def print_results(hits, name_column_width=25, terminal_width=None):
+ installed_packages = [p.project_name for p in pkg_resources.working_set]
+ for hit in hits:
+ name = hit['name']
+ summary = hit['summary'] or ''
+ if terminal_width is not None:
+ # wrap and indent summary to fit terminal
+ summary = textwrap.wrap(summary, terminal_width - name_column_width - 5)
+ summary = ('\n' + ' ' * (name_column_width + 3)).join(summary)
+ line = '%s - %s' % (name.ljust(name_column_width), summary)
+ try:
+ logger.notify(line)
+ if name in installed_packages:
+ dist = pkg_resources.get_distribution(name)
+ logger.indent += 2
+ try:
+ latest = highest_version(hit['versions'])
+ if dist.version == latest:
+ logger.notify('INSTALLED: %s (latest)' % dist.version)
+ else:
+ logger.notify('INSTALLED: %s' % dist.version)
+ logger.notify('LATEST: %s' % latest)
+ finally:
+ logger.indent -= 2
+ except UnicodeEncodeError:
+ pass
+
+def compare_versions(version1, version2):
+ try:
+ return cmp(StrictVersion(version1), StrictVersion(version2))
+ # in case of abnormal version number, fall back to LooseVersion
+ except ValueError:
+ return cmp(LooseVersion(version1), LooseVersion(version2))
+
+def highest_version(versions):
+ return reduce((lambda v1, v2: compare_versions(v1, v2) == 1 and v1 or v2), versions)
+
+SearchCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,39 @@
+from pip.req import InstallRequirement, RequirementSet
+from pip.req import parse_requirements
+from pip.basecommand import Command
+
+class UninstallCommand(Command):
+ name = 'uninstall'
+ usage = '%prog [OPTIONS] PACKAGE_NAMES ...'
+ summary = 'Uninstall packages'
+
+ def __init__(self):
+ super(UninstallCommand, self).__init__()
+ self.parser.add_option(
+ '-r', '--requirement',
+ dest='requirements',
+ action='append',
+ default=[],
+ metavar='FILENAME',
+ help='Uninstall all the packages listed in the given requirements file. '
+ 'This option can be used multiple times.')
+ self.parser.add_option(
+ '-y', '--yes',
+ dest='yes',
+ action='store_true',
+ help="Don't ask for confirmation of uninstall deletions.")
+
+ def run(self, options, args):
+ requirement_set = RequirementSet(
+ build_dir=None,
+ src_dir=None,
+ download_dir=None)
+ for name in args:
+ requirement_set.add_requirement(
+ InstallRequirement.from_line(name))
+ for filename in options.requirements:
+ for req in parse_requirements(filename, options=options):
+ requirement_set.add_requirement(req)
+ requirement_set.uninstall(auto_confirm=options.yes)
+
+UninstallCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,7 @@
+from pip.commands.zip import ZipCommand
+
+class UnzipCommand(ZipCommand):
+ name = 'unzip'
+ summary = 'Unzip individual packages'
+
+UnzipCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,344 @@
+import sys
+import re
+import fnmatch
+import os
+import shutil
+import zipfile
+from pip.util import display_path, backup_dir
+from pip.log import logger
+from pip.exceptions import InstallationError
+from pip.basecommand import Command
+
+class ZipCommand(Command):
+ name = 'zip'
+ usage = '%prog [OPTIONS] PACKAGE_NAMES...'
+ summary = 'Zip individual packages'
+
+ def __init__(self):
+ super(ZipCommand, self).__init__()
+ if self.name == 'zip':
+ self.parser.add_option(
+ '--unzip',
+ action='store_true',
+ dest='unzip',
+ help='Unzip (rather than zip) a package')
+ else:
+ self.parser.add_option(
+ '--zip',
+ action='store_false',
+ dest='unzip',
+ default=True,
+ help='Zip (rather than unzip) a package')
+ self.parser.add_option(
+ '--no-pyc',
+ action='store_true',
+ dest='no_pyc',
+ help='Do not include .pyc files in zip files (useful on Google App Engine)')
+ self.parser.add_option(
+ '-l', '--list',
+ action='store_true',
+ dest='list',
+ help='List the packages available, and their zip status')
+ self.parser.add_option(
+ '--sort-files',
+ action='store_true',
+ dest='sort_files',
+ help='With --list, sort packages according to how many files they contain')
+ self.parser.add_option(
+ '--path',
+ action='append',
+ dest='paths',
+ help='Restrict operations to the given paths (may include wildcards)')
+ self.parser.add_option(
+ '-n', '--simulate',
+ action='store_true',
+ help='Do not actually perform the zip/unzip operation')
+
+ def paths(self):
+ """All the entries of sys.path, possibly restricted by --path"""
+ if not self.select_paths:
+ return sys.path
+ result = []
+ match_any = set()
+ for path in sys.path:
+ path = os.path.normcase(os.path.abspath(path))
+ for match in self.select_paths:
+ match = os.path.normcase(os.path.abspath(match))
+ if '*' in match:
+ if re.search(fnmatch.translate(match+'*'), path):
+ result.append(path)
+ match_any.add(match)
+ break
+ else:
+ if path.startswith(match):
+ result.append(path)
+ match_any.add(match)
+ break
+ else:
+ logger.debug("Skipping path %s because it doesn't match %s"
+ % (path, ', '.join(self.select_paths)))
+ for match in self.select_paths:
+ if match not in match_any and '*' not in match:
+ result.append(match)
+ logger.debug("Adding path %s because it doesn't match anything already on sys.path"
+ % match)
+ return result
+
+ def run(self, options, args):
+ self.select_paths = options.paths
+ self.simulate = options.simulate
+ if options.list:
+ return self.list(options, args)
+ if not args:
+ raise InstallationError(
+ 'You must give at least one package to zip or unzip')
+ packages = []
+ for arg in args:
+ module_name, filename = self.find_package(arg)
+ if options.unzip and os.path.isdir(filename):
+ raise InstallationError(
+ 'The module %s (in %s) is not a zip file; cannot be unzipped'
+ % (module_name, filename))
+ elif not options.unzip and not os.path.isdir(filename):
+ raise InstallationError(
+ 'The module %s (in %s) is not a directory; cannot be zipped'
+ % (module_name, filename))
+ packages.append((module_name, filename))
+ last_status = None
+ for module_name, filename in packages:
+ if options.unzip:
+ last_status = self.unzip_package(module_name, filename)
+ else:
+ last_status = self.zip_package(module_name, filename, options.no_pyc)
+ return last_status
+
+ def unzip_package(self, module_name, filename):
+ zip_filename = os.path.dirname(filename)
+ if not os.path.isfile(zip_filename) and zipfile.is_zipfile(zip_filename):
+ raise InstallationError(
+ 'Module %s (in %s) isn\'t located in a zip file in %s'
+ % (module_name, filename, zip_filename))
+ package_path = os.path.dirname(zip_filename)
+ if not package_path in self.paths():
+ logger.warn(
+ 'Unpacking %s into %s, but %s is not on sys.path'
+ % (display_path(zip_filename), display_path(package_path),
+ display_path(package_path)))
+ logger.notify('Unzipping %s (in %s)' % (module_name, display_path(zip_filename)))
+ if self.simulate:
+ logger.notify('Skipping remaining operations because of --simulate')
+ return
+ logger.indent += 2
+ try:
+ ## FIXME: this should be undoable:
+ zip = zipfile.ZipFile(zip_filename)
+ to_save = []
+ for name in zip.namelist():
+ if name.startswith('%s/' % module_name):
+ content = zip.read(name)
+ dest = os.path.join(package_path, name)
+ if not os.path.exists(os.path.dirname(dest)):
+ os.makedirs(os.path.dirname(dest))
+ if not content and dest.endswith('/'):
+ if not os.path.exists(dest):
+ os.makedirs(dest)
+ else:
+ f = open(dest, 'wb')
+ f.write(content)
+ f.close()
+ else:
+ to_save.append((name, zip.read(name)))
+ zip.close()
+ if not to_save:
+ logger.info('Removing now-empty zip file %s' % display_path(zip_filename))
+ os.unlink(zip_filename)
+ self.remove_filename_from_pth(zip_filename)
+ else:
+ logger.info('Removing entries in %s/ from zip file %s' % (module_name, display_path(zip_filename)))
+ zip = zipfile.ZipFile(zip_filename, 'w')
+ for name, content in to_save:
+ zip.writestr(name, content)
+ zip.close()
+ finally:
+ logger.indent -= 2
+
+ def zip_package(self, module_name, filename, no_pyc):
+ orig_filename = filename
+ logger.notify('Zip %s (in %s)' % (module_name, display_path(filename)))
+ logger.indent += 2
+ if filename.endswith('.egg'):
+ dest_filename = filename
+ else:
+ dest_filename = filename + '.zip'
+ try:
+ ## FIXME: I think this needs to be undoable:
+ if filename == dest_filename:
+ filename = backup_dir(orig_filename)
+ logger.notify('Moving %s aside to %s' % (orig_filename, filename))
+ if not self.simulate:
+ shutil.move(orig_filename, filename)
+ try:
+ logger.info('Creating zip file in %s' % display_path(dest_filename))
+ if not self.simulate:
+ zip = zipfile.ZipFile(dest_filename, 'w')
+ zip.writestr(module_name + '/', '')
+ for dirpath, dirnames, filenames in os.walk(filename):
+ if no_pyc:
+ filenames = [f for f in filenames
+ if not f.lower().endswith('.pyc')]
+ for fns, is_dir in [(dirnames, True), (filenames, False)]:
+ for fn in fns:
+ full = os.path.join(dirpath, fn)
+ dest = os.path.join(module_name, dirpath[len(filename):].lstrip(os.path.sep), fn)
+ if is_dir:
+ zip.writestr(dest+'/', '')
+ else:
+ zip.write(full, dest)
+ zip.close()
+ logger.info('Removing old directory %s' % display_path(filename))
+ if not self.simulate:
+ shutil.rmtree(filename)
+ except:
+ ## FIXME: need to do an undo here
+ raise
+ ## FIXME: should also be undone:
+ self.add_filename_to_pth(dest_filename)
+ finally:
+ logger.indent -= 2
+
+ def remove_filename_from_pth(self, filename):
+ for pth in self.pth_files():
+ f = open(pth, 'r')
+ lines = f.readlines()
+ f.close()
+ new_lines = [
+ l for l in lines if l.strip() != filename]
+ if lines != new_lines:
+ logger.info('Removing reference to %s from .pth file %s'
+ % (display_path(filename), display_path(pth)))
+ if not filter(None, new_lines):
+ logger.info('%s file would be empty: deleting' % display_path(pth))
+ if not self.simulate:
+ os.unlink(pth)
+ else:
+ if not self.simulate:
+ f = open(pth, 'w')
+ f.writelines(new_lines)
+ f.close()
+ return
+ logger.warn('Cannot find a reference to %s in any .pth file' % display_path(filename))
+
+ def add_filename_to_pth(self, filename):
+ path = os.path.dirname(filename)
+ dest = os.path.join(path, filename + '.pth')
+ if path not in self.paths():
+ logger.warn('Adding .pth file %s, but it is not on sys.path' % display_path(dest))
+ if not self.simulate:
+ if os.path.exists(dest):
+ f = open(dest)
+ lines = f.readlines()
+ f.close()
+ if lines and not lines[-1].endswith('\n'):
+ lines[-1] += '\n'
+ lines.append(filename+'\n')
+ else:
+ lines = [filename + '\n']
+ f = open(dest, 'w')
+ f.writelines(lines)
+ f.close()
+
+ def pth_files(self):
+ for path in self.paths():
+ if not os.path.exists(path) or not os.path.isdir(path):
+ continue
+ for filename in os.listdir(path):
+ if filename.endswith('.pth'):
+ yield os.path.join(path, filename)
+
+ def find_package(self, package):
+ for path in self.paths():
+ full = os.path.join(path, package)
+ if os.path.exists(full):
+ return package, full
+ if not os.path.isdir(path) and zipfile.is_zipfile(path):
+ zip = zipfile.ZipFile(path, 'r')
+ try:
+ zip.read('%s/__init__.py' % package)
+ except KeyError:
+ pass
+ else:
+ zip.close()
+ return package, full
+ zip.close()
+ ## FIXME: need special error for package.py case:
+ raise InstallationError(
+ 'No package with the name %s found' % package)
+
+ def list(self, options, args):
+ if args:
+ raise InstallationError(
+ 'You cannot give an argument with --list')
+ for path in sorted(self.paths()):
+ if not os.path.exists(path):
+ continue
+ basename = os.path.basename(path.rstrip(os.path.sep))
+ if os.path.isfile(path) and zipfile.is_zipfile(path):
+ if os.path.dirname(path) not in self.paths():
+ logger.notify('Zipped egg: %s' % display_path(path))
+ continue
+ if (basename != 'site-packages' and basename != 'dist-packages'
+ and not path.replace('\\', '/').endswith('lib/python')):
+ continue
+ logger.notify('In %s:' % display_path(path))
+ logger.indent += 2
+ zipped = []
+ unzipped = []
+ try:
+ for filename in sorted(os.listdir(path)):
+ ext = os.path.splitext(filename)[1].lower()
+ if ext in ('.pth', '.egg-info', '.egg-link'):
+ continue
+ if ext == '.py':
+ logger.info('Not displaying %s: not a package' % display_path(filename))
+ continue
+ full = os.path.join(path, filename)
+ if os.path.isdir(full):
+ unzipped.append((filename, self.count_package(full)))
+ elif zipfile.is_zipfile(full):
+ zipped.append(filename)
+ else:
+ logger.info('Unknown file: %s' % display_path(filename))
+ if zipped:
+ logger.notify('Zipped packages:')
+ logger.indent += 2
+ try:
+ for filename in zipped:
+ logger.notify(filename)
+ finally:
+ logger.indent -= 2
+ else:
+ logger.notify('No zipped packages.')
+ if unzipped:
+ if options.sort_files:
+ unzipped.sort(key=lambda x: -x[1])
+ logger.notify('Unzipped packages:')
+ logger.indent += 2
+ try:
+ for filename, count in unzipped:
+ logger.notify('%s (%i files)' % (filename, count))
+ finally:
+ logger.indent -= 2
+ else:
+ logger.notify('No unzipped packages.')
+ finally:
+ logger.indent -= 2
+
+ def count_package(self, path):
+ total = 0
+ for dirpath, dirnames, filenames in os.walk(path):
+ filenames = [f for f in filenames
+ if not f.lower().endswith('.pyc')]
+ total += len(filenames)
+ return total
+
+ZipCommand()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,13 @@
+"""Exceptions used throughout package"""
+
+class InstallationError(Exception):
+ """General exception during installation"""
+
+class UninstallationError(Exception):
+ """General exception during uninstallation"""
+
+class DistributionNotFound(InstallationError):
+ """Raised when a distribution cannot be found to satisfy a requirement"""
+
+class BadCommand(Exception):
+ """Raised when virtualenv or a command is not found"""
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,567 @@
+"""Routines related to PyPI, indexes"""
+
+import sys
+import os
+import re
+import threading
+import posixpath
+import pkg_resources
+import urllib2
+import urlparse
+import httplib
+import socket
+from Queue import Queue
+from Queue import Empty as QueueEmpty
+from pip.log import logger
+from pip.util import Inf, path_to_url2, url_to_path
+from pip.util import normalize_name, splitext
+from pip.exceptions import DistributionNotFound
+
+__all__ = ['PackageFinder']
+
+class PackageFinder(object):
+ """This finds packages.
+
+ This is meant to match easy_install's technique for looking for
+ packages, by reading pages and looking for appropriate links
+ """
+
+ failure_limit = 3
+
+ def __init__(self, find_links, index_urls):
+ self.find_links = find_links
+ self.index_urls = index_urls
+ self.dependency_links = []
+ self.cache = PageCache()
+ # These are boring links that have already been logged somehow:
+ self.logged_links = set()
+
+ def add_dependency_links(self, links):
+ ## FIXME: this shouldn't be global list this, it should only
+ ## apply to requirements of the package that specifies the
+ ## dependency_links value
+ ## FIXME: also, we should track comes_from (i.e., use Link)
+ self.dependency_links.extend(links)
+
+ def find_requirement(self, req, upgrade):
+ url_name = req.url_name
+ # Only check main index if index URL is given:
+ main_index_url = None
+ if self.index_urls:
+ # Check that we have the url_name correctly spelled:
+ main_index_url = Link(posixpath.join(self.index_urls[0], url_name))
+ # This will also cache the page, so it's okay that we get it again later:
+ page = self._get_page(main_index_url, req)
+ if page is None:
+ url_name = self._find_url_name(Link(self.index_urls[0]), url_name, req) or req.url_name
+ def mkurl_pypi_url(url):
+ loc = posixpath.join(url, url_name)
+ # For maximum compatibility with easy_install, ensure the path
+ # ends in a trailing slash. Although this isn't in the spec
+ # (and PyPI can handle it without the slash) some other index
+ # implementations might break if they relied on easy_install's behavior.
+ if not loc.endswith('/'):
+ loc = loc + '/'
+ return loc
+ if url_name is not None:
+ locations = [
+ mkurl_pypi_url(url)
+ for url in self.index_urls] + self.find_links
+ else:
+ locations = list(self.find_links)
+ locations.extend(self.dependency_links)
+ for version in req.absolute_versions:
+ if url_name is not None and main_index_url is not None:
+ locations = [
+ posixpath.join(main_index_url.url, version)] + locations
+ file_locations = []
+ url_locations = []
+ for url in locations:
+ if url.startswith('file:'):
+ path = url_to_path(url)
+ if os.path.isdir(path):
+ path = os.path.realpath(path)
+ for item in os.listdir(path):
+ file_locations.append(
+ path_to_url2(os.path.join(path, item)))
+ elif os.path.isfile(path):
+ file_locations.append(path_to_url2(path))
+ else:
+ url_locations.append(url)
+
+ locations = [Link(url) for url in url_locations]
+ logger.debug('URLs to search for versions for %s:' % req)
+ for location in locations:
+ logger.debug('* %s' % location)
+ found_versions = []
+ found_versions.extend(
+ self._package_versions(
+ [Link(url, '-f') for url in self.find_links], req.name.lower()))
+ page_versions = []
+ for page in self._get_pages(locations, req):
+ logger.debug('Analyzing links from page %s' % page.url)
+ logger.indent += 2
+ try:
+ page_versions.extend(self._package_versions(page.links, req.name.lower()))
+ finally:
+ logger.indent -= 2
+ dependency_versions = list(self._package_versions(
+ [Link(url) for url in self.dependency_links], req.name.lower()))
+ if dependency_versions:
+ logger.info('dependency_links found: %s' % ', '.join([link.url for parsed, link, version in dependency_versions]))
+ file_versions = list(self._package_versions(
+ [Link(url) for url in file_locations], req.name.lower()))
+ if not found_versions and not page_versions and not dependency_versions and not file_versions:
+ logger.fatal('Could not find any downloads that satisfy the requirement %s' % req)
+ raise DistributionNotFound('No distributions at all found for %s' % req)
+ if req.satisfied_by is not None:
+ found_versions.append((req.satisfied_by.parsed_version, Inf, req.satisfied_by.version))
+ if file_versions:
+ file_versions.sort(reverse=True)
+ logger.info('Local files found: %s' % ', '.join([url_to_path(link.url) for parsed, link, version in file_versions]))
+ found_versions = file_versions + found_versions
+ all_versions = found_versions + page_versions + dependency_versions
+ applicable_versions = []
+ for (parsed_version, link, version) in all_versions:
+ if version not in req.req:
+ logger.info("Ignoring link %s, version %s doesn't match %s"
+ % (link, version, ','.join([''.join(s) for s in req.req.specs])))
+ continue
+ applicable_versions.append((link, version))
+ applicable_versions = sorted(applicable_versions, key=lambda v: pkg_resources.parse_version(v[1]), reverse=True)
+ existing_applicable = bool([link for link, version in applicable_versions if link is Inf])
+ if not upgrade and existing_applicable:
+ if applicable_versions[0][1] is Inf:
+ logger.info('Existing installed version (%s) is most up-to-date and satisfies requirement'
+ % req.satisfied_by.version)
+ else:
+ logger.info('Existing installed version (%s) satisfies requirement (most up-to-date version is %s)'
+ % (req.satisfied_by.version, applicable_versions[0][1]))
+ return None
+ if not applicable_versions:
+ logger.fatal('Could not find a version that satisfies the requirement %s (from versions: %s)'
+ % (req, ', '.join([version for parsed_version, link, version in found_versions])))
+ raise DistributionNotFound('No distributions matching the version for %s' % req)
+ if applicable_versions[0][0] is Inf:
+ # We have an existing version, and its the best version
+ logger.info('Installed version (%s) is most up-to-date (past versions: %s)'
+ % (req.satisfied_by.version, ', '.join([version for link, version in applicable_versions[1:]]) or 'none'))
+ return None
+ if len(applicable_versions) > 1:
+ logger.info('Using version %s (newest of versions: %s)' %
+ (applicable_versions[0][1], ', '.join([version for link, version in applicable_versions])))
+ return applicable_versions[0][0]
+
+ def _find_url_name(self, index_url, url_name, req):
+ """Finds the true URL name of a package, when the given name isn't quite correct.
+ This is usually used to implement case-insensitivity."""
+ if not index_url.url.endswith('/'):
+ # Vaguely part of the PyPI API... weird but true.
+ ## FIXME: bad to modify this?
+ index_url.url += '/'
+ page = self._get_page(index_url, req)
+ if page is None:
+ logger.fatal('Cannot fetch index base URL %s' % index_url)
+ return
+ norm_name = normalize_name(req.url_name)
+ for link in page.links:
+ base = posixpath.basename(link.path.rstrip('/'))
+ if norm_name == normalize_name(base):
+ logger.notify('Real name of requirement %s is %s' % (url_name, base))
+ return base
+ return None
+
+ def _get_pages(self, locations, req):
+ """Yields (page, page_url) from the given locations, skipping
+ locations that have errors, and adding download/homepage links"""
+ pending_queue = Queue()
+ for location in locations:
+ pending_queue.put(location)
+ done = []
+ seen = set()
+ threads = []
+ for i in range(min(10, len(locations))):
+ t = threading.Thread(target=self._get_queued_page, args=(req, pending_queue, done, seen))
+ t.setDaemon(True)
+ threads.append(t)
+ t.start()
+ for t in threads:
+ t.join()
+ return done
+
+ _log_lock = threading.Lock()
+
+ def _get_queued_page(self, req, pending_queue, done, seen):
+ while 1:
+ try:
+ location = pending_queue.get(False)
+ except QueueEmpty:
+ return
+ if location in seen:
+ continue
+ seen.add(location)
+ page = self._get_page(location, req)
+ if page is None:
+ continue
+ done.append(page)
+ for link in page.rel_links():
+ pending_queue.put(link)
+
+ _egg_fragment_re = re.compile(r'#egg=([^&]*)')
+ _egg_info_re = re.compile(r'([a-z0-9_.]+)-([a-z0-9_.-]+)', re.I)
+ _py_version_re = re.compile(r'-py([123]\.[0-9])$')
+
+ def _sort_links(self, links):
+ "Brings links in order, non-egg links first, egg links second"
+ eggs, no_eggs = [], []
+ for link in links:
+ if link.egg_fragment:
+ eggs.append(link)
+ else:
+ no_eggs.append(link)
+ return no_eggs + eggs
+
+ def _package_versions(self, links, search_name):
+ seen_links = {}
+ for link in self._sort_links(links):
+ if link.url in seen_links:
+ continue
+ seen_links[link.url] = None
+ if link.egg_fragment:
+ egg_info = link.egg_fragment
+ else:
+ path = link.path
+ egg_info, ext = link.splitext()
+ if not ext:
+ if link not in self.logged_links:
+ logger.debug('Skipping link %s; not a file' % link)
+ self.logged_links.add(link)
+ continue
+ if egg_info.endswith('.tar'):
+ # Special double-extension case:
+ egg_info = egg_info[:-4]
+ ext = '.tar' + ext
+ if ext not in ('.tar.gz', '.tar.bz2', '.tar', '.tgz', '.zip'):
+ if link not in self.logged_links:
+ logger.debug('Skipping link %s; unknown archive format: %s' % (link, ext))
+ self.logged_links.add(link)
+ continue
+ version = self._egg_info_matches(egg_info, search_name, link)
+ if version is None:
+ logger.debug('Skipping link %s; wrong project name (not %s)' % (link, search_name))
+ continue
+ match = self._py_version_re.search(version)
+ if match:
+ version = version[:match.start()]
+ py_version = match.group(1)
+ if py_version != sys.version[:3]:
+ logger.debug('Skipping %s because Python version is incorrect' % link)
+ continue
+ logger.debug('Found link %s, version: %s' % (link, version))
+ yield (pkg_resources.parse_version(version),
+ link,
+ version)
+
+ def _egg_info_matches(self, egg_info, search_name, link):
+ match = self._egg_info_re.search(egg_info)
+ if not match:
+ logger.debug('Could not parse version from link: %s' % link)
+ return None
+ name = match.group(0).lower()
+ # To match the "safe" name that pkg_resources creates:
+ name = name.replace('_', '-')
+ if name.startswith(search_name.lower()):
+ return match.group(0)[len(search_name):].lstrip('-')
+ else:
+ return None
+
+ def _get_page(self, link, req):
+ return HTMLPage.get_page(link, req, cache=self.cache)
+
+
+class PageCache(object):
+ """Cache of HTML pages"""
+
+ failure_limit = 3
+
+ def __init__(self):
+ self._failures = {}
+ self._pages = {}
+ self._archives = {}
+
+ def too_many_failures(self, url):
+ return self._failures.get(url, 0) >= self.failure_limit
+
+ def get_page(self, url):
+ return self._pages.get(url)
+
+ def is_archive(self, url):
+ return self._archives.get(url, False)
+
+ def set_is_archive(self, url, value=True):
+ self._archives[url] = value
+
+ def add_page_failure(self, url, level):
+ self._failures[url] = self._failures.get(url, 0)+level
+
+ def add_page(self, urls, page):
+ for url in urls:
+ self._pages[url] = page
+
+class HTMLPage(object):
+ """Represents one page, along with its URL"""
+
+ ## FIXME: these regexes are horrible hacks:
+ _homepage_re = re.compile(r'<th>\s*home\s*page', re.I)
+ _download_re = re.compile(r'<th>\s*download\s+url', re.I)
+ ## These aren't so aweful:
+ _rel_re = re.compile("""<[^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*>""", re.I)
+ _href_re = re.compile('href=(?:"([^"]*)"|\'([^\']*)\'|([^>\\s\\n]*))', re.I|re.S)
+ _base_re = re.compile(r"""<base\s+href\s*=\s*['"]?([^'">]+)""", re.I)
+
+ def __init__(self, content, url, headers=None):
+ self.content = content
+ self.url = url
+ self.headers = headers
+
+ def __str__(self):
+ return self.url
+
+ @classmethod
+ def get_page(cls, link, req, cache=None, skip_archives=True):
+ url = link.url
+ url = url.split('#', 1)[0]
+ if cache.too_many_failures(url):
+ return None
+ if url.lower().startswith('svn'):
+ logger.debug('Cannot look at svn URL %s' % link)
+ return None
+ if cache is not None:
+ inst = cache.get_page(url)
+ if inst is not None:
+ return inst
+ try:
+ if skip_archives:
+ if cache is not None:
+ if cache.is_archive(url):
+ return None
+ filename = link.filename
+ for bad_ext in ['.tar', '.tar.gz', '.tar.bz2', '.tgz', '.zip']:
+ if filename.endswith(bad_ext):
+ content_type = cls._get_content_type(url)
+ if content_type.lower().startswith('text/html'):
+ break
+ else:
+ logger.debug('Skipping page %s because of Content-Type: %s' % (link, content_type))
+ if cache is not None:
+ cache.set_is_archive(url)
+ return None
+ logger.debug('Getting page %s' % url)
+ resp = urllib2.urlopen(url)
+ real_url = resp.geturl()
+ headers = resp.info()
+ inst = cls(resp.read(), real_url, headers)
+ except (urllib2.HTTPError, urllib2.URLError, socket.timeout, socket.error), e:
+ desc = str(e)
+ if isinstance(e, socket.timeout):
+ log_meth = logger.info
+ level =1
+ desc = 'timed out'
+ elif isinstance(e, urllib2.URLError):
+ log_meth = logger.info
+ if hasattr(e, 'reason') and isinstance(e.reason, socket.timeout):
+ desc = 'timed out'
+ level = 1
+ else:
+ level = 2
+ elif isinstance(e, urllib2.HTTPError) and e.code == 404:
+ ## FIXME: notify?
+ log_meth = logger.info
+ level = 2
+ else:
+ log_meth = logger.info
+ level = 1
+ log_meth('Could not fetch URL %s: %s' % (link, desc))
+ log_meth('Will skip URL %s when looking for download links for %s' % (link.url, req))
+ if cache is not None:
+ cache.add_page_failure(url, level)
+ return None
+ if cache is not None:
+ cache.add_page([url, real_url], inst)
+ return inst
+
+ @staticmethod
+ def _get_content_type(url):
+ """Get the Content-Type of the given url, using a HEAD request"""
+ scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
+ if scheme == 'http':
+ ConnClass = httplib.HTTPConnection
+ elif scheme == 'https':
+ ConnClass = httplib.HTTPSConnection
+ else:
+ ## FIXME: some warning or something?
+ ## assertion error?
+ return ''
+ if query:
+ path += '?' + query
+ conn = ConnClass(netloc)
+ try:
+ conn.request('HEAD', path, headers={'Host': netloc})
+ resp = conn.getresponse()
+ if resp.status != 200:
+ ## FIXME: doesn't handle redirects
+ return ''
+ return resp.getheader('Content-Type') or ''
+ finally:
+ conn.close()
+
+ @property
+ def base_url(self):
+ if not hasattr(self, "_base_url"):
+ match = self._base_re.search(self.content)
+ if match:
+ self._base_url = match.group(1)
+ else:
+ self._base_url = self.url
+ return self._base_url
+
+ @property
+ def links(self):
+ """Yields all links in the page"""
+ for match in self._href_re.finditer(self.content):
+ url = match.group(1) or match.group(2) or match.group(3)
+ url = self.clean_link(urlparse.urljoin(self.base_url, url))
+ yield Link(url, self)
+
+ def rel_links(self):
+ for url in self.explicit_rel_links():
+ yield url
+ for url in self.scraped_rel_links():
+ yield url
+
+ def explicit_rel_links(self, rels=('homepage', 'download')):
+ """Yields all links with the given relations"""
+ for match in self._rel_re.finditer(self.content):
+ found_rels = match.group(1).lower().split()
+ for rel in rels:
+ if rel in found_rels:
+ break
+ else:
+ continue
+ match = self._href_re.search(match.group(0))
+ if not match:
+ continue
+ url = match.group(1) or match.group(2) or match.group(3)
+ url = self.clean_link(urlparse.urljoin(self.base_url, url))
+ yield Link(url, self)
+
+ def scraped_rel_links(self):
+ for regex in (self._homepage_re, self._download_re):
+ match = regex.search(self.content)
+ if not match:
+ continue
+ href_match = self._href_re.search(self.content, pos=match.end())
+ if not href_match:
+ continue
+ url = match.group(1) or match.group(2) or match.group(3)
+ if not url:
+ continue
+ url = self.clean_link(urlparse.urljoin(self.base_url, url))
+ yield Link(url, self)
+
+ _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I)
+
+ def clean_link(self, url):
+ """Makes sure a link is fully encoded. That is, if a ' ' shows up in
+ the link, it will be rewritten to %20 (while not over-quoting
+ % or other characters)."""
+ return self._clean_re.sub(
+ lambda match: '%%%2x' % ord(match.group(0)), url)
+
+class Link(object):
+
+ def __init__(self, url, comes_from=None):
+ self.url = url
+ self.comes_from = comes_from
+
+ def __str__(self):
+ if self.comes_from:
+ return '%s (from %s)' % (self.url, self.comes_from)
+ else:
+ return self.url
+
+ def __repr__(self):
+ return '<Link %s>' % self
+
+ def __eq__(self, other):
+ return self.url == other.url
+
+ def __hash__(self):
+ return hash(self.url)
+
+ @property
+ def filename(self):
+ url = self.url
+ url = url.split('#', 1)[0]
+ url = url.split('?', 1)[0]
+ url = url.rstrip('/')
+ name = posixpath.basename(url)
+ assert name, (
+ 'URL %r produced no filename' % url)
+ return name
+
+ @property
+ def scheme(self):
+ return urlparse.urlsplit(self.url)[0]
+
+ @property
+ def path(self):
+ return urlparse.urlsplit(self.url)[2]
+
+ def splitext(self):
+ return splitext(posixpath.basename(self.path.rstrip('/')))
+
+ _egg_fragment_re = re.compile(r'#egg=([^&]*)')
+
+ @property
+ def egg_fragment(self):
+ match = self._egg_fragment_re.search(self.url)
+ if not match:
+ return None
+ return match.group(1)
+
+ _md5_re = re.compile(r'md5=([a-f0-9]+)')
+
+ @property
+ def md5_hash(self):
+ match = self._md5_re.search(self.url)
+ if match:
+ return match.group(1)
+ return None
+
+ @property
+ def show_url(self):
+ return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0])
+
+def get_requirement_from_url(url):
+ """Get a requirement from the URL, if possible. This looks for #egg
+ in the URL"""
+ link = Link(url)
+ egg_info = link.egg_fragment
+ if not egg_info:
+ egg_info = splitext(link.filename)[0]
+ return package_to_requirement(egg_info)
+
+def package_to_requirement(package_name):
+ """Translate a name like Foo-1.2 to Foo==1.3"""
+ match = re.search(r'^(.*?)(-dev|-\d.*)', package_name)
+ if match:
+ name = match.group(1)
+ version = match.group(2)
+ else:
+ name = package_name
+ version = ''
+ if version:
+ return '%s==%s' % (name, version)
+ else:
+ return name
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,36 @@
+"""Locations where we look for configs, install stuff, etc"""
+
+import sys
+import os
+from distutils import sysconfig
+
+if getattr(sys, 'real_prefix', None):
+ ## FIXME: is build/ a good name?
+ build_prefix = os.path.join(sys.prefix, 'build')
+ src_prefix = os.path.join(sys.prefix, 'src')
+else:
+ ## FIXME: this isn't a very good default
+ build_prefix = os.path.join(os.getcwd(), 'build')
+ src_prefix = os.path.join(os.getcwd(), 'src')
+
+# FIXME doesn't account for venv linked to global site-packages
+
+site_packages = sysconfig.get_python_lib()
+user_dir = os.path.expanduser('~')
+if sys.platform == 'win32':
+ bin_py = os.path.join(sys.prefix, 'Scripts')
+ # buildout uses 'bin' on Windows too?
+ if not os.path.exists(bin_py):
+ bin_py = os.path.join(sys.prefix, 'bin')
+ user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming
+ default_storage_dir = os.path.join(user_dir, 'pip')
+ default_config_file = os.path.join(default_storage_dir, 'pip.ini')
+ default_log_file = os.path.join(default_storage_dir, 'pip.log')
+else:
+ bin_py = os.path.join(sys.prefix, 'bin')
+ default_storage_dir = os.path.join(user_dir, '.pip')
+ default_config_file = os.path.join(default_storage_dir, 'pip.conf')
+ default_log_file = os.path.join(default_storage_dir, 'pip.log')
+ # Forcing to use /usr/local/bin for standard Mac OS X framework installs
+ if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
+ bin_py = '/usr/local/bin'
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,174 @@
+"""Logging
+"""
+
+import sys
+import logging
+
+class Logger(object):
+
+ """
+ Logging object for use in command-line script. Allows ranges of
+ levels, to avoid some redundancy of displayed information.
+ """
+
+ VERBOSE_DEBUG = logging.DEBUG-1
+ DEBUG = logging.DEBUG
+ INFO = logging.INFO
+ NOTIFY = (logging.INFO+logging.WARN)/2
+ WARN = WARNING = logging.WARN
+ ERROR = logging.ERROR
+ FATAL = logging.FATAL
+
+ LEVELS = [VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
+
+ def __init__(self):
+ self.consumers = []
+ self.indent = 0
+ self.explicit_levels = False
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def debug(self, msg, *args, **kw):
+ self.log(self.DEBUG, msg, *args, **kw)
+ def info(self, msg, *args, **kw):
+ self.log(self.INFO, msg, *args, **kw)
+ def notify(self, msg, *args, **kw):
+ self.log(self.NOTIFY, msg, *args, **kw)
+ def warn(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def error(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def fatal(self, msg, *args, **kw):
+ self.log(self.FATAL, msg, *args, **kw)
+ def log(self, level, msg, *args, **kw):
+ if args:
+ if kw:
+ raise TypeError(
+ "You may give positional or keyword arguments, not both")
+ args = args or kw
+ rendered = None
+ for consumer_level, consumer in self.consumers:
+ if self.level_matches(level, consumer_level):
+ if (self.in_progress_hanging
+ and consumer in (sys.stdout, sys.stderr)):
+ self.in_progress_hanging = False
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ if rendered is None:
+ if args:
+ rendered = msg % args
+ else:
+ rendered = msg
+ rendered = ' '*self.indent + rendered
+ if self.explicit_levels:
+ ## FIXME: should this be a name, not a level number?
+ rendered = '%02i %s' % (level, rendered)
+ if hasattr(consumer, 'write'):
+ consumer.write(rendered+'\n')
+ else:
+ consumer(rendered)
+
+ def start_progress(self, msg):
+ assert not self.in_progress, (
+ "Tried to start_progress(%r) while in_progress %r"
+ % (msg, self.in_progress))
+ if self.level_matches(self.NOTIFY, self._stdout_level()):
+ sys.stdout.write(' '*self.indent + msg)
+ sys.stdout.flush()
+ self.in_progress_hanging = True
+ else:
+ self.in_progress_hanging = False
+ self.in_progress = msg
+ self.last_message = None
+
+ def end_progress(self, msg='done.'):
+ assert self.in_progress, (
+ "Tried to end_progress without start_progress")
+ if self.stdout_level_matches(self.NOTIFY):
+ if not self.in_progress_hanging:
+ # Some message has been printed out since start_progress
+ sys.stdout.write('...' + self.in_progress + msg + '\n')
+ sys.stdout.flush()
+ else:
+ # These erase any messages shown with show_progress (besides .'s)
+ logger.show_progress('')
+ logger.show_progress('')
+ sys.stdout.write(msg + '\n')
+ sys.stdout.flush()
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def show_progress(self, message=None):
+ """If we are in a progress scope, and no log messages have been
+ shown, write out another '.'"""
+ if self.in_progress_hanging:
+ if message is None:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ else:
+ if self.last_message:
+ padding = ' ' * max(0, len(self.last_message)-len(message))
+ else:
+ padding = ''
+ sys.stdout.write('\r%s%s%s%s' % (' '*self.indent, self.in_progress, message, padding))
+ sys.stdout.flush()
+ self.last_message = message
+
+ def stdout_level_matches(self, level):
+ """Returns true if a message at this level will go to stdout"""
+ return self.level_matches(level, self._stdout_level())
+
+ def _stdout_level(self):
+ """Returns the level that stdout runs at"""
+ for level, consumer in self.consumers:
+ if consumer is sys.stdout:
+ return level
+ return self.FATAL
+
+ def level_matches(self, level, consumer_level):
+ """
+ >>> l = Logger()
+ >>> l.level_matches(3, 4)
+ False
+ >>> l.level_matches(3, 2)
+ True
+ >>> l.level_matches(slice(None, 3), 3)
+ False
+ >>> l.level_matches(slice(None, 3), 2)
+ True
+ >>> l.level_matches(slice(1, 3), 1)
+ True
+ >>> l.level_matches(slice(2, 3), 1)
+ False
+ """
+ if isinstance(level, slice):
+ start, stop = level.start, level.stop
+ if start is not None and start > consumer_level:
+ return False
+ if stop is not None or stop <= consumer_level:
+ return False
+ return True
+ else:
+ return level >= consumer_level
+
+ @classmethod
+ def level_for_integer(cls, level):
+ levels = cls.LEVELS
+ if level < 0:
+ return levels[0]
+ if level >= len(levels):
+ return levels[-1]
+ return levels[level]
+
+ def move_stdout_to_stderr(self):
+ to_remove = []
+ to_add = []
+ for consumer_level, consumer in self.consumers:
+ if consumer == sys.stdout:
+ to_remove.append((consumer_level, consumer))
+ to_add.append((consumer_level, sys.stderr))
+ for item in to_remove:
+ self.consumers.remove(item)
+ self.consumers.extend(to_add)
+
+logger = Logger()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,1604 @@
+import sys
+import os
+import shutil
+import re
+import zipfile
+import tarfile
+import pkg_resources
+import tempfile
+import mimetypes
+import urlparse
+import urllib2
+import urllib
+import ConfigParser
+from distutils.sysconfig import get_python_version
+from email.FeedParser import FeedParser
+from pip.locations import bin_py
+from pip.exceptions import InstallationError, UninstallationError
+from pip.vcs import vcs
+from pip.log import logger
+from pip.util import display_path, rmtree, format_size
+from pip.util import splitext, ask, backup_dir
+from pip.util import url_to_path, path_to_url
+from pip.util import is_url, is_installable_dir, is_archive_file, is_local, dist_is_local
+from pip.util import renames, normalize_path, egg_link_path
+from pip.util import make_path_relative, is_svn_page, file_contents
+from pip.util import has_leading_dir, split_leading_dir
+from pip.util import get_file_content
+from pip.util import in_venv
+from pip import call_subprocess
+from pip.backwardcompat import any, md5
+from pip.index import Link
+
+class InstallRequirement(object):
+
+ def __init__(self, req, comes_from, source_dir=None, editable=False,
+ url=None, update=True):
+ if isinstance(req, basestring):
+ req = pkg_resources.Requirement.parse(req)
+ self.req = req
+ self.comes_from = comes_from
+ self.source_dir = source_dir
+ self.editable = editable
+ self.url = url
+ self._egg_info_path = None
+ # This holds the pkg_resources.Distribution object if this requirement
+ # is already available:
+ self.satisfied_by = None
+ # This hold the pkg_resources.Distribution object if this requirement
+ # conflicts with another installed distribution:
+ self.conflicts_with = None
+ self._temp_build_dir = None
+ self._is_bundle = None
+ # True if the editable should be updated:
+ self.update = update
+ # Set to True after successful installation
+ self.install_succeeded = None
+ # UninstallPathSet of uninstalled distribution (for possible rollback)
+ self.uninstalled = None
+
+ @classmethod
+ def from_editable(cls, editable_req, comes_from=None, default_vcs=None):
+ name, url = parse_editable(editable_req, default_vcs)
+ if url.startswith('file:'):
+ source_dir = url_to_path(url)
+ else:
+ source_dir = None
+ return cls(name, comes_from, source_dir=source_dir, editable=True, url=url)
+
+ @classmethod
+ def from_line(cls, name, comes_from=None):
+ """Creates an InstallRequirement from a name, which might be a
+ requirement, directory containing 'setup.py', filename, or URL.
+ """
+ url = None
+ name = name.strip()
+ req = name
+ path = os.path.normpath(os.path.abspath(name))
+
+ if is_url(name):
+ url = name
+ ## FIXME: I think getting the requirement here is a bad idea:
+ #req = get_requirement_from_url(url)
+ req = None
+ elif os.path.isdir(path):
+ if not is_installable_dir(path):
+ raise InstallationError("Directory %r is not installable. File 'setup.py' not found."
+ % name)
+ url = path_to_url(name)
+ #req = get_requirement_from_url(url)
+ req = None
+ elif is_archive_file(path):
+ if not os.path.isfile(path):
+ logger.warn('Requirement %r looks like a filename, but the file does not exist'
+ % name)
+ url = path_to_url(name)
+ #req = get_requirement_from_url(url)
+ req = None
+ return cls(req, comes_from, url=url)
+
+ def __str__(self):
+ if self.req:
+ s = str(self.req)
+ if self.url:
+ s += ' from %s' % self.url
+ else:
+ s = self.url
+ if self.satisfied_by is not None:
+ s += ' in %s' % display_path(self.satisfied_by.location)
+ if self.comes_from:
+ if isinstance(self.comes_from, basestring):
+ comes_from = self.comes_from
+ else:
+ comes_from = self.comes_from.from_path()
+ if comes_from:
+ s += ' (from %s)' % comes_from
+ return s
+
+ def from_path(self):
+ if self.req is None:
+ return None
+ s = str(self.req)
+ if self.comes_from:
+ if isinstance(self.comes_from, basestring):
+ comes_from = self.comes_from
+ else:
+ comes_from = self.comes_from.from_path()
+ if comes_from:
+ s += '->' + comes_from
+ return s
+
+ def build_location(self, build_dir, unpack=True):
+ if self._temp_build_dir is not None:
+ return self._temp_build_dir
+ if self.req is None:
+ self._temp_build_dir = tempfile.mkdtemp('-build', 'pip-')
+ self._ideal_build_dir = build_dir
+ return self._temp_build_dir
+ if self.editable:
+ name = self.name.lower()
+ else:
+ name = self.name
+ # FIXME: Is there a better place to create the build_dir? (hg and bzr need this)
+ if not os.path.exists(build_dir):
+ os.makedirs(build_dir)
+ return os.path.join(build_dir, name)
+
+ def correct_build_location(self):
+ """If the build location was a temporary directory, this will move it
+ to a new more permanent location"""
+ if self.source_dir is not None:
+ return
+ assert self.req is not None
+ assert self._temp_build_dir
+ old_location = self._temp_build_dir
+ new_build_dir = self._ideal_build_dir
+ del self._ideal_build_dir
+ if self.editable:
+ name = self.name.lower()
+ else:
+ name = self.name
+ new_location = os.path.join(new_build_dir, name)
+ if not os.path.exists(new_build_dir):
+ logger.debug('Creating directory %s' % new_build_dir)
+ os.makedirs(new_build_dir)
+ if os.path.exists(new_location):
+ raise InstallationError(
+ 'A package already exists in %s; please remove it to continue'
+ % display_path(new_location))
+ logger.debug('Moving package %s from %s to new location %s'
+ % (self, display_path(old_location), display_path(new_location)))
+ shutil.move(old_location, new_location)
+ self._temp_build_dir = new_location
+ self.source_dir = new_location
+ self._egg_info_path = None
+
+ @property
+ def name(self):
+ if self.req is None:
+ return None
+ return self.req.project_name
+
+ @property
+ def url_name(self):
+ if self.req is None:
+ return None
+ return urllib.quote(self.req.unsafe_name)
+
+ @property
+ def setup_py(self):
+ return os.path.join(self.source_dir, 'setup.py')
+
+ def run_egg_info(self, force_root_egg_info=False):
+ assert self.source_dir
+ if self.name:
+ logger.notify('Running setup.py egg_info for package %s' % self.name)
+ else:
+ logger.notify('Running setup.py egg_info for package from %s' % self.url)
+ logger.indent += 2
+ try:
+ script = self._run_setup_py
+ script = script.replace('__SETUP_PY__', repr(self.setup_py))
+ script = script.replace('__PKG_NAME__', repr(self.name))
+ # We can't put the .egg-info files at the root, because then the source code will be mistaken
+ # for an installed egg, causing problems
+ if self.editable or force_root_egg_info:
+ egg_base_option = []
+ else:
+ egg_info_dir = os.path.join(self.source_dir, 'pip-egg-info')
+ if not os.path.exists(egg_info_dir):
+ os.makedirs(egg_info_dir)
+ egg_base_option = ['--egg-base', 'pip-egg-info']
+ call_subprocess(
+ [sys.executable, '-c', script, 'egg_info'] + egg_base_option,
+ cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False,
+ command_level=logger.VERBOSE_DEBUG,
+ command_desc='python setup.py egg_info')
+ finally:
+ logger.indent -= 2
+ if not self.req:
+ self.req = pkg_resources.Requirement.parse(self.pkg_info()['Name'])
+ self.correct_build_location()
+
+ ## FIXME: This is a lame hack, entirely for PasteScript which has
+ ## a self-provided entry point that causes this awkwardness
+ _run_setup_py = """
+__file__ = __SETUP_PY__
+from setuptools.command import egg_info
+def replacement_run(self):
+ self.mkpath(self.egg_info)
+ installer = self.distribution.fetch_build_egg
+ for ep in egg_info.iter_entry_points('egg_info.writers'):
+ # require=False is the change we're making:
+ writer = ep.load(require=False)
+ if writer:
+ writer(self, ep.name, egg_info.os.path.join(self.egg_info,ep.name))
+ self.find_sources()
+egg_info.egg_info.run = replacement_run
+execfile(__file__)
+"""
+
+ def egg_info_data(self, filename):
+ if self.satisfied_by is not None:
+ if not self.satisfied_by.has_metadata(filename):
+ return None
+ return self.satisfied_by.get_metadata(filename)
+ assert self.source_dir
+ filename = self.egg_info_path(filename)
+ if not os.path.exists(filename):
+ return None
+ fp = open(filename, 'r')
+ data = fp.read()
+ fp.close()
+ return data
+
+ def egg_info_path(self, filename):
+ if self._egg_info_path is None:
+ if self.editable:
+ base = self.source_dir
+ else:
+ base = os.path.join(self.source_dir, 'pip-egg-info')
+ filenames = os.listdir(base)
+ if self.editable:
+ filenames = []
+ for root, dirs, files in os.walk(base):
+ for dir in vcs.dirnames:
+ if dir in dirs:
+ dirs.remove(dir)
+ for dir in dirs:
+ # Don't search in anything that looks like a virtualenv environment
+ if (os.path.exists(os.path.join(root, dir, 'bin', 'python'))
+ or os.path.exists(os.path.join(root, dir, 'Scripts', 'Python.exe'))):
+ dirs.remove(dir)
+ # Also don't search through tests
+ if dir == 'test' or dir == 'tests':
+ dirs.remove(dir)
+ filenames.extend([os.path.join(root, dir)
+ for dir in dirs])
+ filenames = [f for f in filenames if f.endswith('.egg-info')]
+ assert filenames, "No files/directories in %s (from %s)" % (base, filename)
+ assert len(filenames) == 1, "Unexpected files/directories in %s: %s" % (base, ' '.join(filenames))
+ self._egg_info_path = os.path.join(base, filenames[0])
+ return os.path.join(self._egg_info_path, filename)
+
+ def egg_info_lines(self, filename):
+ data = self.egg_info_data(filename)
+ if not data:
+ return []
+ result = []
+ for line in data.splitlines():
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ result.append(line)
+ return result
+
+ def pkg_info(self):
+ p = FeedParser()
+ data = self.egg_info_data('PKG-INFO')
+ if not data:
+ logger.warn('No PKG-INFO file found in %s' % display_path(self.egg_info_path('PKG-INFO')))
+ p.feed(data or '')
+ return p.close()
+
+ @property
+ def dependency_links(self):
+ return self.egg_info_lines('dependency_links.txt')
+
+ _requirements_section_re = re.compile(r'\[(.*?)\]')
+
+ def requirements(self, extras=()):
+ in_extra = None
+ for line in self.egg_info_lines('requires.txt'):
+ match = self._requirements_section_re.match(line)
+ if match:
+ in_extra = match.group(1)
+ continue
+ if in_extra and in_extra not in extras:
+ # Skip requirement for an extra we aren't requiring
+ continue
+ yield line
+
+ @property
+ def absolute_versions(self):
+ for qualifier, version in self.req.specs:
+ if qualifier == '==':
+ yield version
+
+ @property
+ def installed_version(self):
+ return self.pkg_info()['version']
+
+ def assert_source_matches_version(self):
+ assert self.source_dir
+ if self.comes_from is None:
+ # We don't check the versions of things explicitly installed.
+ # This makes, e.g., "pip Package==dev" possible
+ return
+ version = self.installed_version
+ if version not in self.req:
+ logger.fatal(
+ 'Source in %s has the version %s, which does not match the requirement %s'
+ % (display_path(self.source_dir), version, self))
+ raise InstallationError(
+ 'Source in %s has version %s that conflicts with %s'
+ % (display_path(self.source_dir), version, self))
+ else:
+ logger.debug('Source in %s has version %s, which satisfies requirement %s'
+ % (display_path(self.source_dir), version, self))
+
+ def update_editable(self, obtain=True):
+ if not self.url:
+ logger.info("Cannot update repository at %s; repository location is unknown" % self.source_dir)
+ return
+ assert self.editable
+ assert self.source_dir
+ if self.url.startswith('file:'):
+ # Static paths don't get updated
+ return
+ assert '+' in self.url, "bad url: %r" % self.url
+ if not self.update:
+ return
+ vc_type, url = self.url.split('+', 1)
+ backend = vcs.get_backend(vc_type)
+ if backend:
+ vcs_backend = backend(self.url)
+ if obtain:
+ vcs_backend.obtain(self.source_dir)
+ else:
+ vcs_backend.export(self.source_dir)
+ else:
+ assert 0, (
+ 'Unexpected version control type (in %s): %s'
+ % (self.url, vc_type))
+
+ def uninstall(self, auto_confirm=False):
+ """
+ Uninstall the distribution currently satisfying this requirement.
+
+ Prompts before removing or modifying files unless
+ ``auto_confirm`` is True.
+
+ Refuses to delete or modify files outside of ``sys.prefix`` -
+ thus uninstallation within a virtual environment can only
+ modify that virtual environment, even if the virtualenv is
+ linked to global site-packages.
+
+ """
+ if not self.check_if_exists():
+ raise UninstallationError("Cannot uninstall requirement %s, not installed" % (self.name,))
+ dist = self.satisfied_by or self.conflicts_with
+
+ paths_to_remove = UninstallPathSet(dist)
+
+ pip_egg_info_path = os.path.join(dist.location,
+ dist.egg_name()) + '.egg-info'
+ easy_install_egg = dist.egg_name() + '.egg'
+ develop_egg_link = egg_link_path(dist)
+ if os.path.exists(pip_egg_info_path):
+ # package installed by pip
+ paths_to_remove.add(pip_egg_info_path)
+ if dist.has_metadata('installed-files.txt'):
+ for installed_file in dist.get_metadata('installed-files.txt').splitlines():
+ path = os.path.normpath(os.path.join(pip_egg_info_path, installed_file))
+ paths_to_remove.add(path)
+ if dist.has_metadata('top_level.txt'):
+ if dist.has_metadata('namespace_packages.txt'):
+ namespaces = dist.get_metadata('namespace_packages.txt')
+ else:
+ namespaces = []
+ for top_level_pkg in [p for p
+ in dist.get_metadata('top_level.txt').splitlines()
+ if p and p not in namespaces]:
+ path = os.path.join(dist.location, top_level_pkg)
+ paths_to_remove.add(path)
+ paths_to_remove.add(path + '.py')
+ paths_to_remove.add(path + '.pyc')
+
+ elif dist.location.endswith(easy_install_egg):
+ # package installed by easy_install
+ paths_to_remove.add(dist.location)
+ easy_install_pth = os.path.join(os.path.dirname(dist.location),
+ 'easy-install.pth')
+ paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg)
+
+ elif os.path.isfile(develop_egg_link):
+ # develop egg
+ fh = open(develop_egg_link, 'r')
+ link_pointer = os.path.normcase(fh.readline().strip())
+ fh.close()
+ assert (link_pointer == dist.location), 'Egg-link %s does not match installed location of %s (at %s)' % (link_pointer, self.name, dist.location)
+ paths_to_remove.add(develop_egg_link)
+ easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
+ 'easy-install.pth')
+ paths_to_remove.add_pth(easy_install_pth, dist.location)
+
+ # find distutils scripts= scripts
+ if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'):
+ for script in dist.metadata_listdir('scripts'):
+ paths_to_remove.add(os.path.join(bin_py, script))
+ if sys.platform == 'win32':
+ paths_to_remove.add(os.path.join(bin_py, script) + '.bat')
+
+ # find console_scripts
+ if dist.has_metadata('entry_points.txt'):
+ config = ConfigParser.SafeConfigParser()
+ config.readfp(FakeFile(dist.get_metadata_lines('entry_points.txt')))
+ if config.has_section('console_scripts'):
+ for name, value in config.items('console_scripts'):
+ paths_to_remove.add(os.path.join(bin_py, name))
+ if sys.platform == 'win32':
+ paths_to_remove.add(os.path.join(bin_py, name) + '.exe')
+ paths_to_remove.add(os.path.join(bin_py, name) + '-script.py')
+
+ paths_to_remove.remove(auto_confirm)
+ self.uninstalled = paths_to_remove
+
+ def rollback_uninstall(self):
+ if self.uninstalled:
+ self.uninstalled.rollback()
+ else:
+ logger.error("Can't rollback %s, nothing uninstalled."
+ % (self.project_name,))
+
+ def commit_uninstall(self):
+ if self.uninstalled:
+ self.uninstalled.commit()
+ else:
+ logger.error("Can't commit %s, nothing uninstalled."
+ % (self.project_name,))
+
+ def archive(self, build_dir):
+ assert self.source_dir
+ create_archive = True
+ archive_name = '%s-%s.zip' % (self.name, self.installed_version)
+ archive_path = os.path.join(build_dir, archive_name)
+ if os.path.exists(archive_path):
+ response = ask('The file %s exists. (i)gnore, (w)ipe, (b)ackup '
+ % display_path(archive_path), ('i', 'w', 'b'))
+ if response == 'i':
+ create_archive = False
+ elif response == 'w':
+ logger.warn('Deleting %s' % display_path(archive_path))
+ os.remove(archive_path)
+ elif response == 'b':
+ dest_file = backup_dir(archive_path)
+ logger.warn('Backing up %s to %s'
+ % (display_path(archive_path), display_path(dest_file)))
+ shutil.move(archive_path, dest_file)
+ if create_archive:
+ zip = zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED)
+ dir = os.path.normcase(os.path.abspath(self.source_dir))
+ for dirpath, dirnames, filenames in os.walk(dir):
+ if 'pip-egg-info' in dirnames:
+ dirnames.remove('pip-egg-info')
+ for dirname in dirnames:
+ dirname = os.path.join(dirpath, dirname)
+ name = self._clean_zip_name(dirname, dir)
+ zipdir = zipfile.ZipInfo(self.name + '/' + name + '/')
+ zipdir.external_attr = 0755 << 16L
+ zip.writestr(zipdir, '')
+ for filename in filenames:
+ if filename == 'pip-delete-this-directory.txt':
+ continue
+ filename = os.path.join(dirpath, filename)
+ name = self._clean_zip_name(filename, dir)
+ zip.write(filename, self.name + '/' + name)
+ zip.close()
+ logger.indent -= 2
+ logger.notify('Saved %s' % display_path(archive_path))
+
+ def _clean_zip_name(self, name, prefix):
+ assert name.startswith(prefix+'/'), (
+ "name %r doesn't start with prefix %r" % (name, prefix))
+ name = name[len(prefix)+1:]
+ name = name.replace(os.path.sep, '/')
+ return name
+
+ def install(self, install_options):
+ if self.editable:
+ self.install_editable()
+ return
+ temp_location = tempfile.mkdtemp('-record', 'pip-')
+ record_filename = os.path.join(temp_location, 'install-record.txt')
+ try:
+
+ install_args = [sys.executable, '-c',
+ "import setuptools; __file__=%r; execfile(%r)" % (self.setup_py, self.setup_py),
+ 'install', '--single-version-externally-managed', '--record', record_filename]
+
+ if in_venv():
+ ## FIXME: I'm not sure if this is a reasonable location; probably not
+ ## but we can't put it in the default location, as that is a virtualenv symlink that isn't writable
+ install_args += ['--install-headers',
+ os.path.join(sys.prefix, 'include', 'site',
+ 'python' + get_python_version())]
+ logger.notify('Running setup.py install for %s' % self.name)
+ logger.indent += 2
+ try:
+ call_subprocess(install_args + install_options,
+ cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False)
+ finally:
+ logger.indent -= 2
+ self.install_succeeded = True
+ f = open(record_filename)
+ for line in f:
+ line = line.strip()
+ if line.endswith('.egg-info'):
+ egg_info_dir = line
+ break
+ else:
+ logger.warn('Could not find .egg-info directory in install record for %s' % self)
+ ## FIXME: put the record somewhere
+ ## FIXME: should this be an error?
+ return
+ f.close()
+ new_lines = []
+ f = open(record_filename)
+ for line in f:
+ filename = line.strip()
+ if os.path.isdir(filename):
+ filename += os.path.sep
+ new_lines.append(make_path_relative(filename, egg_info_dir))
+ f.close()
+ f = open(os.path.join(egg_info_dir, 'installed-files.txt'), 'w')
+ f.write('\n'.join(new_lines)+'\n')
+ f.close()
+ finally:
+ if os.path.exists(record_filename):
+ os.remove(record_filename)
+ os.rmdir(temp_location)
+
+ def remove_temporary_source(self):
+ """Remove the source files from this requirement, if they are marked
+ for deletion"""
+ if self.is_bundle or os.path.exists(self.delete_marker_filename):
+ logger.info('Removing source in %s' % self.source_dir)
+ if self.source_dir:
+ rmtree(self.source_dir)
+ self.source_dir = None
+ if self._temp_build_dir and os.path.exists(self._temp_build_dir):
+ rmtree(self._temp_build_dir)
+ self._temp_build_dir = None
+
+ def install_editable(self):
+ logger.notify('Running setup.py develop for %s' % self.name)
+ logger.indent += 2
+ try:
+ ## FIXME: should we do --install-headers here too?
+ call_subprocess(
+ [sys.executable, '-c',
+ "import setuptools; __file__=%r; execfile(%r)" % (self.setup_py, self.setup_py),
+ 'develop', '--no-deps'], cwd=self.source_dir, filter_stdout=self._filter_install,
+ show_stdout=False)
+ finally:
+ logger.indent -= 2
+ self.install_succeeded = True
+
+ def _filter_install(self, line):
+ level = logger.NOTIFY
+ for regex in [r'^running .*', r'^writing .*', '^creating .*', '^[Cc]opying .*',
+ r'^reading .*', r"^removing .*\.egg-info' \(and everything under it\)$",
+ r'^byte-compiling ',
+ # Not sure what this warning is, but it seems harmless:
+ r"^warning: manifest_maker: standard file '-c' not found$"]:
+ if re.search(regex, line.strip()):
+ level = logger.INFO
+ break
+ return (level, line)
+
+ def check_if_exists(self):
+ """Find an installed distribution that satisfies or conflicts
+ with this requirement, and set self.satisfied_by or
+ self.conflicts_with appropriately."""
+ if self.req is None:
+ return False
+ try:
+ self.satisfied_by = pkg_resources.get_distribution(self.req)
+ except pkg_resources.DistributionNotFound:
+ return False
+ except pkg_resources.VersionConflict:
+ self.conflicts_with = pkg_resources.get_distribution(self.req.project_name)
+ return True
+
+ @property
+ def is_bundle(self):
+ if self._is_bundle is not None:
+ return self._is_bundle
+ base = self._temp_build_dir
+ if not base:
+ ## FIXME: this doesn't seem right:
+ return False
+ self._is_bundle = (os.path.exists(os.path.join(base, 'pip-manifest.txt'))
+ or os.path.exists(os.path.join(base, 'pyinstall-manifest.txt')))
+ return self._is_bundle
+
+ def bundle_requirements(self):
+ for dest_dir in self._bundle_editable_dirs:
+ package = os.path.basename(dest_dir)
+ ## FIXME: svnism:
+ for vcs_backend in vcs.backends:
+ url = rev = None
+ vcs_bundle_file = os.path.join(
+ dest_dir, vcs_backend.bundle_file)
+ if os.path.exists(vcs_bundle_file):
+ vc_type = vcs_backend.name
+ fp = open(vcs_bundle_file)
+ content = fp.read()
+ fp.close()
+ url, rev = vcs_backend().parse_vcs_bundle_file(content)
+ break
+ if url:
+ url = '%s+%s@%s' % (vc_type, url, rev)
+ else:
+ url = None
+ yield InstallRequirement(
+ package, self, editable=True, url=url,
+ update=False, source_dir=dest_dir)
+ for dest_dir in self._bundle_build_dirs:
+ package = os.path.basename(dest_dir)
+ yield InstallRequirement(
+ package, self,
+ source_dir=dest_dir)
+
+ def move_bundle_files(self, dest_build_dir, dest_src_dir):
+ base = self._temp_build_dir
+ assert base
+ src_dir = os.path.join(base, 'src')
+ build_dir = os.path.join(base, 'build')
+ bundle_build_dirs = []
+ bundle_editable_dirs = []
+ for source_dir, dest_dir, dir_collection in [
+ (src_dir, dest_src_dir, bundle_editable_dirs),
+ (build_dir, dest_build_dir, bundle_build_dirs)]:
+ if os.path.exists(source_dir):
+ for dirname in os.listdir(source_dir):
+ dest = os.path.join(dest_dir, dirname)
+ dir_collection.append(dest)
+ if os.path.exists(dest):
+ logger.warn('The directory %s (containing package %s) already exists; cannot move source from bundle %s'
+ % (dest, dirname, self))
+ continue
+ if not os.path.exists(dest_dir):
+ logger.info('Creating directory %s' % dest_dir)
+ os.makedirs(dest_dir)
+ shutil.move(os.path.join(source_dir, dirname), dest)
+ if not os.listdir(source_dir):
+ os.rmdir(source_dir)
+ self._temp_build_dir = None
+ self._bundle_build_dirs = bundle_build_dirs
+ self._bundle_editable_dirs = bundle_editable_dirs
+
+ @property
+ def delete_marker_filename(self):
+ assert self.source_dir
+ return os.path.join(self.source_dir, 'pip-delete-this-directory.txt')
+
+DELETE_MARKER_MESSAGE = '''\
+This file is placed here by pip to indicate the source was put
+here by pip.
+
+Once this package is successfully installed this source code will be
+deleted (unless you remove this file).
+'''
+
+class RequirementSet(object):
+
+ def __init__(self, build_dir, src_dir, download_dir, download_cache=None,
+ upgrade=False, ignore_installed=False,
+ ignore_dependencies=False):
+ self.build_dir = build_dir
+ self.src_dir = src_dir
+ self.download_dir = download_dir
+ self.download_cache = download_cache
+ self.upgrade = upgrade
+ self.ignore_installed = ignore_installed
+ self.requirements = {}
+ # Mapping of alias: real_name
+ self.requirement_aliases = {}
+ self.unnamed_requirements = []
+ self.ignore_dependencies = ignore_dependencies
+ self.successfully_downloaded = []
+ self.successfully_installed = []
+ self.reqs_to_cleanup = []
+
+ def __str__(self):
+ reqs = [req for req in self.requirements.values()
+ if not req.comes_from]
+ reqs.sort(key=lambda req: req.name.lower())
+ return ' '.join([str(req.req) for req in reqs])
+
+ def add_requirement(self, install_req):
+ name = install_req.name
+ if not name:
+ self.unnamed_requirements.append(install_req)
+ else:
+ if self.has_requirement(name):
+ raise InstallationError(
+ 'Double requirement given: %s (aready in %s, name=%r)'
+ % (install_req, self.get_requirement(name), name))
+ self.requirements[name] = install_req
+ ## FIXME: what about other normalizations? E.g., _ vs. -?
+ if name.lower() != name:
+ self.requirement_aliases[name.lower()] = name
+
+ def has_requirement(self, project_name):
+ for name in project_name, project_name.lower():
+ if name in self.requirements or name in self.requirement_aliases:
+ return True
+ return False
+
+ @property
+ def is_download(self):
+ if self.download_dir:
+ self.download_dir = os.path.expanduser(self.download_dir)
+ if os.path.exists(self.download_dir):
+ return True
+ else:
+ logger.fatal('Could not find download directory')
+ raise InstallationError(
+ "Could not find or access download directory '%s'"
+ % display_path(self.download_dir))
+ return False
+
+ def get_requirement(self, project_name):
+ for name in project_name, project_name.lower():
+ if name in self.requirements:
+ return self.requirements[name]
+ if name in self.requirement_aliases:
+ return self.requirements[self.requirement_aliases[name]]
+ raise KeyError("No project with the name %r" % project_name)
+
+ def uninstall(self, auto_confirm=False):
+ for req in self.requirements.values():
+ req.uninstall(auto_confirm=auto_confirm)
+ req.commit_uninstall()
+
+ def locate_files(self):
+ ## FIXME: duplicates code from install_files; relevant code should
+ ## probably be factored out into a separate method
+ unnamed = list(self.unnamed_requirements)
+ reqs = self.requirements.values()
+ while reqs or unnamed:
+ if unnamed:
+ req_to_install = unnamed.pop(0)
+ else:
+ req_to_install = reqs.pop(0)
+ install_needed = True
+ if not self.ignore_installed and not req_to_install.editable:
+ req_to_install.check_if_exists()
+ if req_to_install.satisfied_by:
+ if self.upgrade:
+ req_to_install.conflicts_with = req_to_install.satisfied_by
+ req_to_install.satisfied_by = None
+ else:
+ install_needed = False
+ if req_to_install.satisfied_by:
+ logger.notify('Requirement already satisfied '
+ '(use --upgrade to upgrade): %s'
+ % req_to_install)
+
+ if req_to_install.editable:
+ if req_to_install.source_dir is None:
+ req_to_install.source_dir = req_to_install.build_location(self.src_dir)
+ elif install_needed:
+ req_to_install.source_dir = req_to_install.build_location(self.build_dir, not self.is_download)
+
+ if req_to_install.source_dir is not None and not os.path.isdir(req_to_install.source_dir):
+ raise InstallationError('Could not install requirement %s '
+ 'because source folder %s does not exist '
+ '(perhaps --no-download was used without first running '
+ 'an equivalent install with --no-install?)'
+ % (req_to_install, req_to_install.source_dir))
+
+ def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
+ """Prepare process. Create temp directories, download and/or unpack files."""
+ unnamed = list(self.unnamed_requirements)
+ reqs = self.requirements.values()
+ while reqs or unnamed:
+ if unnamed:
+ req_to_install = unnamed.pop(0)
+ else:
+ req_to_install = reqs.pop(0)
+ install = True
+ if not self.ignore_installed and not req_to_install.editable:
+ req_to_install.check_if_exists()
+ if req_to_install.satisfied_by:
+ if self.upgrade:
+ req_to_install.conflicts_with = req_to_install.satisfied_by
+ req_to_install.satisfied_by = None
+ else:
+ install = False
+ if req_to_install.satisfied_by:
+ logger.notify('Requirement already satisfied '
+ '(use --upgrade to upgrade): %s'
+ % req_to_install)
+ if req_to_install.editable:
+ logger.notify('Obtaining %s' % req_to_install)
+ elif install:
+ if req_to_install.url and req_to_install.url.lower().startswith('file:'):
+ logger.notify('Unpacking %s' % display_path(url_to_path(req_to_install.url)))
+ else:
+ logger.notify('Downloading/unpacking %s' % req_to_install)
+ logger.indent += 2
+ try:
+ is_bundle = False
+ if req_to_install.editable:
+ if req_to_install.source_dir is None:
+ location = req_to_install.build_location(self.src_dir)
+ req_to_install.source_dir = location
+ else:
+ location = req_to_install.source_dir
+ if not os.path.exists(self.build_dir):
+ os.makedirs(self.build_dir)
+ req_to_install.update_editable(not self.is_download)
+ if self.is_download:
+ req_to_install.run_egg_info()
+ req_to_install.archive(self.download_dir)
+ else:
+ req_to_install.run_egg_info()
+ elif install:
+ ##@@ if filesystem packages are not marked
+ ##editable in a req, a non deterministic error
+ ##occurs when the script attempts to unpack the
+ ##build directory
+
+ location = req_to_install.build_location(self.build_dir, not self.is_download)
+ ## FIXME: is the existance of the checkout good enough to use it? I don't think so.
+ unpack = True
+ if not os.path.exists(os.path.join(location, 'setup.py')):
+ ## FIXME: this won't upgrade when there's an existing package unpacked in `location`
+ if req_to_install.url is None:
+ url = finder.find_requirement(req_to_install, upgrade=self.upgrade)
+ else:
+ ## FIXME: should req_to_install.url already be a link?
+ url = Link(req_to_install.url)
+ assert url
+ if url:
+ try:
+ self.unpack_url(url, location, self.is_download)
+ except urllib2.HTTPError, e:
+ logger.fatal('Could not install requirement %s because of error %s'
+ % (req_to_install, e))
+ raise InstallationError(
+ 'Could not install requirement %s because of HTTP error %s for URL %s'
+ % (req_to_install, e, url))
+ else:
+ unpack = False
+ if unpack:
+ is_bundle = req_to_install.is_bundle
+ url = None
+ if is_bundle:
+ req_to_install.move_bundle_files(self.build_dir, self.src_dir)
+ for subreq in req_to_install.bundle_requirements():
+ reqs.append(subreq)
+ self.add_requirement(subreq)
+ elif self.is_download:
+ req_to_install.source_dir = location
+ if url and url.scheme in vcs.all_schemes:
+ req_to_install.run_egg_info()
+ req_to_install.archive(self.download_dir)
+ else:
+ req_to_install.source_dir = location
+ req_to_install.run_egg_info()
+ if force_root_egg_info:
+ # We need to run this to make sure that the .egg-info/
+ # directory is created for packing in the bundle
+ req_to_install.run_egg_info(force_root_egg_info=True)
+ req_to_install.assert_source_matches_version()
+ f = open(req_to_install.delete_marker_filename, 'w')
+ f.write(DELETE_MARKER_MESSAGE)
+ f.close()
+ #@@ sketchy way of identifying packages not grabbed from an index
+ if bundle and req_to_install.url:
+ self.copy_to_builddir(req_to_install)
+ if not is_bundle and not self.is_download:
+ ## FIXME: shouldn't be globally added:
+ finder.add_dependency_links(req_to_install.dependency_links)
+ ## FIXME: add extras in here:
+ if not self.ignore_dependencies:
+ for req in req_to_install.requirements():
+ try:
+ name = pkg_resources.Requirement.parse(req).project_name
+ except ValueError, e:
+ ## FIXME: proper warning
+ logger.error('Invalid requirement: %r (%s) in requirement %s' % (req, e, req_to_install))
+ continue
+ if self.has_requirement(name):
+ ## FIXME: check for conflict
+ continue
+ subreq = InstallRequirement(req, req_to_install)
+ reqs.append(subreq)
+ self.add_requirement(subreq)
+ if req_to_install.name not in self.requirements:
+ self.requirements[req_to_install.name] = req_to_install
+ else:
+ self.reqs_to_cleanup.append(req_to_install)
+ if install:
+ self.successfully_downloaded.append(req_to_install)
+ if bundle and (req_to_install.url and req_to_install.url.startswith('file:///')):
+ self.copy_to_builddir(req_to_install)
+ finally:
+ logger.indent -= 2
+
+ def cleanup_files(self, bundle=False):
+ """Clean up files, remove builds."""
+ logger.notify('Cleaning up...')
+ logger.indent += 2
+ for req in self.reqs_to_cleanup:
+ req.remove_temporary_source()
+
+ # The build dir can always be removed.
+ remove_dir = [self.build_dir]
+
+ # The source dir of a bundle can always be removed.
+ if bundle:
+ remove_dir.append(self.src_dir)
+
+ for dir in remove_dir:
+ if os.path.exists(dir):
+ logger.info('Removing temporary dir %s...' % dir)
+ ## FIXME: should this use pip.util.rmtree?
+ shutil.rmtree(dir)
+
+ logger.indent -= 2
+
+ def copy_to_builddir(self, req_to_install):
+ target_dir = req_to_install.editable and self.src_dir or self.build_dir
+ logger.info("Copying %s to %s" %(req_to_install.name, target_dir))
+ dest = os.path.join(target_dir, req_to_install.name)
+ shutil.copytree(req_to_install.source_dir, dest)
+ shutil.copymode(req_to_install.source_dir, dest)
+ call_subprocess(["python", "%s/setup.py"%dest, "clean"])
+
+ def unpack_url(self, link, location, only_download=False):
+ if only_download:
+ location = self.download_dir
+ for backend in vcs.backends:
+ if link.scheme in backend.schemes:
+ vcs_backend = backend(link.url)
+ if only_download:
+ vcs_backend.export(location)
+ else:
+ vcs_backend.unpack(location)
+ return
+ if link.url.lower().startswith('file:'):
+ source = url_to_path(link.url)
+ content_type = mimetypes.guess_type(source)[0]
+ if os.path.isdir(source):
+ # delete the location since shutil will create it again :(
+ if os.path.isdir(location):
+ shutil.rmtree(location)
+ shutil.copytree(source, location)
+ else:
+ self.unpack_file(source, location, content_type, link)
+ return
+ temp_dir = tempfile.mkdtemp('-unpack', 'pip-')
+ md5_hash = link.md5_hash
+ target_url = link.url.split('#', 1)[0]
+ target_file = None
+ if self.download_cache:
+ self.download_cache = os.path.expanduser(self.download_cache)
+ if not os.path.isdir(self.download_cache):
+ logger.indent -= 2
+ logger.notify('Creating supposed download cache at %s' % self.download_cache)
+ logger.indent += 2
+ os.makedirs(self.download_cache)
+ target_file = os.path.join(self.download_cache,
+ urllib.quote(target_url, ''))
+ if (target_file and os.path.exists(target_file)
+ and os.path.exists(target_file+'.content-type')):
+ fp = open(target_file+'.content-type')
+ content_type = fp.read().strip()
+ fp.close()
+ if md5_hash:
+ download_hash = md5()
+ fp = open(target_file, 'rb')
+ while 1:
+ chunk = fp.read(4096)
+ if not chunk:
+ break
+ download_hash.update(chunk)
+ fp.close()
+ temp_location = target_file
+ logger.notify('Using download cache from %s' % target_file)
+ else:
+ try:
+ resp = urllib2.urlopen(target_url)
+ except urllib2.HTTPError, e:
+ logger.fatal("HTTP error %s while getting %s" % (e.code, link))
+ raise
+ except IOError, e:
+ # Typically an FTP error
+ logger.fatal("Error %s while getting %s" % (e, link))
+ raise
+ content_type = resp.info()['content-type']
+ filename = link.filename
+ ext = splitext(filename)[1]
+ if not ext:
+ ext = mimetypes.guess_extension(content_type)
+ if ext:
+ filename += ext
+ if not ext and link.url != resp.geturl():
+ ext = os.path.splitext(resp.geturl())[1]
+ if ext:
+ filename += ext
+ temp_location = os.path.join(temp_dir, filename)
+ fp = open(temp_location, 'wb')
+ if md5_hash:
+ download_hash = md5()
+ try:
+ total_length = int(resp.info()['content-length'])
+ except (ValueError, KeyError):
+ total_length = 0
+ downloaded = 0
+ show_progress = total_length > 40*1000 or not total_length
+ show_url = link.show_url
+ try:
+ if show_progress:
+ ## FIXME: the URL can get really long in this message:
+ if total_length:
+ logger.start_progress('Downloading %s (%s): ' % (show_url, format_size(total_length)))
+ else:
+ logger.start_progress('Downloading %s (unknown size): ' % show_url)
+ else:
+ logger.notify('Downloading %s' % show_url)
+ logger.debug('Downloading from URL %s' % link)
+ while 1:
+ chunk = resp.read(4096)
+ if not chunk:
+ break
+ downloaded += len(chunk)
+ if show_progress:
+ if not total_length:
+ logger.show_progress('%s' % format_size(downloaded))
+ else:
+ logger.show_progress('%3i%% %s' % (100*downloaded/total_length, format_size(downloaded)))
+ if md5_hash:
+ download_hash.update(chunk)
+ fp.write(chunk)
+ fp.close()
+ finally:
+ if show_progress:
+ logger.end_progress('%s downloaded' % format_size(downloaded))
+ if md5_hash:
+ download_hash = download_hash.hexdigest()
+ if download_hash != md5_hash:
+ logger.fatal("MD5 hash of the package %s (%s) doesn't match the expected hash %s!"
+ % (link, download_hash, md5_hash))
+ raise InstallationError('Bad MD5 hash for package %s' % link)
+ if only_download:
+ self.copy_file(temp_location, location, content_type, link)
+ else:
+ self.unpack_file(temp_location, location, content_type, link)
+ if target_file and target_file != temp_location:
+ logger.notify('Storing download in cache at %s' % display_path(target_file))
+ shutil.copyfile(temp_location, target_file)
+ fp = open(target_file+'.content-type', 'w')
+ fp.write(content_type)
+ fp.close()
+ os.unlink(temp_location)
+ if target_file is None:
+ os.unlink(temp_location)
+ os.rmdir(temp_dir)
+
+ def copy_file(self, filename, location, content_type, link):
+ copy = True
+ download_location = os.path.join(location, link.filename)
+ if os.path.exists(download_location):
+ response = ask('The file %s exists. (i)gnore, (w)ipe, (b)ackup '
+ % display_path(download_location), ('i', 'w', 'b'))
+ if response == 'i':
+ copy = False
+ elif response == 'w':
+ logger.warn('Deleting %s' % display_path(download_location))
+ os.remove(download_location)
+ elif response == 'b':
+ dest_file = backup_dir(download_location)
+ logger.warn('Backing up %s to %s'
+ % (display_path(download_location), display_path(dest_file)))
+ shutil.move(download_location, dest_file)
+ if copy:
+ shutil.copy(filename, download_location)
+ logger.indent -= 2
+ logger.notify('Saved %s' % display_path(download_location))
+
+ def unpack_file(self, filename, location, content_type, link):
+ if (content_type == 'application/zip'
+ or filename.endswith('.zip')
+ or filename.endswith('.pybundle')
+ or zipfile.is_zipfile(filename)):
+ self.unzip_file(filename, location, flatten=not filename.endswith('.pybundle'))
+ elif (content_type == 'application/x-gzip'
+ or tarfile.is_tarfile(filename)
+ or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')):
+ self.untar_file(filename, location)
+ elif (content_type and content_type.startswith('text/html')
+ and is_svn_page(file_contents(filename))):
+ # We don't really care about this
+ from pip.vcs.subversion import Subversion
+ Subversion('svn+' + link.url).unpack(location)
+ else:
+ ## FIXME: handle?
+ ## FIXME: magic signatures?
+ logger.fatal('Cannot unpack file %s (downloaded from %s, content-type: %s); cannot detect archive format'
+ % (filename, location, content_type))
+ raise InstallationError('Cannot determine archive format of %s' % location)
+
+ def unzip_file(self, filename, location, flatten=True):
+ """Unzip the file (zip file located at filename) to the destination
+ location"""
+ if not os.path.exists(location):
+ os.makedirs(location)
+ zipfp = open(filename, 'rb')
+ try:
+ zip = zipfile.ZipFile(zipfp)
+ leading = has_leading_dir(zip.namelist()) and flatten
+ for name in zip.namelist():
+ data = zip.read(name)
+ fn = name
+ if leading:
+ fn = split_leading_dir(name)[1]
+ fn = os.path.join(location, fn)
+ dir = os.path.dirname(fn)
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ if fn.endswith('/') or fn.endswith('\\'):
+ # A directory
+ if not os.path.exists(fn):
+ os.makedirs(fn)
+ else:
+ fp = open(fn, 'wb')
+ try:
+ fp.write(data)
+ finally:
+ fp.close()
+ finally:
+ zipfp.close()
+
+ def untar_file(self, filename, location):
+ """Untar the file (tar file located at filename) to the destination location"""
+ if not os.path.exists(location):
+ os.makedirs(location)
+ if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'):
+ mode = 'r:gz'
+ elif filename.lower().endswith('.bz2') or filename.lower().endswith('.tbz'):
+ mode = 'r:bz2'
+ elif filename.lower().endswith('.tar'):
+ mode = 'r'
+ else:
+ logger.warn('Cannot determine compression type for file %s' % filename)
+ mode = 'r:*'
+ tar = tarfile.open(filename, mode)
+ try:
+ leading = has_leading_dir([member.name for member in tar.getmembers()])
+ for member in tar.getmembers():
+ fn = member.name
+ if leading:
+ fn = split_leading_dir(fn)[1]
+ path = os.path.join(location, fn)
+ if member.isdir():
+ if not os.path.exists(path):
+ os.makedirs(path)
+ else:
+ try:
+ fp = tar.extractfile(member)
+ except (KeyError, AttributeError), e:
+ # Some corrupt tar files seem to produce this
+ # (specifically bad symlinks)
+ logger.warn(
+ 'In the tar file %s the member %s is invalid: %s'
+ % (filename, member.name, e))
+ continue
+ if not os.path.exists(os.path.dirname(path)):
+ os.makedirs(os.path.dirname(path))
+ destfp = open(path, 'wb')
+ try:
+ shutil.copyfileobj(fp, destfp)
+ finally:
+ destfp.close()
+ fp.close()
+ finally:
+ tar.close()
+
+ def install(self, install_options):
+ """Install everything in this set (after having downloaded and unpacked the packages)"""
+ to_install = sorted([r for r in self.requirements.values()
+ if self.upgrade or not r.satisfied_by],
+ key=lambda p: p.name.lower())
+ if to_install:
+ logger.notify('Installing collected packages: %s' % (', '.join([req.name for req in to_install])))
+ logger.indent += 2
+ try:
+ for requirement in to_install:
+ if requirement.conflicts_with:
+ logger.notify('Found existing installation: %s'
+ % requirement.conflicts_with)
+ logger.indent += 2
+ try:
+ requirement.uninstall(auto_confirm=True)
+ finally:
+ logger.indent -= 2
+ try:
+ requirement.install(install_options)
+ except:
+ # if install did not succeed, rollback previous uninstall
+ if requirement.conflicts_with and not requirement.install_succeeded:
+ requirement.rollback_uninstall()
+ raise
+ else:
+ if requirement.conflicts_with and requirement.install_succeeded:
+ requirement.commit_uninstall()
+ requirement.remove_temporary_source()
+ finally:
+ logger.indent -= 2
+ self.successfully_installed = to_install
+
+ def create_bundle(self, bundle_filename):
+ ## FIXME: can't decide which is better; zip is easier to read
+ ## random files from, but tar.bz2 is smaller and not as lame a
+ ## format.
+
+ ## FIXME: this file should really include a manifest of the
+ ## packages, maybe some other metadata files. It would make
+ ## it easier to detect as well.
+ zip = zipfile.ZipFile(bundle_filename, 'w', zipfile.ZIP_DEFLATED)
+ vcs_dirs = []
+ for dir, basename in (self.build_dir, 'build'), (self.src_dir, 'src'):
+ dir = os.path.normcase(os.path.abspath(dir))
+ for dirpath, dirnames, filenames in os.walk(dir):
+ for backend in vcs.backends:
+ vcs_backend = backend()
+ vcs_url = vcs_rev = None
+ if vcs_backend.dirname in dirnames:
+ for vcs_dir in vcs_dirs:
+ if dirpath.startswith(vcs_dir):
+ # vcs bundle file already in parent directory
+ break
+ else:
+ vcs_url, vcs_rev = vcs_backend.get_info(
+ os.path.join(dir, dirpath))
+ vcs_dirs.append(dirpath)
+ vcs_bundle_file = vcs_backend.bundle_file
+ vcs_guide = vcs_backend.guide % {'url': vcs_url,
+ 'rev': vcs_rev}
+ dirnames.remove(vcs_backend.dirname)
+ break
+ if 'pip-egg-info' in dirnames:
+ dirnames.remove('pip-egg-info')
+ for dirname in dirnames:
+ dirname = os.path.join(dirpath, dirname)
+ name = self._clean_zip_name(dirname, dir)
+ zip.writestr(basename + '/' + name + '/', '')
+ for filename in filenames:
+ if filename == 'pip-delete-this-directory.txt':
+ continue
+ filename = os.path.join(dirpath, filename)
+ name = self._clean_zip_name(filename, dir)
+ zip.write(filename, basename + '/' + name)
+ if vcs_url:
+ name = os.path.join(dirpath, vcs_bundle_file)
+ name = self._clean_zip_name(name, dir)
+ zip.writestr(basename + '/' + name, vcs_guide)
+
+ zip.writestr('pip-manifest.txt', self.bundle_requirements())
+ zip.close()
+
+ BUNDLE_HEADER = '''\
+# This is a pip bundle file, that contains many source packages
+# that can be installed as a group. You can install this like:
+# pip this_file.zip
+# The rest of the file contains a list of all the packages included:
+'''
+
+ def bundle_requirements(self):
+ parts = [self.BUNDLE_HEADER]
+ for req in sorted(
+ [req for req in self.requirements.values()
+ if not req.comes_from],
+ key=lambda x: x.name):
+ parts.append('%s==%s\n' % (req.name, req.installed_version))
+ parts.append('# These packages were installed to satisfy the above requirements:\n')
+ for req in sorted(
+ [req for req in self.requirements.values()
+ if req.comes_from],
+ key=lambda x: x.name):
+ parts.append('%s==%s\n' % (req.name, req.installed_version))
+ ## FIXME: should we do something with self.unnamed_requirements?
+ return ''.join(parts)
+
+ def _clean_zip_name(self, name, prefix):
+ assert name.startswith(prefix+'/'), (
+ "name %r doesn't start with prefix %r" % (name, prefix))
+ name = name[len(prefix)+1:]
+ name = name.replace(os.path.sep, '/')
+ return name
+
+_scheme_re = re.compile(r'^(http|https|file):', re.I)
+
+def parse_requirements(filename, finder=None, comes_from=None, options=None):
+ skip_match = None
+ skip_regex = options.skip_requirements_regex
+ if skip_regex:
+ skip_match = re.compile(skip_regex)
+ filename, content = get_file_content(filename, comes_from=comes_from)
+ for line_number, line in enumerate(content.splitlines()):
+ line_number += 1
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ if skip_match and skip_match.search(line):
+ continue
+ if line.startswith('-r') or line.startswith('--requirement'):
+ if line.startswith('-r'):
+ req_url = line[2:].strip()
+ else:
+ req_url = line[len('--requirement'):].strip().strip('=')
+ if _scheme_re.search(filename):
+ # Relative to a URL
+ req_url = urlparse.urljoin(req_url, filename)
+ elif not _scheme_re.search(req_url):
+ req_url = os.path.join(os.path.dirname(filename), req_url)
+ for item in parse_requirements(req_url, finder, comes_from=filename, options=options):
+ yield item
+ elif line.startswith('-Z') or line.startswith('--always-unzip'):
+ # No longer used, but previously these were used in
+ # requirement files, so we'll ignore.
+ pass
+ elif line.startswith('-f') or line.startswith('--find-links'):
+ if line.startswith('-f'):
+ line = line[2:].strip()
+ else:
+ line = line[len('--find-links'):].strip().lstrip('=')
+ ## FIXME: it would be nice to keep track of the source of
+ ## the find_links:
+ if finder: finder.find_links.append(line)
+ elif line.startswith('-i') or line.startswith('--index-url'):
+ if line.startswith('-i'):
+ line = line[2:].strip()
+ else:
+ line = line[len('--index-url'):].strip().lstrip('=')
+ if finder: finder.index_urls = [line]
+ elif line.startswith('--extra-index-url'):
+ line = line[len('--extra-index-url'):].strip().lstrip('=')
+ if finder: finder.index_urls.append(line)
+ else:
+ comes_from = '-r %s (line %s)' % (filename, line_number)
+ if line.startswith('-e') or line.startswith('--editable'):
+ if line.startswith('-e'):
+ line = line[2:].strip()
+ else:
+ line = line[len('--editable'):].strip()
+ req = InstallRequirement.from_editable(
+ line, comes_from=comes_from, default_vcs=options.default_vcs)
+ else:
+ req = InstallRequirement.from_line(line, comes_from)
+ yield req
+
+def parse_editable(editable_req, default_vcs=None):
+ """Parses svn+http://blahblah@rev#egg=Foobar into a requirement
+ (Foobar) and a URL"""
+ url = editable_req
+ if os.path.isdir(url) and os.path.exists(os.path.join(url, 'setup.py')):
+ # Treating it as code that has already been checked out
+ url = path_to_url(url)
+ if url.lower().startswith('file:'):
+ return None, url
+ for version_control in vcs:
+ if url.lower().startswith('%s:' % version_control):
+ url = '%s+%s' % (version_control, url)
+ if '+' not in url:
+ if default_vcs:
+ url = default_vcs + '+' + url
+ else:
+ raise InstallationError(
+ '--editable=%s should be formatted with svn+URL, git+URL, hg+URL or bzr+URL' % editable_req)
+ vc_type = url.split('+', 1)[0].lower()
+ if not vcs.get_backend(vc_type):
+ raise InstallationError(
+ 'For --editable=%s only svn (svn+URL), Git (git+URL), Mercurial (hg+URL) and Bazaar (bzr+URL) is currently supported' % editable_req)
+ match = re.search(r'(?:#|#.*?&)egg=([^&]*)', editable_req)
+ if (not match or not match.group(1)) and vcs.get_backend(vc_type):
+ parts = [p for p in editable_req.split('#', 1)[0].split('/') if p]
+ if parts[-2] in ('tags', 'branches', 'tag', 'branch'):
+ req = parts[-3]
+ elif parts[-1] == 'trunk':
+ req = parts[-2]
+ else:
+ raise InstallationError(
+ '--editable=%s is not the right format; it must have #egg=Package'
+ % editable_req)
+ else:
+ req = match.group(1)
+ ## FIXME: use package_to_requirement?
+ match = re.search(r'^(.*?)(?:-dev|-\d.*)', req)
+ if match:
+ # Strip off -dev, -0.2, etc.
+ req = match.group(1)
+ return req, url
+
+class UninstallPathSet(object):
+ """A set of file paths to be removed in the uninstallation of a
+ requirement."""
+ def __init__(self, dist):
+ self.paths = set()
+ self._refuse = set()
+ self.pth = {}
+ self.dist = dist
+ self.save_dir = None
+ self._moved_paths = []
+
+ def _permitted(self, path):
+ """
+ Return True if the given path is one we are permitted to
+ remove/modify, False otherwise.
+
+ """
+ return is_local(path)
+
+ def _can_uninstall(self):
+ if not dist_is_local(self.dist):
+ logger.notify("Not uninstalling %s at %s, outside environment %s"
+ % (self.dist.project_name, normalize_path(self.dist.location), sys.prefix))
+ return False
+ return True
+
+ def add(self, path):
+ path = normalize_path(path)
+ if not os.path.exists(path):
+ return
+ if self._permitted(path):
+ self.paths.add(path)
+ else:
+ self._refuse.add(path)
+
+ def add_pth(self, pth_file, entry):
+ pth_file = normalize_path(pth_file)
+ if self._permitted(pth_file):
+ entry = os.path.normcase(entry)
+ if pth_file not in self.pth:
+ self.pth[pth_file] = UninstallPthEntries(pth_file)
+ self.pth[pth_file].add(entry)
+ else:
+ self._refuse.add(pth_file)
+
+ def compact(self, paths):
+ """Compact a path set to contain the minimal number of paths
+ necessary to contain all paths in the set. If /a/path/ and
+ /a/path/to/a/file.txt are both in the set, leave only the
+ shorter path."""
+ short_paths = set()
+ for path in sorted(paths, key=len):
+ if not any([(path.startswith(shortpath) and
+ path[len(shortpath.rstrip(os.path.sep))] == os.path.sep)
+ for shortpath in short_paths]):
+ short_paths.add(path)
+ return short_paths
+
+ def remove(self, auto_confirm=False):
+ """Remove paths in ``self.paths`` with confirmation (unless
+ ``auto_confirm`` is True)."""
+ if not self._can_uninstall():
+ return
+ logger.notify('Uninstalling %s:' % self.dist.project_name)
+ logger.indent += 2
+ paths = sorted(self.compact(self.paths))
+ try:
+ if auto_confirm:
+ response = 'y'
+ else:
+ for path in paths:
+ logger.notify(path)
+ response = ask('Proceed (y/n)? ', ('y', 'n'))
+ if self._refuse:
+ logger.notify('Not removing or modifying (outside of prefix):')
+ for path in self.compact(self._refuse):
+ logger.notify(path)
+ if response == 'y':
+ self.save_dir = tempfile.mkdtemp(suffix='-uninstall',
+ prefix='pip-')
+ for path in paths:
+ new_path = os.path.splitdrive(path)[1].lstrip(os.path.sep)
+ new_path = os.path.join(self.save_dir, new_path)
+ logger.info('Removing file or directory %s' % path)
+ self._moved_paths.append(path)
+ renames(path, new_path)
+ for pth in self.pth.values():
+ pth.remove()
+ logger.notify('Successfully uninstalled %s' % self.dist.project_name)
+
+ finally:
+ logger.indent -= 2
+
+ def rollback(self):
+ """Rollback the changes previously made by remove()."""
+ if self.save_dir is None:
+ logger.error("Can't roll back %s; was not uninstalled" % self.dist.project_name)
+ return False
+ logger.notify('Rolling back uninstall of %s' % self.dist.project_name)
+ for path in self._moved_paths:
+ tmp_path = os.path.join(self.save_dir, path.lstrip(os.path.sep))
+ logger.info('Replacing %s' % path)
+ renames(tmp_path, path)
+ for pth in self.pth:
+ pth.rollback()
+
+ def commit(self):
+ """Remove temporary save dir: rollback will no longer be possible."""
+ if self.save_dir is not None:
+ shutil.rmtree(self.save_dir)
+ self.save_dir = None
+ self._moved_paths = []
+
+
+class UninstallPthEntries(object):
+ def __init__(self, pth_file):
+ if not os.path.isfile(pth_file):
+ raise UninstallationError("Cannot remove entries from nonexistent file %s" % pth_file)
+ self.file = pth_file
+ self.entries = set()
+ self._saved_lines = None
+
+ def add(self, entry):
+ self.entries.add(entry)
+
+ def remove(self):
+ logger.info('Removing pth entries from %s:' % self.file)
+ fh = open(self.file, 'r')
+ lines = fh.readlines()
+ self._saved_lines = lines
+ fh.close()
+ try:
+ for entry in self.entries:
+ logger.info('Removing entry: %s' % entry)
+ try:
+ lines.remove(entry + '\n')
+ except ValueError:
+ pass
+ finally:
+ pass
+ fh = open(self.file, 'w')
+ fh.writelines(lines)
+ fh.close()
+
+ def rollback(self):
+ if self._saved_lines is None:
+ logger.error('Cannot roll back changes to %s, none were made' % self.file)
+ return False
+ logger.info('Rolling %s back to previous state' % self.file)
+ fh = open(self.file, 'w')
+ fh.writelines(self._saved_lines)
+ fh.close()
+ return True
+
+class FakeFile(object):
+ """Wrap a list of lines in an object with readline() to make
+ ConfigParser happy."""
+ def __init__(self, lines):
+ self._gen = (l for l in lines)
+
+ def readline(self):
+ try:
+ return self._gen.next()
+ except StopIteration:
+ return ''
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,16 @@
+import sys
+import os
+
+def run():
+ base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ ## FIXME: this is kind of crude; if we could create a fake pip
+ ## module, then exec into it and update pip.__path__ properly, we
+ ## wouldn't have to update sys.path:
+ sys.path.insert(0, base)
+ import pip
+ return pip.main()
+
+if __name__ == '__main__':
+ exit = run()
+ if exit:
+ sys.exit(exit)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,419 @@
+import sys
+import shutil
+import os
+import posixpath
+import stat
+import urllib
+import urllib2
+import re
+
+import pkg_resources
+
+from pip.backwardcompat import WindowsError
+from pip.exceptions import InstallationError
+from pip.locations import site_packages
+
+__all__ = ['rmtree', 'display_path', 'backup_dir',
+ 'find_command', 'splitext', 'ask', 'Inf',
+ 'url_to_path', 'path_to_url',
+ 'path_to_url2', 'normalize_name',
+ 'format_size', 'is_url', 'is_installable_dir', 'is_archive_file',
+ 'strip_prefix', 'is_svn_page', 'file_contents',
+ 'split_leading_dir', 'has_leading_dir',
+ 'make_path_relative', 'normalize_path',
+ 'get_file_content', 'renames', 'get_terminal_size']
+
+def rmtree(dir):
+ shutil.rmtree(dir, ignore_errors=True,
+ onerror=rmtree_errorhandler)
+
+def rmtree_errorhandler(func, path, exc_info):
+ """On Windows, the files in .svn are read-only, so when rmtree() tries to
+ remove them, an exception is thrown. We catch that here, remove the
+ read-only attribute, and hopefully continue without problems."""
+ exctype, value = exc_info[:2]
+ # lookin for a windows error
+ if exctype is not WindowsError or 'Access is denied' not in str(value):
+ raise
+ # file type should currently be read only
+ if ((os.stat(path).st_mode & stat.S_IREAD) != stat.S_IREAD):
+ raise
+ # convert to read/write
+ os.chmod(path, stat.S_IWRITE)
+ # use the original function to repeat the operation
+ func(path)
+
+def display_path(path):
+ """Gives the display value for a given path, making it relative to cwd
+ if possible."""
+ path = os.path.normcase(os.path.abspath(path))
+ if path.startswith(os.getcwd() + os.path.sep):
+ path = '.' + path[len(os.getcwd()):]
+ return path
+
+def backup_dir(dir, ext='.bak'):
+ """Figure out the name of a directory to back up the given dir to
+ (adding .bak, .bak2, etc)"""
+ n = 1
+ extension = ext
+ while os.path.exists(dir + extension):
+ n += 1
+ extension = ext + str(n)
+ return dir + extension
+
+def splitext(path):
+ """Like os.path.splitext, but take off .tar too"""
+ base, ext = posixpath.splitext(path)
+ if base.lower().endswith('.tar'):
+ ext = base[-4:] + ext
+ base = base[:-4]
+ return base, ext
+
+def find_command(cmd, paths=None, pathext=None):
+ """Searches the PATH for the given command and returns its path"""
+ if paths is None:
+ paths = os.environ.get('PATH', []).split(os.pathsep)
+ if isinstance(paths, basestring):
+ paths = [paths]
+ # check if there are funny path extensions for executables, e.g. Windows
+ if pathext is None:
+ pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
+ pathext = [ext for ext in pathext.lower().split(os.pathsep)]
+ # don't use extensions if the command ends with one of them
+ if os.path.splitext(cmd)[1].lower() in pathext:
+ pathext = ['']
+ # check if we find the command on PATH
+ for path in paths:
+ # try without extension first
+ cmd_path = os.path.join(path, cmd)
+ for ext in pathext:
+ # then including the extension
+ cmd_path_ext = cmd_path + ext
+ if os.path.exists(cmd_path_ext):
+ return cmd_path_ext
+ if os.path.exists(cmd_path):
+ return cmd_path
+ return None
+
+def ask(message, options):
+ """Ask the message interactively, with the given possible responses"""
+ while 1:
+ if os.environ.get('PIP_NO_INPUT'):
+ raise Exception('No input was expected ($PIP_NO_INPUT set); question: %s' % message)
+ response = raw_input(message)
+ response = response.strip().lower()
+ if response not in options:
+ print 'Your response (%r) was not one of the expected responses: %s' % (
+ response, ', '.join(options))
+ else:
+ return response
+
+class _Inf(object):
+ """I am bigger than everything!"""
+ def __cmp__(self, a):
+ if self is a:
+ return 0
+ return 1
+ def __repr__(self):
+ return 'Inf'
+Inf = _Inf()
+del _Inf
+
+
+def url_to_path(url):
+ """
+ Convert a file: URL to a path.
+ """
+ assert url.startswith('file:'), (
+ "You can only turn file: urls into filenames (not %r)" % url)
+ path = url[len('file:'):].lstrip('/')
+ path = urllib.unquote(path)
+ if _url_drive_re.match(path):
+ path = path[0] + ':' + path[2:]
+ else:
+ path = '/' + path
+ return path
+
+_drive_re = re.compile('^([a-z]):', re.I)
+_url_drive_re = re.compile('^([a-z])[:|]', re.I)
+
+def path_to_url(path):
+ """
+ Convert a path to a file: URL. The path will be made absolute.
+ """
+ path = os.path.normcase(os.path.abspath(path))
+ if _drive_re.match(path):
+ path = path[0] + '|' + path[2:]
+ url = urllib.quote(path)
+ url = url.replace(os.path.sep, '/')
+ url = url.lstrip('/')
+ return 'file:///' + url
+
+def path_to_url2(path):
+ """
+ Convert a path to a file: URL. The path will be made absolute and have
+ quoted path parts.
+ """
+ path = os.path.normcase(os.path.abspath(path))
+ drive, path = os.path.splitdrive(path)
+ filepath = path.split(os.path.sep)
+ url = '/'.join([urllib.quote(part) for part in filepath])
+ if not drive:
+ url = url.lstrip('/')
+ return 'file:///' + drive + url
+
+_normalize_re = re.compile(r'[^a-z]', re.I)
+
+def normalize_name(name):
+ return _normalize_re.sub('-', name.lower())
+
+def format_size(bytes):
+ if bytes > 1000*1000:
+ return '%.1fMb' % (bytes/1000.0/1000)
+ elif bytes > 10*1000:
+ return '%iKb' % (bytes/1000)
+ elif bytes > 1000:
+ return '%.1fKb' % (bytes/1000.0)
+ else:
+ return '%ibytes' % bytes
+
+def is_url(name):
+ """Returns true if the name looks like a URL"""
+ from pip.vcs import vcs
+ if ':' not in name:
+ return False
+ scheme = name.split(':', 1)[0].lower()
+ return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes
+
+def is_installable_dir(path):
+ """Return True if `path` is a directory containing a setup.py file."""
+ if not os.path.isdir(path):
+ return False
+ setup_py = os.path.join(path, 'setup.py')
+ if os.path.isfile(setup_py):
+ return True
+ return False
+
+def is_archive_file(name):
+ """Return True if `name` is a considered as an archive file."""
+ archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar', '.pybundle')
+ ext = splitext(name)[1].lower()
+ if ext in archives:
+ return True
+ return False
+
+def is_svn_page(html):
+ """Returns true if the page appears to be the index page of an svn repository"""
+ return (re.search(r'<title>[^<]*Revision \d+:', html)
+ and re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I))
+
+def file_contents(filename):
+ fp = open(filename, 'rb')
+ try:
+ return fp.read()
+ finally:
+ fp.close()
+
+def split_leading_dir(path):
+ path = str(path)
+ path = path.lstrip('/').lstrip('\\')
+ if '/' in path and (('\\' in path and path.find('/') < path.find('\\'))
+ or '\\' not in path):
+ return path.split('/', 1)
+ elif '\\' in path:
+ return path.split('\\', 1)
+ else:
+ return path, ''
+
+def has_leading_dir(paths):
+ """Returns true if all the paths have the same leading path name
+ (i.e., everything is in one subdirectory in an archive)"""
+ common_prefix = None
+ for path in paths:
+ prefix, rest = split_leading_dir(path)
+ if not prefix:
+ return False
+ elif common_prefix is None:
+ common_prefix = prefix
+ elif prefix != common_prefix:
+ return False
+ return True
+
+def make_path_relative(path, rel_to):
+ """
+ Make a filename relative, where the filename path, and it is
+ relative to rel_to
+
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/usr/share/another-place/src/Directory')
+ '../../../something/a-file.pth'
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/home/user/src/Directory')
+ '../../../usr/share/something/a-file.pth'
+ >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
+ 'a-file.pth'
+ """
+ path_filename = os.path.basename(path)
+ path = os.path.dirname(path)
+ path = os.path.normpath(os.path.abspath(path))
+ rel_to = os.path.normpath(os.path.abspath(rel_to))
+ path_parts = path.strip(os.path.sep).split(os.path.sep)
+ rel_to_parts = rel_to.strip(os.path.sep).split(os.path.sep)
+ while path_parts and rel_to_parts and path_parts[0] == rel_to_parts[0]:
+ path_parts.pop(0)
+ rel_to_parts.pop(0)
+ full_parts = ['..']*len(rel_to_parts) + path_parts + [path_filename]
+ if full_parts == ['']:
+ return '.' + os.path.sep
+ return os.path.sep.join(full_parts)
+
+def normalize_path(path):
+ """
+ Convert a path to its canonical, case-normalized, absolute version.
+
+ """
+ return os.path.normcase(os.path.realpath(path))
+
+_scheme_re = re.compile(r'^(http|https|file):', re.I)
+_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I)
+
+def get_file_content(url, comes_from=None):
+ """Gets the content of a file; it may be a filename, file: URL, or
+ http: URL. Returns (location, content)"""
+ match = _scheme_re.search(url)
+ if match:
+ scheme = match.group(1).lower()
+ if (scheme == 'file' and comes_from
+ and comes_from.startswith('http')):
+ raise InstallationError(
+ 'Requirements file %s references URL %s, which is local'
+ % (comes_from, url))
+ if scheme == 'file':
+ path = url.split(':', 1)[1]
+ path = path.replace('\\', '/')
+ match = _url_slash_drive_re.match(path)
+ if match:
+ path = match.group(1) + ':' + path.split('|', 1)[1]
+ path = urllib.unquote(path)
+ if path.startswith('/'):
+ path = '/' + path.lstrip('/')
+ url = path
+ else:
+ ## FIXME: catch some errors
+ resp = urllib2.urlopen(url)
+ return resp.geturl(), resp.read()
+ f = open(url)
+ content = f.read()
+ f.close()
+ return url, content
+
+def renames(old, new):
+ """Like os.renames(), but handles renaming across devices."""
+ # Implementation borrowed from os.renames().
+ head, tail = os.path.split(new)
+ if head and tail and not os.path.exists(head):
+ os.makedirs(head)
+
+ shutil.move(old, new)
+
+ head, tail = os.path.split(old)
+ if head and tail:
+ try:
+ os.removedirs(head)
+ except OSError:
+ pass
+
+def in_venv():
+ """
+ Return True if we're running inside a virtualenv, False otherwise.
+
+ """
+ return hasattr(sys, 'real_prefix')
+
+def is_local(path):
+ """
+ Return True if path is within sys.prefix, if we're running in a virtualenv.
+
+ If we're not in a virtualenv, all paths are considered "local."
+
+ """
+ if not in_venv():
+ return True
+ return normalize_path(path).startswith(normalize_path(sys.prefix))
+
+def dist_is_local(dist):
+ """
+ Return True if given Distribution object is installed locally
+ (i.e. within current virtualenv).
+
+ Always True if we're not in a virtualenv.
+
+ """
+ return is_local(dist_location(dist))
+
+def get_installed_distributions(local_only=True, skip=('setuptools', 'pip', 'python')):
+ """
+ Return a list of installed Distribution objects.
+
+ If ``local_only`` is True (default), only return installations
+ local to the current virtualenv, if in a virtualenv.
+
+ ``skip`` argument is an iterable of lower-case project names to
+ ignore; defaults to ('setuptools', 'pip', 'python'). [FIXME also
+ skip virtualenv?]
+
+ """
+ if local_only:
+ local_test = dist_is_local
+ else:
+ local_test = lambda d: True
+ return [d for d in pkg_resources.working_set if local_test(d) and d.key not in skip]
+
+def egg_link_path(dist):
+ """
+ Return the path where we'd expect to find a .egg-link file for
+ this distribution. (There doesn't seem to be any metadata in the
+ Distribution object for a develop egg that points back to its
+ .egg-link and easy-install.pth files).
+
+ This won't find a globally-installed develop egg if we're in a
+ virtualenv.
+
+ """
+ return os.path.join(site_packages, dist.project_name) + '.egg-link'
+
+def dist_location(dist):
+ """
+ Get the site-packages location of this distribution. Generally
+ this is dist.location, except in the case of develop-installed
+ packages, where dist.location is the source code location, and we
+ want to know where the egg-link file is.
+
+ """
+ egg_link = egg_link_path(dist)
+ if os.path.exists(egg_link):
+ return egg_link
+ return dist.location
+
+def get_terminal_size():
+ """Returns a tuple (x, y) representing the width(x) and the height(x)
+ in characters of the terminal window."""
+ def ioctl_GWINSZ(fd):
+ try:
+ import fcntl, termios, struct
+ cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
+ '1234'))
+ except:
+ return None
+ return cr
+ cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
+ if not cr:
+ try:
+ fd = os.open(os.ctermid(), os.O_RDONLY)
+ cr = ioctl_GWINSZ(fd)
+ os.close(fd)
+ except:
+ pass
+ if not cr:
+ cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
+ return int(cr[1]), int(cr[0])
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,234 @@
+"""Handles all VCS (version control) support"""
+
+import os
+import shutil
+import urlparse
+import urllib
+from pip.util import display_path, backup_dir, find_command, ask
+from pip.exceptions import BadCommand
+from pip.log import logger
+
+__all__ = ['vcs', 'get_source_requirement', 'import_vcs_support']
+
+class VcsSupport(object):
+ _registry = {}
+ schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp']
+
+ def __init__(self):
+ # Register more schemes with urlparse for various version control systems
+ urlparse.uses_netloc.extend(self.schemes)
+ urlparse.uses_fragment.extend(self.schemes)
+ super(VcsSupport, self).__init__()
+
+ def __iter__(self):
+ return self._registry.__iter__()
+
+ @property
+ def backends(self):
+ return self._registry.values()
+
+ @property
+ def dirnames(self):
+ return [backend.dirname for backend in self.backends]
+
+ @property
+ def all_schemes(self):
+ schemes = []
+ for backend in self.backends:
+ schemes.extend(backend.schemes)
+ return schemes
+
+ def register(self, cls):
+ if not hasattr(cls, 'name'):
+ logger.warn('Cannot register VCS %s' % cls.__name__)
+ return
+ if cls.name not in self._registry:
+ self._registry[cls.name] = cls
+
+ def unregister(self, cls=None, name=None):
+ if name in self._registry:
+ del self._registry[name]
+ elif cls in self._registry.values():
+ del self._registry[cls.name]
+ else:
+ logger.warn('Cannot unregister because no class or name given')
+
+ def get_backend_name(self, location):
+ """
+ Return the name of the version control backend if found at given
+ location, e.g. vcs.get_backend_name('/path/to/vcs/checkout')
+ """
+ for vc_type in self._registry.values():
+ path = os.path.join(location, vc_type.dirname)
+ if os.path.exists(path):
+ return vc_type.name
+ return None
+
+ def get_backend(self, name):
+ name = name.lower()
+ if name in self._registry:
+ return self._registry[name]
+
+ def get_backend_from_location(self, location):
+ vc_type = self.get_backend_name(location)
+ if vc_type:
+ return self.get_backend(vc_type)
+ return None
+
+vcs = VcsSupport()
+
+
+
+class VersionControl(object):
+ name = ''
+ dirname = ''
+
+ def __init__(self, url=None, *args, **kwargs):
+ self.url = url
+ self._cmd = None
+ super(VersionControl, self).__init__(*args, **kwargs)
+
+ def _filter(self, line):
+ return (logger.INFO, line)
+
+ @property
+ def cmd(self):
+ if self._cmd is not None:
+ return self._cmd
+ command = find_command(self.name)
+ if command is None:
+ raise BadCommand('Cannot find command %r' % self.name)
+ logger.info('Found command %r at %r' % (self.name, command))
+ self._cmd = command
+ return command
+
+ def get_url_rev(self):
+ """
+ Returns the correct repository URL and revision by parsing the given
+ repository URL
+ """
+ url = self.url.split('+', 1)[1]
+ scheme, netloc, path, query, frag = urlparse.urlsplit(url)
+ rev = None
+ if '@' in path:
+ path, rev = path.rsplit('@', 1)
+ url = urlparse.urlunsplit((scheme, netloc, path, query, ''))
+ return url, rev
+
+ def get_info(self, location):
+ """
+ Returns (url, revision), where both are strings
+ """
+ assert not location.rstrip('/').endswith(self.dirname), 'Bad directory: %s' % location
+ return self.get_url(location), self.get_revision(location)
+
+ def normalize_url(self, url):
+ """
+ Normalize a URL for comparison by unquoting it and removing any trailing slash.
+ """
+ return urllib.unquote(url).rstrip('/')
+
+ def compare_urls(self, url1, url2):
+ """
+ Compare two repo URLs for identity, ignoring incidental differences.
+ """
+ return (self.normalize_url(url1) == self.normalize_url(url2))
+
+ def parse_vcs_bundle_file(self, content):
+ """
+ Takes the contents of the bundled text file that explains how to revert
+ the stripped off version control data of the given package and returns
+ the URL and revision of it.
+ """
+ raise NotImplementedError
+
+ def obtain(self, dest):
+ """
+ Called when installing or updating an editable package, takes the
+ source path of the checkout.
+ """
+ raise NotImplementedError
+
+ def switch(self, dest, url, rev_options):
+ """
+ Switch the repo at ``dest`` to point to ``URL``.
+ """
+ raise NotImplemented
+
+ def update(self, dest, rev_options):
+ """
+ Update an already-existing repo to the given ``rev_options``.
+ """
+ raise NotImplementedError
+
+ def check_destination(self, dest, url, rev_options, rev_display):
+ """
+ Prepare a location to receive a checkout/clone.
+
+ Return True if the location is ready for (and requires) a
+ checkout/clone, False otherwise.
+ """
+ checkout = True
+ prompt = False
+ if os.path.exists(dest):
+ checkout = False
+ if os.path.exists(os.path.join(dest, self.dirname)):
+ existing_url = self.get_url(dest)
+ if self.compare_urls(existing_url, url):
+ logger.info('%s in %s exists, and has correct URL (%s)'
+ % (self.repo_name.title(), display_path(dest), url))
+ logger.notify('Updating %s %s%s'
+ % (display_path(dest), self.repo_name, rev_display))
+ self.update(dest, rev_options)
+ else:
+ logger.warn('%s %s in %s exists with URL %s'
+ % (self.name, self.repo_name, display_path(dest), existing_url))
+ prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', ('s', 'i', 'w', 'b'))
+ else:
+ logger.warn('Directory %s already exists, and is not a %s %s.'
+ % (dest, self.name, self.repo_name))
+ prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b'))
+ if prompt:
+ logger.warn('The plan is to install the %s repository %s'
+ % (self.name, url))
+ response = ask('What to do? %s' % prompt[0], prompt[1])
+
+ if response == 's':
+ logger.notify('Switching %s %s to %s%s'
+ % (self.repo_name, display_path(dest), url, rev_display))
+ self.switch(dest, url, rev_options)
+ elif response == 'i':
+ # do nothing
+ pass
+ elif response == 'w':
+ logger.warn('Deleting %s' % display_path(dest))
+ shutil.rmtree(dest)
+ checkout = True
+ elif response == 'b':
+ dest_dir = backup_dir(dest)
+ logger.warn('Backing up %s to %s'
+ % (display_path(dest), dest_dir))
+ shutil.move(dest, dest_dir)
+ checkout = True
+ return checkout
+
+ def unpack(self, location):
+ raise NotImplementedError
+
+ def get_src_requirement(self, dist, location, find_tags=False):
+ raise NotImplementedError
+
+def get_src_requirement(dist, location, find_tags):
+ version_control = vcs.get_backend_from_location(location)
+ if version_control:
+ return version_control().get_src_requirement(dist, location, find_tags)
+ logger.warn('cannot determine version of editable source in %s (is not SVN checkout, Git clone, Mercurial clone or Bazaar branch)' % location)
+ return dist.as_requirement()
+
+def import_vcs_support():
+ # Import all the version control support modules:
+ here = os.path.dirname(__file__)
+ for name in os.listdir(here):
+ if name != '__init__.py' and name.endswith('.py'):
+ name = os.path.splitext(name)[0]
+ __import__('pip.vcs.%s' % name)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,133 @@
+import os
+import shutil
+import tempfile
+import re
+from pip import call_subprocess
+from pip.log import logger
+from pip.util import rmtree, display_path
+from pip.vcs import vcs, VersionControl
+
+class Bazaar(VersionControl):
+ name = 'bzr'
+ dirname = '.bzr'
+ repo_name = 'branch'
+ bundle_file = 'bzr-branch.txt'
+ schemes = ('bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp')
+ guide = ('# This was a Bazaar branch; to make it a branch again run:\n'
+ 'bzr branch -r %(rev)s %(url)s .\n')
+
+ def parse_vcs_bundle_file(self, content):
+ url = rev = None
+ for line in content.splitlines():
+ if not line.strip() or line.strip().startswith('#'):
+ continue
+ match = re.search(r'^bzr\s*branch\s*-r\s*(\d*)', line)
+ if match:
+ rev = match.group(1).strip()
+ url = line[match.end():].strip().split(None, 1)[0]
+ if url and rev:
+ return url, rev
+ return None, None
+
+ def unpack(self, location):
+ """Get the bzr branch at the url to the destination location"""
+ url, rev = self.get_url_rev()
+ logger.notify('Checking out bzr repository %s to %s' % (url, location))
+ logger.indent += 2
+ try:
+ if os.path.exists(location):
+ os.rmdir(location)
+ call_subprocess(
+ [self.cmd, 'branch', url, location],
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ logger.indent -= 2
+
+ def export(self, location):
+ """Export the Bazaar repository at the url to the destination location"""
+ temp_dir = tempfile.mkdtemp('-export', 'pip-')
+ self.unpack(temp_dir)
+ if os.path.exists(location):
+ # Remove the location to make sure Bazaar can export it correctly
+ rmtree(location)
+ try:
+ call_subprocess([self.cmd, 'export', location], cwd=temp_dir,
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ shutil.rmtree(temp_dir)
+
+ def switch(self, dest, url, rev_options):
+ call_subprocess([self.cmd, 'switch', url], cwd=dest)
+
+ def update(self, dest, rev_options):
+ call_subprocess(
+ [self.cmd, 'pull', '-q'] + rev_options, cwd=dest)
+
+ def obtain(self, dest):
+ url, rev = self.get_url_rev()
+ if rev:
+ rev_options = ['-r', rev]
+ rev_display = ' (to revision %s)' % rev
+ else:
+ rev_options = []
+ rev_display = ''
+ if self.check_destination(dest, url, rev_options, rev_display):
+ logger.notify('Checking out %s%s to %s'
+ % (url, rev_display, display_path(dest)))
+ call_subprocess(
+ [self.cmd, 'branch', '-q'] + rev_options + [url, dest])
+
+ def get_url_rev(self):
+ # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it
+ url, rev = super(Bazaar, self).get_url_rev()
+ if url.startswith('ssh://'):
+ url = 'bzr+' + url
+ return url, rev
+
+ def get_url(self, location):
+ urls = call_subprocess(
+ [self.cmd, 'info'], show_stdout=False, cwd=location)
+ for line in urls.splitlines():
+ line = line.strip()
+ for x in ('checkout of branch: ',
+ 'parent branch: '):
+ if line.startswith(x):
+ return line.split(x)[1]
+ return None
+
+ def get_revision(self, location):
+ revision = call_subprocess(
+ [self.cmd, 'revno'], show_stdout=False, cwd=location)
+ return revision.splitlines()[-1]
+
+ def get_tag_revs(self, location):
+ tags = call_subprocess(
+ [self.cmd, 'tags'], show_stdout=False, cwd=location)
+ tag_revs = []
+ for line in tags.splitlines():
+ tags_match = re.search(r'([.\w-]+)\s*(.*)$', line)
+ if tags_match:
+ tag = tags_match.group(1)
+ rev = tags_match.group(2)
+ tag_revs.append((rev.strip(), tag.strip()))
+ return dict(tag_revs)
+
+ def get_src_requirement(self, dist, location, find_tags):
+ repo = self.get_url(location)
+ if not repo.lower().startswith('bzr:'):
+ repo = 'bzr+' + repo
+ egg_project_name = dist.egg_name().split('-', 1)[0]
+ if not repo:
+ return None
+ current_rev = self.get_revision(location)
+ tag_revs = self.get_tag_revs(location)
+
+ if current_rev in tag_revs:
+ # It's a tag
+ tag = tag_revs.get(current_rev, current_rev)
+ full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev])
+ else:
+ full_egg_name = '%s-dev_r%s' % (dist.egg_name(), current_rev)
+ return '%s@%s#egg=%s' % (repo, current_rev, full_egg_name)
+
+vcs.register(Bazaar)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,185 @@
+import os
+import shutil
+import tempfile
+import re
+from pip import call_subprocess
+from pip.util import display_path
+from pip.vcs import vcs, VersionControl
+from pip.log import logger
+
+class Git(VersionControl):
+ name = 'git'
+ dirname = '.git'
+ repo_name = 'clone'
+ schemes = ('git', 'git+http', 'git+ssh', 'git+git')
+ bundle_file = 'git-clone.txt'
+ guide = ('# This was a Git repo; to make it a repo again run:\n'
+ 'git init\ngit remote add origin %(url)s -f\ngit checkout %(rev)s\n')
+
+ def parse_vcs_bundle_file(self, content):
+ url = rev = None
+ for line in content.splitlines():
+ if not line.strip() or line.strip().startswith('#'):
+ continue
+ url_match = re.search(r'git\s*remote\s*add\s*origin(.*)\s*-f', line)
+ if url_match:
+ url = url_match.group(1).strip()
+ rev_match = re.search(r'^git\s*checkout\s*-q\s*(.*)\s*', line)
+ if rev_match:
+ rev = rev_match.group(1).strip()
+ if url and rev:
+ return url, rev
+ return None, None
+
+ def unpack(self, location):
+ """Clone the Git repository at the url to the destination location"""
+ url, rev = self.get_url_rev()
+ logger.notify('Cloning Git repository %s to %s' % (url, location))
+ logger.indent += 2
+ try:
+ if os.path.exists(location):
+ os.rmdir(location)
+ call_subprocess(
+ [self.cmd, 'clone', url, location],
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ logger.indent -= 2
+
+ def export(self, location):
+ """Export the Git repository at the url to the destination location"""
+ temp_dir = tempfile.mkdtemp('-export', 'pip-')
+ self.unpack(temp_dir)
+ try:
+ if not location.endswith('/'):
+ location = location + '/'
+ call_subprocess(
+ [self.cmd, 'checkout-index', '-a', '-f', '--prefix', location],
+ filter_stdout=self._filter, show_stdout=False, cwd=temp_dir)
+ finally:
+ shutil.rmtree(temp_dir)
+
+ def check_rev_options(self, rev, dest, rev_options):
+ """Check the revision options before checkout to compensate that tags
+ and branches may need origin/ as a prefix"""
+ if rev is None:
+ # bail and use preset
+ return rev_options
+ revisions = self.get_tag_revs(dest)
+ revisions.update(self.get_branch_revs(dest))
+ if rev in revisions:
+ # if rev is a sha
+ return [rev]
+ inverse_revisions = dict((v,k) for k, v in revisions.iteritems())
+ if rev not in inverse_revisions: # is rev a name or tag?
+ origin_rev = 'origin/%s' % rev
+ if origin_rev in inverse_revisions:
+ rev = inverse_revisions[origin_rev]
+ else:
+ logger.warn("Could not find a tag or branch '%s', assuming commit." % rev)
+ return [rev]
+
+ def switch(self, dest, url, rev_options):
+ call_subprocess(
+ [self.cmd, 'config', 'remote.origin.url', url], cwd=dest)
+ call_subprocess(
+ [self.cmd, 'checkout', '-q'] + rev_options, cwd=dest)
+
+ def update(self, dest, rev_options):
+ call_subprocess([self.cmd, 'fetch', '-q'], cwd=dest)
+ call_subprocess(
+ [self.cmd, 'checkout', '-q', '-f'] + rev_options, cwd=dest)
+
+ def obtain(self, dest):
+ url, rev = self.get_url_rev()
+ if rev:
+ rev_options = [rev]
+ rev_display = ' (to %s)' % rev
+ else:
+ rev_options = ['master']
+ rev_display = ''
+ if self.check_destination(dest, url, rev_options, rev_display):
+ logger.notify('Cloning %s%s to %s' % (url, rev_display, display_path(dest)))
+ call_subprocess([self.cmd, 'clone', '-q', url, dest])
+ checked_rev = self.check_rev_options(rev, dest, rev_options)
+ # only explicitely checkout the "revision" in case the check
+ # found a valid tag, commit or branch
+ if rev_options != checked_rev:
+ call_subprocess(
+ [self.cmd, 'checkout', '-q'] + checked_rev, cwd=dest)
+
+ def get_url(self, location):
+ url = call_subprocess(
+ [self.cmd, 'config', 'remote.origin.url'],
+ show_stdout=False, cwd=location)
+ return url.strip()
+
+ def get_revision(self, location):
+ current_rev = call_subprocess(
+ [self.cmd, 'rev-parse', 'HEAD'], show_stdout=False, cwd=location)
+ return current_rev.strip()
+
+ def get_tag_revs(self, location):
+ tags = call_subprocess(
+ [self.cmd, 'tag', '-l'],
+ show_stdout=False, raise_on_returncode=False, cwd=location)
+ tag_revs = []
+ for line in tags.splitlines():
+ tag = line.strip()
+ rev = call_subprocess(
+ [self.cmd, 'rev-parse', tag], show_stdout=False, cwd=location)
+ tag_revs.append((rev.strip(), tag))
+ tag_revs = dict(tag_revs)
+ return tag_revs
+
+ def get_branch_revs(self, location):
+ branches = call_subprocess(
+ [self.cmd, 'branch', '-r'], show_stdout=False, cwd=location)
+ branch_revs = []
+ for line in branches.splitlines():
+ line = line.split('->')[0].strip()
+ branch = "".join([b for b in line.split() if b != '*'])
+ rev = call_subprocess(
+ [self.cmd, 'rev-parse', branch], show_stdout=False, cwd=location)
+ branch_revs.append((rev.strip(), branch))
+ branch_revs = dict(branch_revs)
+ return branch_revs
+
+ def get_src_requirement(self, dist, location, find_tags):
+ repo = self.get_url(location)
+ if not repo.lower().startswith('git:'):
+ repo = 'git+' + repo
+ egg_project_name = dist.egg_name().split('-', 1)[0]
+ if not repo:
+ return None
+ current_rev = self.get_revision(location)
+ tag_revs = self.get_tag_revs(location)
+ branch_revs = self.get_branch_revs(location)
+
+ if current_rev in tag_revs:
+ # It's a tag
+ full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev])
+ elif (current_rev in branch_revs and
+ branch_revs[current_rev] != 'origin/master'):
+ # It's the head of a branch
+ full_egg_name = '%s-%s' % (dist.egg_name(),
+ branch_revs[current_rev].replace('origin/', ''))
+ else:
+ full_egg_name = '%s-dev' % dist.egg_name()
+
+ return '%s@%s#egg=%s' % (repo, current_rev, full_egg_name)
+
+ def get_url_rev(self):
+ """
+ Prefixes stub URLs like 'user at hostname:user/repo.git' with 'ssh://'.
+ That's required because although they use SSH they sometimes doesn't
+ work with a ssh:// scheme (e.g. Github). But we need a scheme for
+ parsing. Hence we remove it again afterwards and return it as a stub.
+ """
+ if not '://' in self.url:
+ self.url = self.url.replace('git+', 'git+ssh://')
+ url, rev = super(Git, self).get_url_rev()
+ url = url.replace('ssh://', '')
+ return url, rev
+ return super(Git, self).get_url_rev()
+
+vcs.register(Git)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,161 @@
+import os
+import shutil
+import tempfile
+import re
+import ConfigParser
+from pip import call_subprocess
+from pip.util import display_path, path_to_url
+from pip.log import logger
+from pip.vcs import vcs, VersionControl
+
+
+class Mercurial(VersionControl):
+ name = 'hg'
+ dirname = '.hg'
+ repo_name = 'clone'
+ schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http')
+ bundle_file = 'hg-clone.txt'
+ guide = ('# This was a Mercurial repo; to make it a repo again run:\n'
+ 'hg init\nhg pull %(url)s\nhg update -r %(rev)s\n')
+
+ def parse_vcs_bundle_file(self, content):
+ url = rev = None
+ for line in content.splitlines():
+ if not line.strip() or line.strip().startswith('#'):
+ continue
+ url_match = re.search(r'hg\s*pull\s*(.*)\s*', line)
+ if url_match:
+ url = url_match.group(1).strip()
+ rev_match = re.search(r'^hg\s*update\s*-r\s*(.*)\s*', line)
+ if rev_match:
+ rev = rev_match.group(1).strip()
+ if url and rev:
+ return url, rev
+ return None, None
+
+ def unpack(self, location):
+ """Clone the Hg repository at the url to the destination location"""
+ url, rev = self.get_url_rev()
+ logger.notify('Cloning Mercurial repository %s to %s' % (url, location))
+ logger.indent += 2
+ try:
+ if os.path.exists(location):
+ os.rmdir(location)
+ call_subprocess(
+ [self.cmd, 'clone', url, location],
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ logger.indent -= 2
+
+ def export(self, location):
+ """Export the Hg repository at the url to the destination location"""
+ temp_dir = tempfile.mkdtemp('-export', 'pip-')
+ self.unpack(temp_dir)
+ try:
+ call_subprocess(
+ [self.cmd, 'archive', location],
+ filter_stdout=self._filter, show_stdout=False, cwd=temp_dir)
+ finally:
+ shutil.rmtree(temp_dir)
+
+ def switch(self, dest, url, rev_options):
+ repo_config = os.path.join(dest, self.dirname, 'hgrc')
+ config = ConfigParser.SafeConfigParser()
+ try:
+ config.read(repo_config)
+ config.set('paths', 'default', url)
+ config_file = open(repo_config, 'w')
+ config.write(config_file)
+ config_file.close()
+ except (OSError, ConfigParser.NoSectionError), e:
+ logger.warn(
+ 'Could not switch Mercurial repository to %s: %s'
+ % (url, e))
+ else:
+ call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest)
+
+ def update(self, dest, rev_options):
+ call_subprocess([self.cmd, 'pull', '-q'], cwd=dest)
+ call_subprocess(
+ [self.cmd, 'update', '-q'] + rev_options, cwd=dest)
+
+ def obtain(self, dest):
+ url, rev = self.get_url_rev()
+ if rev:
+ rev_options = [rev]
+ rev_display = ' (to revision %s)' % rev
+ else:
+ rev_options = []
+ rev_display = ''
+ if self.check_destination(dest, url, rev_options, rev_display):
+ logger.notify('Cloning hg %s%s to %s'
+ % (url, rev_display, display_path(dest)))
+ call_subprocess([self.cmd, 'clone', '--noupdate', '-q', url, dest])
+ call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest)
+
+ def get_url(self, location):
+ url = call_subprocess(
+ [self.cmd, 'showconfig', 'paths.default'],
+ show_stdout=False, cwd=location).strip()
+ if url.startswith('/') or url.startswith('\\'):
+ url = path_to_url(url)
+ return url.strip()
+
+ def get_tag_revs(self, location):
+ tags = call_subprocess(
+ [self.cmd, 'tags'], show_stdout=False, cwd=location)
+ tag_revs = []
+ for line in tags.splitlines():
+ tags_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line)
+ if tags_match:
+ tag = tags_match.group(1)
+ rev = tags_match.group(2)
+ tag_revs.append((rev.strip(), tag.strip()))
+ return dict(tag_revs)
+
+ def get_branch_revs(self, location):
+ branches = call_subprocess(
+ [self.cmd, 'branches'], show_stdout=False, cwd=location)
+ branch_revs = []
+ for line in branches.splitlines():
+ branches_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line)
+ if branches_match:
+ branch = branches_match.group(1)
+ rev = branches_match.group(2)
+ branch_revs.append((rev.strip(), branch.strip()))
+ return dict(branch_revs)
+
+ def get_revision(self, location):
+ current_revision = call_subprocess(
+ [self.cmd, 'parents', '--template={rev}'],
+ show_stdout=False, cwd=location).strip()
+ return current_revision
+
+ def get_revision_hash(self, location):
+ current_rev_hash = call_subprocess(
+ [self.cmd, 'parents', '--template={node}'],
+ show_stdout=False, cwd=location).strip()
+ return current_rev_hash
+
+ def get_src_requirement(self, dist, location, find_tags):
+ repo = self.get_url(location)
+ if not repo.lower().startswith('hg:'):
+ repo = 'hg+' + repo
+ egg_project_name = dist.egg_name().split('-', 1)[0]
+ if not repo:
+ return None
+ current_rev = self.get_revision(location)
+ current_rev_hash = self.get_revision_hash(location)
+ tag_revs = self.get_tag_revs(location)
+ branch_revs = self.get_branch_revs(location)
+ if current_rev in tag_revs:
+ # It's a tag
+ full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev])
+ elif current_rev in branch_revs:
+ # It's the tip of a branch
+ full_egg_name = '%s-%s' % (dist.egg_name(), branch_revs[current_rev])
+ else:
+ full_egg_name = '%s-dev' % dist.egg_name()
+ return '%s@%s#egg=%s' % (repo, current_rev_hash, full_egg_name)
+
+vcs.register(Mercurial)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,260 @@
+import os
+import re
+from pip import call_subprocess
+from pip.index import Link
+from pip.util import rmtree, display_path
+from pip.log import logger
+from pip.vcs import vcs, VersionControl
+
+_svn_xml_url_re = re.compile('url="([^"]+)"')
+_svn_rev_re = re.compile('committed-rev="(\d+)"')
+_svn_url_re = re.compile(r'URL: (.+)')
+_svn_revision_re = re.compile(r'Revision: (.+)')
+
+class Subversion(VersionControl):
+ name = 'svn'
+ dirname = '.svn'
+ repo_name = 'checkout'
+ schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https')
+ bundle_file = 'svn-checkout.txt'
+ guide = ('# This was an svn checkout; to make it a checkout again run:\n'
+ 'svn checkout --force -r %(rev)s %(url)s .\n')
+
+ def get_info(self, location):
+ """Returns (url, revision), where both are strings"""
+ assert not location.rstrip('/').endswith(self.dirname), 'Bad directory: %s' % location
+ output = call_subprocess(
+ [self.cmd, 'info', location], show_stdout=False, extra_environ={'LANG': 'C'})
+ match = _svn_url_re.search(output)
+ if not match:
+ logger.warn('Cannot determine URL of svn checkout %s' % display_path(location))
+ logger.info('Output that cannot be parsed: \n%s' % output)
+ return None, None
+ url = match.group(1).strip()
+ match = _svn_revision_re.search(output)
+ if not match:
+ logger.warn('Cannot determine revision of svn checkout %s' % display_path(location))
+ logger.info('Output that cannot be parsed: \n%s' % output)
+ return url, None
+ return url, match.group(1)
+
+ def parse_vcs_bundle_file(self, content):
+ for line in content.splitlines():
+ if not line.strip() or line.strip().startswith('#'):
+ continue
+ match = re.search(r'^-r\s*([^ ])?', line)
+ if not match:
+ return None, None
+ rev = match.group(1)
+ rest = line[match.end():].strip().split(None, 1)[0]
+ return rest, rev
+ return None, None
+
+ def unpack(self, location):
+ """Check out the svn repository at the url to the destination location"""
+ url, rev = self.get_url_rev()
+ logger.notify('Checking out svn repository %s to %s' % (url, location))
+ logger.indent += 2
+ try:
+ if os.path.exists(location):
+ # Subversion doesn't like to check out over an existing directory
+ # --force fixes this, but was only added in svn 1.5
+ rmtree(location)
+ call_subprocess(
+ [self.cmd, 'checkout', url, location],
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ logger.indent -= 2
+
+ def export(self, location):
+ """Export the svn repository at the url to the destination location"""
+ url, rev = self.get_url_rev()
+ logger.notify('Exporting svn repository %s to %s' % (url, location))
+ logger.indent += 2
+ try:
+ if os.path.exists(location):
+ # Subversion doesn't like to check out over an existing directory
+ # --force fixes this, but was only added in svn 1.5
+ rmtree(location)
+ call_subprocess(
+ [self.cmd, 'export', url, location],
+ filter_stdout=self._filter, show_stdout=False)
+ finally:
+ logger.indent -= 2
+
+ def switch(self, dest, url, rev_options):
+ call_subprocess(
+ [self.cmd, 'switch'] + rev_options + [url, dest])
+
+ def update(self, dest, rev_options):
+ call_subprocess(
+ [self.cmd, 'update'] + rev_options + [dest])
+
+ def obtain(self, dest):
+ url, rev = self.get_url_rev()
+ if rev:
+ rev_options = ['-r', rev]
+ rev_display = ' (to revision %s)' % rev
+ else:
+ rev_options = []
+ rev_display = ''
+ if self.check_destination(dest, url, rev_options, rev_display):
+ logger.notify('Checking out %s%s to %s'
+ % (url, rev_display, display_path(dest)))
+ call_subprocess(
+ [self.cmd, 'checkout', '-q'] + rev_options + [url, dest])
+
+ def get_location(self, dist, dependency_links):
+ egg_fragment_re = re.compile(r'#egg=(.*)$')
+ for url in dependency_links:
+ egg_fragment = Link(url).egg_fragment
+ if not egg_fragment:
+ continue
+ if '-' in egg_fragment:
+ ## FIXME: will this work when a package has - in the name?
+ key = '-'.join(egg_fragment.split('-')[:-1]).lower()
+ else:
+ key = egg_fragment
+ if key == dist.key:
+ return url.split('#', 1)[0]
+ return None
+
+ def get_revision(self, location):
+ """
+ Return the maximum revision for all files under a given location
+ """
+ # Note: taken from setuptools.command.egg_info
+ revision = 0
+
+ for base, dirs, files in os.walk(location):
+ if self.dirname not in dirs:
+ dirs[:] = []
+ continue # no sense walking uncontrolled subdirs
+ dirs.remove(self.dirname)
+ entries_fn = os.path.join(base, self.dirname, 'entries')
+ if not os.path.exists(entries_fn):
+ ## FIXME: should we warn?
+ continue
+ f = open(entries_fn)
+ data = f.read()
+ f.close()
+
+ if data.startswith('8') or data.startswith('9') or data.startswith('10'):
+ data = map(str.splitlines,data.split('\n\x0c\n'))
+ del data[0][0] # get rid of the '8'
+ dirurl = data[0][3]
+ revs = [int(d[9]) for d in data if len(d)>9 and d[9]]+[0]
+ if revs:
+ localrev = max(revs)
+ else:
+ localrev = 0
+ elif data.startswith('<?xml'):
+ dirurl = _svn_xml_url_re.search(data).group(1) # get repository URL
+ revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)]+[0]
+ if revs:
+ localrev = max(revs)
+ else:
+ localrev = 0
+ else:
+ logger.warn("Unrecognized .svn/entries format; skipping %s", base)
+ dirs[:] = []
+ continue
+ if base == location:
+ base_url = dirurl+'/' # save the root url
+ elif not dirurl.startswith(base_url):
+ dirs[:] = []
+ continue # not part of the same svn tree, skip it
+ revision = max(revision, localrev)
+ return revision
+
+ def get_url_rev(self):
+ # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it
+ url, rev = super(Subversion, self).get_url_rev()
+ if url.startswith('ssh://'):
+ url = 'svn+' + url
+ return url, rev
+
+ def get_url(self, location):
+ # In cases where the source is in a subdirectory, not alongside setup.py
+ # we have to look up in the location until we find a real setup.py
+ orig_location = location
+ while not os.path.exists(os.path.join(location, 'setup.py')):
+ last_location = location
+ location = os.path.dirname(location)
+ if location == last_location:
+ # We've traversed up to the root of the filesystem without finding setup.py
+ logger.warn("Could not find setup.py for directory %s (tried all parent directories)"
+ % orig_location)
+ return None
+ f = open(os.path.join(location, self.dirname, 'entries'))
+ data = f.read()
+ f.close()
+ if data.startswith('8') or data.startswith('9') or data.startswith('10'):
+ data = map(str.splitlines,data.split('\n\x0c\n'))
+ del data[0][0] # get rid of the '8'
+ return data[0][3]
+ elif data.startswith('<?xml'):
+ match = _svn_xml_url_re.search(data)
+ if not match:
+ raise ValueError('Badly formatted data: %r' % data)
+ return match.group(1) # get repository URL
+ else:
+ logger.warn("Unrecognized .svn/entries format in %s" % location)
+ # Or raise exception?
+ return None
+
+ def get_tag_revs(self, svn_tag_url):
+ stdout = call_subprocess(
+ [self.cmd, 'ls', '-v', svn_tag_url], show_stdout=False)
+ results = []
+ for line in stdout.splitlines():
+ parts = line.split()
+ rev = int(parts[0])
+ tag = parts[-1].strip('/')
+ results.append((tag, rev))
+ return results
+
+ def find_tag_match(self, rev, tag_revs):
+ best_match_rev = None
+ best_tag = None
+ for tag, tag_rev in tag_revs:
+ if (tag_rev > rev and
+ (best_match_rev is None or best_match_rev > tag_rev)):
+ # FIXME: Is best_match > tag_rev really possible?
+ # or is it a sign something is wacky?
+ best_match_rev = tag_rev
+ best_tag = tag
+ return best_tag
+
+ def get_src_requirement(self, dist, location, find_tags=False):
+ repo = self.get_url(location)
+ if repo is None:
+ return None
+ parts = repo.split('/')
+ ## FIXME: why not project name?
+ egg_project_name = dist.egg_name().split('-', 1)[0]
+ rev = self.get_revision(location)
+ if parts[-2] in ('tags', 'tag'):
+ # It's a tag, perfect!
+ full_egg_name = '%s-%s' % (egg_project_name, parts[-1])
+ elif parts[-2] in ('branches', 'branch'):
+ # It's a branch :(
+ full_egg_name = '%s-%s-r%s' % (dist.egg_name(), parts[-1], rev)
+ elif parts[-1] == 'trunk':
+ # Trunk :-/
+ full_egg_name = '%s-dev_r%s' % (dist.egg_name(), rev)
+ if find_tags:
+ tag_url = '/'.join(parts[:-1]) + '/tags'
+ tag_revs = self.get_tag_revs(tag_url)
+ match = self.find_tag_match(rev, tag_revs)
+ if match:
+ logger.notify('trunk checkout %s seems to be equivalent to tag %s' % match)
+ repo = '%s/%s' % (tag_url, match)
+ full_egg_name = '%s-%s' % (egg_project_name, match)
+ else:
+ # Don't know what it is
+ logger.warn('svn URL does not fit normal structure (tags/branches/trunk): %s' % repo)
+ full_egg_name = '%s-dev_r%s' % (egg_project_name, rev)
+ return 'svn+%s@%s#egg=%s' % (repo, rev, full_egg_name)
+
+vcs.register(Subversion)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,52 @@
+"""Tools for working with virtualenv environments"""
+
+import os
+import sys
+import subprocess
+from pip.exceptions import BadCommand
+from pip.log import logger
+
+def restart_in_venv(venv, base, site_packages, args):
+ """
+ Restart this script using the interpreter in the given virtual environment
+ """
+ if base and not os.path.isabs(venv) and not venv.startswith('~'):
+ base = os.path.expanduser(base)
+ # ensure we have an abs basepath at this point:
+ # a relative one makes no sense (or does it?)
+ if os.path.isabs(base):
+ venv = os.path.join(base, venv)
+
+ if venv.startswith('~'):
+ venv = os.path.expanduser(venv)
+
+ if not os.path.exists(venv):
+ try:
+ import virtualenv
+ except ImportError:
+ print 'The virtual environment does not exist: %s' % venv
+ print 'and virtualenv is not installed, so a new environment cannot be created'
+ sys.exit(3)
+ print 'Creating new virtualenv environment in %s' % venv
+ virtualenv.logger = logger
+ logger.indent += 2
+ virtualenv.create_environment(venv, site_packages=site_packages)
+ if sys.platform == 'win32':
+ python = os.path.join(venv, 'Scripts', 'python.exe')
+ # check for bin directory which is used in buildouts
+ if not os.path.exists(python):
+ python = os.path.join(venv, 'bin', 'python.exe')
+ else:
+ python = os.path.join(venv, 'bin', 'python')
+ if not os.path.exists(python):
+ python = venv
+ if not os.path.exists(python):
+ raise BadCommand('Cannot find virtual environment interpreter at %s' % python)
+ base = os.path.dirname(os.path.dirname(python))
+ file = os.path.join(os.path.dirname(__file__), 'runner.py')
+ if file.endswith('.pyc'):
+ file = file[:-1]
+ proc = subprocess.Popen(
+ [python, file] + args + [base, '___VENV_RESTART___'])
+ proc.wait()
+ sys.exit(proc.returncode)
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg
===================================================================
(Binary files differ)
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools.pth
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools.pth (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site-packages/setuptools.pth 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+./setuptools-0.6c11-py2.6.egg
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/site.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1,701 @@
+"""Append module search paths for third-party packages to sys.path.
+
+****************************************************************
+* This module is automatically imported during initialization. *
+****************************************************************
+
+In earlier versions of Python (up to 1.5a3), scripts or modules that
+needed to use site-specific modules would place ``import site''
+somewhere near the top of their code. Because of the automatic
+import, this is no longer necessary (but code that does it still
+works).
+
+This will append site-specific paths to the module search path. On
+Unix, it starts with sys.prefix and sys.exec_prefix (if different) and
+appends lib/python<version>/site-packages as well as lib/site-python.
+It also supports the Debian convention of
+lib/python<version>/dist-packages. On other platforms (mainly Mac and
+Windows), it uses just sys.prefix (and sys.exec_prefix, if different,
+but this is unlikely). The resulting directories, if they exist, are
+appended to sys.path, and also inspected for path configuration files.
+
+FOR DEBIAN, this sys.path is augmented with directories in /usr/local.
+Local addons go into /usr/local/lib/python<version>/site-packages
+(resp. /usr/local/lib/site-python), Debian addons install into
+/usr/{lib,share}/python<version>/dist-packages.
+
+A path configuration file is a file whose name has the form
+<package>.pth; its contents are additional directories (one per line)
+to be added to sys.path. Non-existing directories (or
+non-directories) are never added to sys.path; no directory is added to
+sys.path more than once. Blank lines and lines beginning with
+'#' are skipped. Lines starting with 'import' are executed.
+
+For example, suppose sys.prefix and sys.exec_prefix are set to
+/usr/local and there is a directory /usr/local/lib/python2.X/site-packages
+with three subdirectories, foo, bar and spam, and two path
+configuration files, foo.pth and bar.pth. Assume foo.pth contains the
+following:
+
+ # foo package configuration
+ foo
+ bar
+ bletch
+
+and bar.pth contains:
+
+ # bar package configuration
+ bar
+
+Then the following directories are added to sys.path, in this order:
+
+ /usr/local/lib/python2.X/site-packages/bar
+ /usr/local/lib/python2.X/site-packages/foo
+
+Note that bletch is omitted because it doesn't exist; bar precedes foo
+because bar.pth comes alphabetically before foo.pth; and spam is
+omitted because it is not mentioned in either path configuration file.
+
+After these path manipulations, an attempt is made to import a module
+named sitecustomize, which can perform arbitrary additional
+site-specific customizations. If this import fails with an
+ImportError exception, it is silently ignored.
+
+"""
+
+import sys
+import os
+import __builtin__
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+# Prefixes for site-packages; add additional prefixes like /usr/local here
+PREFIXES = [sys.prefix, sys.exec_prefix]
+# Enable per user site-packages directory
+# set it to False to disable the feature or True to force the feature
+ENABLE_USER_SITE = None
+# for distutils.commands.install
+USER_SITE = None
+USER_BASE = None
+
+_is_jython = sys.platform[:4] == 'java'
+if _is_jython:
+ ModuleType = type(os)
+
+def makepath(*paths):
+ dir = os.path.join(*paths)
+ if _is_jython and (dir == '__classpath__' or
+ dir.startswith('__pyclasspath__')):
+ return dir, dir
+ dir = os.path.abspath(dir)
+ return dir, os.path.normcase(dir)
+
+def abs__file__():
+ """Set all module' __file__ attribute to an absolute path"""
+ for m in sys.modules.values():
+ if ((_is_jython and not isinstance(m, ModuleType)) or
+ hasattr(m, '__loader__')):
+ # only modules need the abspath in Jython. and don't mess
+ # with a PEP 302-supplied __file__
+ continue
+ f = getattr(m, '__file__', None)
+ if f is None:
+ continue
+ m.__file__ = os.path.abspath(f)
+
+def removeduppaths():
+ """ Remove duplicate entries from sys.path along with making them
+ absolute"""
+ # This ensures that the initial path provided by the interpreter contains
+ # only absolute pathnames, even if we're running from the build directory.
+ L = []
+ known_paths = set()
+ for dir in sys.path:
+ # Filter out duplicate paths (on case-insensitive file systems also
+ # if they only differ in case); turn relative paths into absolute
+ # paths.
+ dir, dircase = makepath(dir)
+ if not dircase in known_paths:
+ L.append(dir)
+ known_paths.add(dircase)
+ sys.path[:] = L
+ return known_paths
+
+# XXX This should not be part of site.py, since it is needed even when
+# using the -S option for Python. See http://www.python.org/sf/586680
+def addbuilddir():
+ """Append ./build/lib.<platform> in case we're running in the build dir
+ (especially for Guido :-)"""
+ from distutils.util import get_platform
+ s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
+ if hasattr(sys, 'gettotalrefcount'):
+ s += '-pydebug'
+ s = os.path.join(os.path.dirname(sys.path[-1]), s)
+ sys.path.append(s)
+
+def _init_pathinfo():
+ """Return a set containing all existing directory entries from sys.path"""
+ d = set()
+ for dir in sys.path:
+ try:
+ if os.path.isdir(dir):
+ dir, dircase = makepath(dir)
+ d.add(dircase)
+ except TypeError:
+ continue
+ return d
+
+def addpackage(sitedir, name, known_paths):
+ """Add a new path to known_paths by combining sitedir and 'name' or execute
+ sitedir if it starts with 'import'"""
+ if known_paths is None:
+ _init_pathinfo()
+ reset = 1
+ else:
+ reset = 0
+ fullname = os.path.join(sitedir, name)
+ try:
+ f = open(fullname, "rU")
+ except IOError:
+ return
+ try:
+ for line in f:
+ if line.startswith("#"):
+ continue
+ if line.startswith("import"):
+ exec line
+ continue
+ line = line.rstrip()
+ dir, dircase = makepath(sitedir, line)
+ if not dircase in known_paths and os.path.exists(dir):
+ sys.path.append(dir)
+ known_paths.add(dircase)
+ finally:
+ f.close()
+ if reset:
+ known_paths = None
+ return known_paths
+
+def addsitedir(sitedir, known_paths=None):
+ """Add 'sitedir' argument to sys.path if missing and handle .pth files in
+ 'sitedir'"""
+ if known_paths is None:
+ known_paths = _init_pathinfo()
+ reset = 1
+ else:
+ reset = 0
+ sitedir, sitedircase = makepath(sitedir)
+ if not sitedircase in known_paths:
+ sys.path.append(sitedir) # Add path component
+ try:
+ names = os.listdir(sitedir)
+ except os.error:
+ return
+ names.sort()
+ for name in names:
+ if name.endswith(os.extsep + "pth"):
+ addpackage(sitedir, name, known_paths)
+ if reset:
+ known_paths = None
+ return known_paths
+
+def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_prefix):
+ """Add site-packages (and possibly site-python) to sys.path"""
+ prefixes = [os.path.join(sys_prefix, "local"), sys_prefix]
+ if exec_prefix != sys_prefix:
+ prefixes.append(os.path.join(exec_prefix, "local"))
+
+ for prefix in prefixes:
+ if prefix:
+ if sys.platform in ('os2emx', 'riscos') or _is_jython:
+ sitedirs = [os.path.join(prefix, "Lib", "site-packages")]
+ elif sys.platform == 'darwin' and prefix == sys_prefix:
+
+ if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python
+
+ sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"),
+ os.path.join(prefix, "Extras", "lib", "python")]
+
+ else: # any other Python distros on OSX work this way
+ sitedirs = [os.path.join(prefix, "lib",
+ "python" + sys.version[:3], "site-packages")]
+
+ elif os.sep == '/':
+ sitedirs = [os.path.join(prefix,
+ "lib",
+ "python" + sys.version[:3],
+ "site-packages"),
+ os.path.join(prefix, "lib", "site-python"),
+ os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")]
+ lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages")
+ if (os.path.exists(lib64_dir) and
+ os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]):
+ sitedirs.append(lib64_dir)
+ try:
+ # sys.getobjects only available in --with-pydebug build
+ sys.getobjects
+ sitedirs.insert(0, os.path.join(sitedirs[0], 'debug'))
+ except AttributeError:
+ pass
+ # Debian-specific dist-packages directories:
+ sitedirs.append(os.path.join(prefix, "lib",
+ "python" + sys.version[:3],
+ "dist-packages"))
+ sitedirs.append(os.path.join(prefix, "local/lib",
+ "python" + sys.version[:3],
+ "dist-packages"))
+ sitedirs.append(os.path.join(prefix, "lib", "dist-python"))
+ else:
+ sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")]
+ if sys.platform == 'darwin':
+ # for framework builds *only* we add the standard Apple
+ # locations. Currently only per-user, but /Library and
+ # /Network/Library could be added too
+ if 'Python.framework' in prefix:
+ home = os.environ.get('HOME')
+ if home:
+ sitedirs.append(
+ os.path.join(home,
+ 'Library',
+ 'Python',
+ sys.version[:3],
+ 'site-packages'))
+ for sitedir in sitedirs:
+ if os.path.isdir(sitedir):
+ addsitedir(sitedir, known_paths)
+ return None
+
+def check_enableusersite():
+ """Check if user site directory is safe for inclusion
+
+ The function tests for the command line flag (including environment var),
+ process uid/gid equal to effective uid/gid.
+
+ None: Disabled for security reasons
+ False: Disabled by user (command line option)
+ True: Safe and enabled
+ """
+ if hasattr(sys, 'flags') and getattr(sys.flags, 'no_user_site', False):
+ return False
+
+ if hasattr(os, "getuid") and hasattr(os, "geteuid"):
+ # check process uid == effective uid
+ if os.geteuid() != os.getuid():
+ return None
+ if hasattr(os, "getgid") and hasattr(os, "getegid"):
+ # check process gid == effective gid
+ if os.getegid() != os.getgid():
+ return None
+
+ return True
+
+def addusersitepackages(known_paths):
+ """Add a per user site-package to sys.path
+
+ Each user has its own python directory with site-packages in the
+ home directory.
+
+ USER_BASE is the root directory for all Python versions
+
+ USER_SITE is the user specific site-packages directory
+
+ USER_SITE/.. can be used for data.
+ """
+ global USER_BASE, USER_SITE, ENABLE_USER_SITE
+ env_base = os.environ.get("PYTHONUSERBASE", None)
+
+ def joinuser(*args):
+ return os.path.expanduser(os.path.join(*args))
+
+ #if sys.platform in ('os2emx', 'riscos'):
+ # # Don't know what to put here
+ # USER_BASE = ''
+ # USER_SITE = ''
+ if os.name == "nt":
+ base = os.environ.get("APPDATA") or "~"
+ if env_base:
+ USER_BASE = env_base
+ else:
+ USER_BASE = joinuser(base, "Python")
+ USER_SITE = os.path.join(USER_BASE,
+ "Python" + sys.version[0] + sys.version[2],
+ "site-packages")
+ else:
+ if env_base:
+ USER_BASE = env_base
+ else:
+ USER_BASE = joinuser("~", ".local")
+ USER_SITE = os.path.join(USER_BASE, "lib",
+ "python" + sys.version[:3],
+ "site-packages")
+
+ if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
+ addsitedir(USER_SITE, known_paths)
+ if ENABLE_USER_SITE:
+ for dist_libdir in ("lib", "local/lib"):
+ user_site = os.path.join(USER_BASE, dist_libdir,
+ "python" + sys.version[:3],
+ "dist-packages")
+ if os.path.isdir(user_site):
+ addsitedir(user_site, known_paths)
+ return known_paths
+
+
+
+def setBEGINLIBPATH():
+ """The OS/2 EMX port has optional extension modules that do double duty
+ as DLLs (and must use the .DLL file extension) for other extensions.
+ The library search path needs to be amended so these will be found
+ during module import. Use BEGINLIBPATH so that these are at the start
+ of the library search path.
+
+ """
+ dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
+ libpath = os.environ['BEGINLIBPATH'].split(';')
+ if libpath[-1]:
+ libpath.append(dllpath)
+ else:
+ libpath[-1] = dllpath
+ os.environ['BEGINLIBPATH'] = ';'.join(libpath)
+
+
+def setquit():
+ """Define new built-ins 'quit' and 'exit'.
+ These are simply strings that display a hint on how to exit.
+
+ """
+ if os.sep == ':':
+ eof = 'Cmd-Q'
+ elif os.sep == '\\':
+ eof = 'Ctrl-Z plus Return'
+ else:
+ eof = 'Ctrl-D (i.e. EOF)'
+
+ class Quitter(object):
+ def __init__(self, name):
+ self.name = name
+ def __repr__(self):
+ return 'Use %s() or %s to exit' % (self.name, eof)
+ def __call__(self, code=None):
+ # Shells like IDLE catch the SystemExit, but listen when their
+ # stdin wrapper is closed.
+ try:
+ sys.stdin.close()
+ except:
+ pass
+ raise SystemExit(code)
+ __builtin__.quit = Quitter('quit')
+ __builtin__.exit = Quitter('exit')
+
+
+class _Printer(object):
+ """interactive prompt objects for printing the license text, a list of
+ contributors and the copyright notice."""
+
+ MAXLINES = 23
+
+ def __init__(self, name, data, files=(), dirs=()):
+ self.__name = name
+ self.__data = data
+ self.__files = files
+ self.__dirs = dirs
+ self.__lines = None
+
+ def __setup(self):
+ if self.__lines:
+ return
+ data = None
+ for dir in self.__dirs:
+ for filename in self.__files:
+ filename = os.path.join(dir, filename)
+ try:
+ fp = file(filename, "rU")
+ data = fp.read()
+ fp.close()
+ break
+ except IOError:
+ pass
+ if data:
+ break
+ if not data:
+ data = self.__data
+ self.__lines = data.split('\n')
+ self.__linecnt = len(self.__lines)
+
+ def __repr__(self):
+ self.__setup()
+ if len(self.__lines) <= self.MAXLINES:
+ return "\n".join(self.__lines)
+ else:
+ return "Type %s() to see the full %s text" % ((self.__name,)*2)
+
+ def __call__(self):
+ self.__setup()
+ prompt = 'Hit Return for more, or q (and Return) to quit: '
+ lineno = 0
+ while 1:
+ try:
+ for i in range(lineno, lineno + self.MAXLINES):
+ print self.__lines[i]
+ except IndexError:
+ break
+ else:
+ lineno += self.MAXLINES
+ key = None
+ while key is None:
+ key = raw_input(prompt)
+ if key not in ('', 'q'):
+ key = None
+ if key == 'q':
+ break
+
+def setcopyright():
+ """Set 'copyright' and 'credits' in __builtin__"""
+ __builtin__.copyright = _Printer("copyright", sys.copyright)
+ if _is_jython:
+ __builtin__.credits = _Printer(
+ "credits",
+ "Jython is maintained by the Jython developers (www.jython.org).")
+ else:
+ __builtin__.credits = _Printer("credits", """\
+ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
+ for supporting Python development. See www.python.org for more information.""")
+ here = os.path.dirname(os.__file__)
+ __builtin__.license = _Printer(
+ "license", "See http://www.python.org/%.3s/license.html" % sys.version,
+ ["LICENSE.txt", "LICENSE"],
+ [os.path.join(here, os.pardir), here, os.curdir])
+
+
+class _Helper(object):
+ """Define the built-in 'help'.
+ This is a wrapper around pydoc.help (with a twist).
+
+ """
+
+ def __repr__(self):
+ return "Type help() for interactive help, " \
+ "or help(object) for help about object."
+ def __call__(self, *args, **kwds):
+ import pydoc
+ return pydoc.help(*args, **kwds)
+
+def sethelper():
+ __builtin__.help = _Helper()
+
+def aliasmbcs():
+ """On Windows, some default encodings are not provided by Python,
+ while they are always available as "mbcs" in each locale. Make
+ them usable by aliasing to "mbcs" in such a case."""
+ if sys.platform == 'win32':
+ import locale, codecs
+ enc = locale.getdefaultlocale()[1]
+ if enc.startswith('cp'): # "cp***" ?
+ try:
+ codecs.lookup(enc)
+ except LookupError:
+ import encodings
+ encodings._cache[enc] = encodings._unknown
+ encodings.aliases.aliases[enc] = 'mbcs'
+
+def setencoding():
+ """Set the string encoding used by the Unicode implementation. The
+ default is 'ascii', but if you're willing to experiment, you can
+ change this."""
+ encoding = "ascii" # Default value set by _PyUnicode_Init()
+ if 0:
+ # Enable to support locale aware default string encodings.
+ import locale
+ loc = locale.getdefaultlocale()
+ if loc[1]:
+ encoding = loc[1]
+ if 0:
+ # Enable to switch off string to Unicode coercion and implicit
+ # Unicode to string conversion.
+ encoding = "undefined"
+ if encoding != "ascii":
+ # On Non-Unicode builds this will raise an AttributeError...
+ sys.setdefaultencoding(encoding) # Needs Python Unicode build !
+
+
+def execsitecustomize():
+ """Run custom site specific code, if available."""
+ try:
+ import sitecustomize
+ except ImportError:
+ pass
+
+def virtual_install_main_packages():
+ f = open(os.path.join(os.path.dirname(__file__), 'orig-prefix.txt'))
+ sys.real_prefix = f.read().strip()
+ f.close()
+ pos = 2
+ if sys.path[0] == '':
+ pos += 1
+ if sys.platform == 'win32':
+ paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
+ elif _is_jython:
+ paths = [os.path.join(sys.real_prefix, 'Lib')]
+ else:
+ paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])]
+ lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3])
+ if os.path.exists(lib64_path):
+ paths.append(lib64_path)
+ # This is hardcoded in the Python executable, but relative to sys.prefix:
+ plat_path = os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3],
+ 'plat-%s' % sys.platform)
+ if os.path.exists(plat_path):
+ paths.append(plat_path)
+ # This is hardcoded in the Python executable, but
+ # relative to sys.prefix, so we have to fix up:
+ for path in list(paths):
+ tk_dir = os.path.join(path, 'lib-tk')
+ if os.path.exists(tk_dir):
+ paths.append(tk_dir)
+
+ # These are hardcoded in the Apple's Python executable,
+ # but relative to sys.prefix, so we have to fix them up:
+ if sys.platform == 'darwin':
+ hardcoded_paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3], module)
+ for module in ('plat-darwin', 'plat-mac', 'plat-mac/lib-scriptpackages')]
+
+ for path in hardcoded_paths:
+ if os.path.exists(path):
+ paths.append(path)
+
+ sys.path.extend(paths)
+
+def force_global_eggs_after_local_site_packages():
+ """
+ Force easy_installed eggs in the global environment to get placed
+ in sys.path after all packages inside the virtualenv. This
+ maintains the "least surprise" result that packages in the
+ virtualenv always mask global packages, never the other way
+ around.
+
+ """
+ egginsert = getattr(sys, '__egginsert', 0)
+ for i, path in enumerate(sys.path):
+ if i > egginsert and path.startswith(sys.prefix):
+ egginsert = i
+ sys.__egginsert = egginsert + 1
+
+def virtual_addsitepackages(known_paths):
+ force_global_eggs_after_local_site_packages()
+ return addsitepackages(known_paths, sys_prefix=sys.real_prefix)
+
+def fixclasspath():
+ """Adjust the special classpath sys.path entries for Jython. These
+ entries should follow the base virtualenv lib directories.
+ """
+ paths = []
+ classpaths = []
+ for path in sys.path:
+ if path == '__classpath__' or path.startswith('__pyclasspath__'):
+ classpaths.append(path)
+ else:
+ paths.append(path)
+ sys.path = paths
+ sys.path.extend(classpaths)
+
+def execusercustomize():
+ """Run custom user specific code, if available."""
+ try:
+ import usercustomize
+ except ImportError:
+ pass
+
+
+def main():
+ global ENABLE_USER_SITE
+ virtual_install_main_packages()
+ abs__file__()
+ paths_in_sys = removeduppaths()
+ if (os.name == "posix" and sys.path and
+ os.path.basename(sys.path[-1]) == "Modules"):
+ addbuilddir()
+ if _is_jython:
+ fixclasspath()
+ GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), 'no-global-site-packages.txt'))
+ if not GLOBAL_SITE_PACKAGES:
+ ENABLE_USER_SITE = False
+ if ENABLE_USER_SITE is None:
+ ENABLE_USER_SITE = check_enableusersite()
+ paths_in_sys = addsitepackages(paths_in_sys)
+ paths_in_sys = addusersitepackages(paths_in_sys)
+ if GLOBAL_SITE_PACKAGES:
+ paths_in_sys = virtual_addsitepackages(paths_in_sys)
+ if sys.platform == 'os2emx':
+ setBEGINLIBPATH()
+ setquit()
+ setcopyright()
+ sethelper()
+ aliasmbcs()
+ setencoding()
+ execsitecustomize()
+ if ENABLE_USER_SITE:
+ execusercustomize()
+ # Remove sys.setdefaultencoding() so that users cannot change the
+ # encoding after initialization. The test for presence is needed when
+ # this module is run as a script, because this code is executed twice.
+ if hasattr(sys, "setdefaultencoding"):
+ del sys.setdefaultencoding
+
+main()
+
+def _script():
+ help = """\
+ %s [--user-base] [--user-site]
+
+ Without arguments print some useful information
+ With arguments print the value of USER_BASE and/or USER_SITE separated
+ by '%s'.
+
+ Exit codes with --user-base or --user-site:
+ 0 - user site directory is enabled
+ 1 - user site directory is disabled by user
+ 2 - uses site directory is disabled by super user
+ or for security reasons
+ >2 - unknown error
+ """
+ args = sys.argv[1:]
+ if not args:
+ print "sys.path = ["
+ for dir in sys.path:
+ print " %r," % (dir,)
+ print "]"
+ def exists(path):
+ if os.path.isdir(path):
+ return "exists"
+ else:
+ return "doesn't exist"
+ print "USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE))
+ print "USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE))
+ print "ENABLE_USER_SITE: %r" % ENABLE_USER_SITE
+ sys.exit(0)
+
+ buffer = []
+ if '--user-base' in args:
+ buffer.append(USER_BASE)
+ if '--user-site' in args:
+ buffer.append(USER_SITE)
+
+ if buffer:
+ print os.pathsep.join(buffer)
+ if ENABLE_USER_SITE:
+ sys.exit(0)
+ elif ENABLE_USER_SITE is False:
+ sys.exit(1)
+ elif ENABLE_USER_SITE is None:
+ sys.exit(2)
+ else:
+ sys.exit(3)
+ else:
+ import textwrap
+ print textwrap.dedent(help % (sys.argv[0], os.pathsep))
+ sys.exit(10)
+
+if __name__ == '__main__':
+ _script()
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/sre.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_compile.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_compile.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_compile.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/sre_compile.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_compile.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_constants.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_constants.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_constants.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/sre_constants.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_constants.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_parse.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_parse.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_parse.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/sre_parse.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/sre_parse.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/stat.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/stat.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/stat.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/stat.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/stat.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/types.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/types.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/types.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/types.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/types.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/warnings.py
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/lib/python2.6/warnings.py (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/lib/python2.6/warnings.py 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+link /opt/python-2.6.4/lib/python2.6/warnings.py
\ No newline at end of file
Property changes on: zopeorg.buildout/branches/beta.zope.org/lib/python2.6/warnings.py
___________________________________________________________________
Added: svn:special
+ *
Added: zopeorg.buildout/branches/beta.zope.org/src/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/src/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/src/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+Packages in eggs that you develop should go in this directory
Added: zopeorg.buildout/branches/beta.zope.org/var/README.txt
===================================================================
--- zopeorg.buildout/branches/beta.zope.org/var/README.txt (rev 0)
+++ zopeorg.buildout/branches/beta.zope.org/var/README.txt 2011-05-09 12:32:56 UTC (rev 121636)
@@ -0,0 +1 @@
+This directory contains the Data.fs ZODB data storage, and other runtime files
More information about the checkins
mailing list