[Checkins] SVN: van.pydeb/ Initial import of van.pydeb. This package extends and replaces
Brian Sutherland
jinty at web.de
Tue May 26 09:14:01 EDT 2009
Log message for revision 100399:
Initial import of van.pydeb. This package extends and replaces
vanguardistas.pydebdep.
It also breaks backwards compatibility badly (which is why it's a new package).
vanguardistas.pydebdep will shortly be removed.
Changed:
A van.pydeb/
A van.pydeb/trunk/
A van.pydeb/trunk/README.txt
A van.pydeb/trunk/buildout.cfg
A van.pydeb/trunk/setup.py
A van.pydeb/trunk/van/
A van.pydeb/trunk/van/__init__.py
A van.pydeb/trunk/van/pydeb/
A van.pydeb/trunk/van/pydeb/__init__.py
A van.pydeb/trunk/van/pydeb/py_to_bin.txt
A van.pydeb/trunk/van/pydeb/py_to_src.txt
A van.pydeb/trunk/van/pydeb/tests/
A van.pydeb/trunk/van/pydeb/tests/__init__.py
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/PKG-INFO
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/SOURCES.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/dependency_links.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/namespace_packages.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/requires.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/top_level.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/PKG-INFO
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/SOURCES.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/dependency_links.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/namespace_packages.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/requires.txt
A van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/top_level.txt
A van.pydeb/trunk/van/pydeb/tests/extras.txt
A van.pydeb/trunk/van/pydeb/tests/test_doctest.py
A van.pydeb/trunk/van/pydeb/tests/translations.txt
A van.pydeb/trunk/van/pydeb/tests/version.txt
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/PKG-INFO
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/SOURCES.txt
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/dependency_links.txt
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/namespace_packages.txt
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/not-zip-safe
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/requires.txt
A van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/top_level.txt
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/PKG-INFO
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/SOURCES.txt
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/dependency_links.txt
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/namespace_packages.txt
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/not-zip-safe
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/requires.txt
A van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/top_level.txt
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/PKG-INFO
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/SOURCES.txt
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/dependency_links.txt
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/namespace_packages.txt
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/not-zip-safe
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/requires.txt
A van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/top_level.txt
-=-
Added: van.pydeb/trunk/README.txt
===================================================================
--- van.pydeb/trunk/README.txt (rev 0)
+++ van.pydeb/trunk/README.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,45 @@
+PyDebDep
+========
+
+Tools for introspecting egg-info directories and translating the resulting
+information into debian format. This information is translated:
+
+ * Setuptools version numbers to debian format that sorts correctly
+ * Setuptools package names to debian binary and source package names
+ * Setuptools dependencies to debian dependencies
+
+This package provides a script ``pydebdep`` which introspects an installed
+.egg-info to extract egg dependency information. The package names are
+converted to their debian equivilant and the dependency information is printed
+in the format of a dpkg "Depends:" line.
+
+Usage
+-----
+
+To extract the dependency info of this package, one can::
+
+ $ python2.4 setup.py build
+ $ PYTHONPATH=./src python2.4 pydebdep --depends --egg_info src/vanguardistas.pydebdep.egg-info
+ python-setuptools, python-vanguardistas
+
+This information can then used in a debian/rules file as follows:
+
+ i="$$(pydebdep --depends --egg_info debian/$(PACKAGE)/usr/lib/python$*/site-packages/$(EGG_NAME).egg-info)" && echo "setuptools:Depends=$$i" >> debian/$(PACKAGE).substvars
+
+The different methods of using this are:
+
+Give the dependencies (including the extra dependencies) of the package:
+
+ pydebdep depends --egg_info debian/$(PACKAGE)/usr/lip/python$*/$(EGG_NAME).egg-info
+
+The dependencies of an extra:
+
+ pydebdep depends --egg_info debian/$(PACKAGE)/usr/lip/python$*/$(EGG_NAME).egg-info --extra $(EXTRA)
+
+The dependencies of 2 extras:
+
+ pydebdep depends --egg_info debian/$(PACKAGE)/usr/lip/python$*/$(EGG_NAME).egg-info --extra $(EXTRA) --extra $(EXTRA2)
+
+The dependencies of a package excluding the dependencies of extras:
+
+ pydebdep depends --egg_info debian/$(PACKAGE)/usr/lip/python$*/$(EGG_NAME).egg-info --exclude-extra $(EXTRA1) --exclude-extra $(EXTRA2)
Property changes on: van.pydeb/trunk/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/buildout.cfg
===================================================================
--- van.pydeb/trunk/buildout.cfg (rev 0)
+++ van.pydeb/trunk/buildout.cfg 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,13 @@
+[buildout]
+parts = test interp
+develop = .
+project = van.pydeb
+
+[interp]
+recipe = zc.recipe.egg
+eggs = ${buildout:project}
+interpreter = python
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = ${buildout:project}
Added: van.pydeb/trunk/setup.py
===================================================================
--- van.pydeb/trunk/setup.py (rev 0)
+++ van.pydeb/trunk/setup.py 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2008 Vanguardistas 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.
+#
+##############################################################################
+import os
+from setuptools import setup, find_packages
+
+long_description = open('README.txt', 'r').read()
+
+setup(name="van.pydeb",
+ description='Make egg metadata information available for Debian packaging',
+ long_description=long_description,
+ author="Vanguardistas",
+ url='http://pypi.python.org/pypi/van.pydeb',
+ version='1.0.0dev',
+ license = 'ZPL 2.1',
+ packages=find_packages(),
+ entry_points = {'console_scripts': ['van_pydeb = van.pydeb:main',]},
+ namespace_packages=["van"],
+ install_requires=[
+ 'setuptools',
+ ],
+ classifiers=['Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'Topic :: System :: Archiving :: Packaging',
+ 'License :: DFSG approved',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Framework :: Setuptools Plugin',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: Python',
+ ],
+ include_package_data = True,
+ zip_safe = False,
+ )
Property changes on: van.pydeb/trunk/setup.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/__init__.py
===================================================================
--- van.pydeb/trunk/van/__init__.py (rev 0)
+++ van.pydeb/trunk/van/__init__.py 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,3 @@
+# this is a namespace package
+import pkg_resources
+pkg_resources.declare_namespace(__name__)
Property changes on: van.pydeb/trunk/van/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/__init__.py
===================================================================
--- van.pydeb/trunk/van/pydeb/__init__.py (rev 0)
+++ van.pydeb/trunk/van/pydeb/__init__.py 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,206 @@
+##############################################################################
+#
+# Copyright (c) 2008 Vanguardistas 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.
+#
+##############################################################################
+import sys
+import os.path
+import optparse
+
+from pkg_resources import PathMetadata, Distribution
+from pkg_resources import component_re # Is this a public interface?
+
+_HERE = os.path.dirname(__file__)
+#
+# Package name conversion
+#
+
+# An attempt at a cannonical list of translations
+def _read_map(file):
+ map = {}
+ reverse_map = {}
+ try:
+ f = open(file, 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ k, v = line.split()
+ assert k not in map, "Duplicate key %s already in map. File %s" % (k, file)
+ map[k] = v
+ assert v not in reverse_map, "Duplicate key %s already in reverse map. File %s" % (v, file)
+ reverse_map[v] = k
+ finally:
+ f.close()
+ return map, reverse_map
+
+_PY_TO_BIN, _BIN_TO_PY = _read_map(os.path.join(_HERE, 'py_to_bin.txt'))
+_PY_TO_SRC, _SRC_TO_PY = _read_map(os.path.join(_HERE, 'py_to_src.txt'))
+
+def py_to_bin(setuptools_project):
+ """Convert a setuptools project name to a debian binary package name"""
+ return _PY_TO_BIN.get(setuptools_project, 'python-%s' % setuptools_project.lower())
+
+def py_to_src(setuptools_project):
+ """Convert a setuptools project name to a debian source package name"""
+ return _PY_TO_SRC.get(setuptools_project, setuptools_project.lower())
+
+def bin_to_py(binary_package):
+ """Convert a doebian binary package name to a setuptools project name"""
+ py_package_name = _BIN_TO_PY.get(binary_package)
+ if py_package_name is not None:
+ return py_package_name
+ assert binary_package.startswith('python-')
+ return binary_package[7:]
+
+def src_to_py(source_package):
+ """Convert a debian source package name to a setuptools project name"""
+ return _SRC_TO_PY.get(source_package, source_package)
+
+#
+# Version Conversion
+#
+
+
+def py_version_to_deb(version):
+ """Converts an egg version to debian format to preserve sorting rules.
+
+ We try to convert egg versions to debian versions here in a way that
+ preserves sorting rules and takes into account egg ideosynchracies. We also
+ try to maintain readability of the version numbers and so do not aim for
+ perfection (It's highly doubtful we could attain it anyway).
+
+ For a simple and nasty example:
+
+ >>> py_version_to_deb('2.8.0')
+ '2.8.0'
+ >>> py_version_to_deb('2.8.0pre1')
+ '2.8.0~c~pre1'
+
+ """
+ version = version.lower()
+ result = []
+ for part in component_re.split(version):
+ if not part or part.isdigit() or part == '.' or part == '-':
+ result.append(part)
+ continue
+ result.append('~')
+ if part in ['pre', 'preview', 'rc']:
+ # ok. so because of the way setuptools does this, we can't manage to preserve the original
+ # version number and maintain sort order
+ result.append('c~')
+ if part == 'dev':
+ result.append('~')
+ result.append(part)
+ return ''.join(result)
+
+#
+# Dependency Conversion
+#
+
+_setuptools_debian_operators = {'>=': '>=',
+ '>': '>>',
+ '<': '<<',
+ '==': '=',
+ '!=': None, # != not supported by debian, use conflicts in future for this
+ '<=': '<='}
+
+def main(argv=sys.argv):
+ """Run the dependency calculation program.
+
+ >>> import os
+ >>> here = os.path.dirname(__file__)
+ >>> ex1 = os.path.join(here, 'tests', 'dummy.foo.egg-info')
+ >>> exitcode = main(['bin', 'depends', '--egg_info', ex1])
+ python-bar (<< 0.3~c~pre1), python-dummy, python-foo (>> 0.1), python-foobar
+ >>> exitcode
+ 0
+ """
+ parser = optparse.OptionParser(usage="usage: %prog command [options]")
+ parser.add_option("--egg_info", dest="egg_info",
+ help="The egg-info directory to use.")
+ parser.add_option("--exclude-extra", dest="exclude_extras", action="append",
+ help="Exclude extras from dependencies")
+ parser.add_option("--extra", dest="extras", action="append",
+ help="Generate dependency for extra[s]")
+ options, args = parser.parse_args(argv)
+ assert len(args) == 2, "One and only one command can be specified"
+ command = args[1]
+ assert os.path.exists(options.egg_info), "Does not exist: %s" % options.egg_info
+ if command == 'depends':
+ deps = _get_debian_dependencies(options.egg_info, extras=options.extras, exclude_extras=options.exclude_extras)
+ print ', '.join(sorted(deps))
+ elif command == 'provides':
+ deps = _get_debian_provides(options.egg_info, extras=options.extras, exclude_extras=options.exclude_extras)
+ print ', '.join(sorted(deps))
+ else:
+ raise Exception("Unknown command: %s" % command)
+ return 0
+
+def _get_debian_provides(file, extras=None, exclude_extras=None):
+ # get provides for extras
+ pydeps = set([])
+ base_dir = os.path.dirname(file)
+ metadata = PathMetadata(base_dir, file)
+ dist = Distribution.from_filename(file, metadata=metadata)
+ if exclude_extras is not None:
+ assert extras is None
+ extras = set(dist.extras) - set(exclude_extras)
+ if extras is None:
+ extras = set(dist.extras)
+ for i in extras:
+ pydeps.add('%s-%s' % (py_to_bin(dist.project_name), i))
+ return pydeps
+
+def _get_debian_dependencies(file, extras=None, exclude_extras=None):
+ """Returns a list of the format of the dpkg dependency info."""
+ pydeps = set([])
+ base_dir = os.path.dirname(file)
+ metadata = PathMetadata(base_dir, file)
+ dist = Distribution.from_filename(file, metadata=metadata)
+ included_extras = set(dist.extras)
+ if exclude_extras is not None:
+ included_extras = included_extras - set(exclude_extras)
+ if extras is not None:
+ assert exclude_extras is None
+ included_extras = extras
+ for req in dist.requires(extras=included_extras):
+ bin_pkg = py_to_bin(req.project_name)
+ pkgs = []
+ for extra in req.extras:
+ pkgs.append('%s-%s' % (bin_pkg, extra))
+ if not pkgs:
+ pkgs = [bin_pkg]
+ for pkg in pkgs:
+ if req.specs:
+ for spec in req.specs:
+ op, version = spec
+ op = _setuptools_debian_operators[op]
+ if op is None:
+ continue
+ dpkg_version = py_version_to_deb(version)
+ pydeps.add('%s (%s %s)' % (pkg, op, dpkg_version))
+ else:
+ pydeps.add(pkg)
+ # Let's depend on the namespace pacakges as well.
+ # this is a pretty ugly way to get __init__.py into the namespace packages
+ # which seems to be necessary.
+ # though testing it out on ubuntu gutsy said it wasnt, it was on Debian etch
+ #
+ # Perhaps we could remove this a bit later
+ namespace_pkgs = dist._get_metadata('namespace_packages.txt')
+ for pkg in namespace_pkgs:
+ bin_pkg = py_to_bin(pkg)
+ pydeps.add(bin_pkg)
+ if extras is not None:
+ # only give the dependencies of the metapackage
+ pydeps = pydeps - _get_debian_dependencies(file, exclude_extras=dist.extras)
+ return pydeps
Property changes on: van.pydeb/trunk/van/pydeb/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/py_to_bin.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/py_to_bin.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/py_to_bin.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,9 @@
+# Map eggs to debian binary packages
+
+pytz python-tz
+PIL python-imaging
+Reportlab python-reportlab
+BeautifulSoup python-beautifulsoup
+M2Crypto python-m2crypto
+SQLAlchemy python-sqlalchemy
+ZODB3 python-zodb
Property changes on: van.pydeb/trunk/van/pydeb/py_to_bin.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/py_to_src.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/py_to_src.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/py_to_src.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,8 @@
+# Map eggs to debian source packages
+BeautifulSoup beautifulsoup
+M2Crypto m2crypto
+SQLAlchemy sqlalchemy
+ZODB3 zodb
+PIL python-imaging
+Reportlab python-reportlab
+pytz python-tz
Property changes on: van.pydeb/trunk/van/pydeb/py_to_src.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/__init__.py
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/__init__.py (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/__init__.py 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+# import
Property changes on: van.pydeb/trunk/van/pydeb/tests/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/PKG-INFO
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/PKG-INFO (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/PKG-INFO 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: dummy.FOO2
+Version: 1.0
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/SOURCES.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/SOURCES.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/SOURCES.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,16 @@
+__init__.py
+apt.py
+egg_metadata.txt
+setup.ex1.py
+setup.ex2.py
+simple.dsc
+test_doctest.py
+dummy/__init__.py
+dummy.FOO2.egg-info/PKG-INFO
+dummy.FOO2.egg-info/SOURCES.txt
+dummy.FOO2.egg-info/dependency_links.txt
+dummy.FOO2.egg-info/namespace_packages.txt
+dummy.FOO2.egg-info/requires.txt
+dummy.FOO2.egg-info/top_level.txt
+dummy/FOO2/__init__.py
+test_eggs/z3c.breadcrumb-1.0.2.tar.gz
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/SOURCES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/dependency_links.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/dependency_links.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/dependency_links.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/dependency_links.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/namespace_packages.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/namespace_packages.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/namespace_packages.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+dummy
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/namespace_packages.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/requires.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/requires.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/requires.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,4 @@
+foo > 0.1
+foobar
+bar != 0.2
+bar < 0.3
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/requires.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/top_level.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/top_level.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/top_level.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+dummy
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.FOO2.egg-info/top_level.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/PKG-INFO
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/PKG-INFO (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/PKG-INFO 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: dummy.foo
+Version: 1.0
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/SOURCES.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/SOURCES.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/SOURCES.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,16 @@
+__init__.py
+apt.py
+egg_metadata.txt
+setup.ex1.py
+setup.ex2.py
+simple.dsc
+test_doctest.py
+dummy/__init__.py
+dummy.foo.egg-info/PKG-INFO
+dummy.foo.egg-info/SOURCES.txt
+dummy.foo.egg-info/dependency_links.txt
+dummy.foo.egg-info/namespace_packages.txt
+dummy.foo.egg-info/requires.txt
+dummy.foo.egg-info/top_level.txt
+dummy/foo/__init__.py
+test_eggs/z3c.breadcrumb-1.0.2.tar.gz
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/SOURCES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/dependency_links.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/dependency_links.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/dependency_links.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/dependency_links.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/namespace_packages.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/namespace_packages.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/namespace_packages.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+dummy
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/namespace_packages.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/requires.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/requires.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/requires.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,4 @@
+foo > 0.1
+foobar
+bar != 0.2
+bar < 0.3pre1
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/requires.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/top_level.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/top_level.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/top_level.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+dummy
Property changes on: van.pydeb/trunk/van/pydeb/tests/dummy.foo.egg-info/top_level.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/extras.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/extras.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/extras.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,76 @@
+Setuptools Extras Handling
+==========================
+
+Setup
+-----
+
+ >>> import os
+ >>> from van.pydeb import tests, main
+ >>> here = os.path.dirname(tests.__file__)
+ >>> zope_component = os.path.join(here, 'zope.component.egg-info')
+ >>> zope_security = os.path.join(here, 'zope.security.egg-info')
+ >>> zope_app_publication = os.path.join(here, 'zope.app.publication.egg-info')
+
+ >>> def runit(string):
+ ... main(['bin'] + string.split())
+
+The basic case: package depends directly on all extra dependencies
+------------------------------------------------------------------
+
+zope.component has a 'zcml' extra, we should check that by the the dependencies
+of this extra are shown in the depends and provides line:
+
+ >>> runit('depends --egg_info %s' % zope_component)
+ python-setuptools, python-z3c.recipe.sphinxdoc, python-zodb, python-zope, python-zope.configuration, python-zope.event, python-zope.hookable, python-zope.i18nmessageid, python-zope.interface, python-zope.location, python-zope.proxy, python-zope.security, python-zope.testing
+
+We can have create a provides line for all extras:
+
+ >>> runit('provides --egg_info %s' % zope_component)
+ python-zope.component-docs, python-zope.component-hook, python-zope.component-persistentregistry, python-zope.component-test, python-zope.component-zcml
+
+Moving an extra's dependencies into "Suggests:"
+-----------------------------------------------
+
+We notice that the "docs" dependency us not a hard one and decide to exclude it
+(it goes into Suggests:):
+
+ >>> runit('depends --egg_info %s --exclude-extra docs' % zope_component)
+ python-setuptools, python-zodb, python-zope, python-zope.configuration, python-zope.event, python-zope.hookable, python-zope.i18nmessageid, python-zope.interface, python-zope.location, python-zope.proxy, python-zope.security, python-zope.testing
+
+We could also exclude it from the "provides" list:
+
+ >>> runit('provides --egg_info %s --exclude-extra docs' % zope_component)
+ python-zope.component-hook, python-zope.component-persistentregistry, python-zope.component-test, python-zope.component-zcml
+
+Moving an extra into a metapackage
+----------------------------------
+
+Now we decide to move the 'zcml' extra to it's own metapackage, thus we need to separate out it's dependencies:
+
+ >>> runit('depends --egg_info %s --exclude-extra docs --exclude-extra zcml' % zope_component)
+ python-setuptools, python-zodb, python-zope, python-zope.event, python-zope.hookable, python-zope.interface, python-zope.location, python-zope.testing
+ >>> runit('depends --egg_info %s --extra zcml' % zope_component)
+ python-zope.configuration, python-zope.i18nmessageid, python-zope.proxy, python-zope.security
+
+We could also have the docs extra included in the metapackage if we wanted:
+
+ >>> runit('depends --egg_info %s --extra zcml --extra docs' % zope_component)
+ python-z3c.recipe.sphinxdoc, python-zope.configuration, python-zope.i18nmessageid, python-zope.proxy, python-zope.security
+
+And make a "Provides" list for that:
+
+ >>> runit('provides --egg_info %s --extra docs --extra zcml' % zope_component)
+ python-zope.component-docs, python-zope.component-zcml
+
+Packages that depend on extras
+------------------------------
+
+Depend on the provides list:
+
+ >>> runit('depends --egg_info %s' % zope_app_publication) # doctest: +ELLIPSIS
+ python-..., python-zope.component-zcml, ...
+
+But packages that don't, get the original dependency:
+
+ >>> runit('depends --egg_info %s' % zope_security) # doctest: +ELLIPSIS
+ python-..., python-zope.component, ...
Property changes on: van.pydeb/trunk/van/pydeb/tests/extras.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/test_doctest.py
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/test_doctest.py (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/test_doctest.py 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2008 Vanguardistas 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.
+#
+##############################################################################
+import unittest
+import doctest
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(doctest.DocTestSuite('van.pydeb'))
+ suite.addTest(doctest.DocFileSuite('translations.txt'))
+ suite.addTest(doctest.DocFileSuite('extras.txt'))
+ suite.addTest(doctest.DocFileSuite('version.txt'))
+ return suite
Property changes on: van.pydeb/trunk/van/pydeb/tests/test_doctest.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/translations.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/translations.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/translations.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,39 @@
+Test various builtin translations
+=================================
+
+
+ >>> from van import pydeb
+
+Paste
+-----
+
+ >>> print pydeb.py_to_bin("Paste")
+ python-paste
+ >>> print pydeb.py_to_bin("PasteDeploy")
+ python-pastedeploy
+ >>> print pydeb.py_to_bin("PasteScript")
+ python-pastescript
+
+ZODB3
+-----
+
+ >>> print pydeb.py_to_bin("ZODB3")
+ python-zodb
+ >>> print pydeb.py_to_src("ZODB3")
+ zodb
+ >>> print pydeb.bin_to_py("python-zodb")
+ ZODB3
+ >>> print pydeb.src_to_py("zodb")
+ ZODB3
+
+zope.interface
+--------------
+
+ >>> print pydeb.py_to_bin("zope.interface")
+ python-zope.interface
+ >>> print pydeb.py_to_src("zope.interface")
+ zope.interface
+ >>> print pydeb.bin_to_py("python-zope.interface")
+ zope.interface
+ >>> print pydeb.src_to_py("zope.interface")
+ zope.interface
Property changes on: van.pydeb/trunk/van/pydeb/tests/translations.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/version.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/version.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/version.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,82 @@
+Test conversion between setuptools and debian version numbers
+
+Setup a testing function:
+
+ >>> from van.pydeb import py_version_to_deb
+ >>> from pkg_resources import parse_version
+ >>> from subprocess import call
+
+ >>> def dpkg_is_gt(v1, v2):
+ ... return call(['dpkg', '--compare-versions', v1, '>>', v2]) == 0
+ >>> def test_gt(v1, v2):
+ ... st_gt = parse_version(v1) > parse_version(v2)
+ ... v1_c, v2_c = py_version_to_deb(v1), py_version_to_deb(v2)
+ ... dpkg_gt = dpkg_is_gt(v1_c, v2_c)
+ ... print "Dpkgized versions:", v1_c, v2_c
+ ... if st_gt == dpkg_gt:
+ ... if st_gt:
+ ... print "Greater Than"
+ ... else:
+ ... print "Not Greater Than"
+ ... else:
+ ... print "ERROR: setuptools and dpkg do not agree."
+
+These are the cases we want to fix:
+
+ >>> test_gt('2.8.0', '2.8.0dev1')
+ Dpkgized versions: 2.8.0 2.8.0~~dev1
+ Greater Than
+
+ >>> test_gt('2.8.0pre1', '2.8.0a1')
+ Dpkgized versions: 2.8.0~c~pre1 2.8.0~a1
+ Greater Than
+
+ >>> test_gt('2.8.0d1', '2.8.0pre1')
+ Dpkgized versions: 2.8.0~d1 2.8.0~c~pre1
+ Greater Than
+
+ >>> test_gt('2.8.0a1', '2.8.0dev1')
+ Dpkgized versions: 2.8.0~a1 2.8.0~~dev1
+ Greater Than
+
+ >>> test_gt('2.8.0-1', '2.8.0rc1')
+ Dpkgized versions: 2.8.0-1 2.8.0~c~rc1
+ Greater Than
+
+ >>> test_gt('2.8.1', '2.8.0-1')
+ Dpkgized versions: 2.8.1 2.8.0-1
+ Greater Than
+
+ >>> test_gt('2.8.0', '2.8.0a1')
+ Dpkgized versions: 2.8.0 2.8.0~a1
+ Greater Than
+
+ >>> test_gt('2.8.0', '2.8.0pre1')
+ Dpkgized versions: 2.8.0 2.8.0~c~pre1
+ Greater Than
+
+ >>> test_gt('2.8.0preview1', '2.8.0a1')
+ Dpkgized versions: 2.8.0~c~preview1 2.8.0~a1
+ Greater Than
+
+ >>> test_gt('2.8.0', '2.8.0rc1')
+ Dpkgized versions: 2.8.0 2.8.0~c~rc1
+ Greater Than
+
+ >>> test_gt('2.8.0', '2.8.0RC1')
+ Dpkgized versions: 2.8.0 2.8.0~c~rc1
+ Greater Than
+
+ >>> test_gt('2.8.0possible', '2.8.0rc1') # even duplicate the bugs...
+ Dpkgized versions: 2.8.0~possible 2.8.0~c~rc1
+ Greater Than
+
+ >>> test_gt('2.8.0rc1', '2.8.0RC1')
+ Dpkgized versions: 2.8.0~c~rc1 2.8.0~c~rc1
+ Not Greater Than
+
+ >>> test_gt('2.8.0cat', '2.8.0rc1')
+ Dpkgized versions: 2.8.0~cat 2.8.0~c~rc1
+ Greater Than
+
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/version.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/PKG-INFO
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/PKG-INFO (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/PKG-INFO 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,122 @@
+Metadata-Version: 1.0
+Name: zope.app.publication
+Version: 3.7.1dev
+Summary: Zope publication
+Home-page: http://pypi.python.org/pypi/zope.app.publication
+Author: Zope Corporation and Contributors
+Author-email: zope-dev at zope.org
+License: ZPL 2.1
+Description: Publication and traversal components.
+
+ =======
+ CHANGES
+ =======
+
+ 3.7.1 (unreleased)
+ ------------------
+
+ - ...
+
+ 3.7.0 (2009-05-23)
+ ------------------
+
+ - Moved the publicationtraverse module to zope.traversing, removing the
+ zope.app.publisher -> zope.app.publication dependency (which was a
+ cycle).
+
+ - Moved IHTTPException to zope.publisher, removing the dependency
+ on zope.app.http.
+
+ - Moved the DefaultViewName API from zope.app.publisher.browser to
+ zope.publisher.defaultview, making it accessible to other packages
+ that need it.
+
+ - Look up the application controller through a utility registration
+ rather than a direct reference.
+
+ 3.6.0 (2009-05-18)
+ ------------------
+
+ - Use ``zope:adapter`` ZCML directive instead of ``zope:view``.
+ This avoid dependency on ``zope.app.component``.
+
+ - Update imports from ``zope.app.security`` to ``zope.authentication`` and
+ ``zope.principalregistry``.
+
+ - Use ``zope.browser.interfaces.ISystemError`` to avoid dependency on
+ ``zope.app.exception``.
+
+ - Refactored tests so they can run successfully with ZODB 3.8 and 3.9.
+
+ 3.5.3 (2009-03-13)
+ ------------------
+
+ - Adapt to the removal of IXMLPresentation from zope.app.publisher which
+ was removed to adapt to removal of deprecated interfaces from zope.component.
+
+ 3.5.2 (2009-03-10)
+ ------------------
+
+ - Use ISkinnable.providedBy(request) instead of IBrowserRequest as condition
+ for calling setDefaultSkin. This at the same time removes dependency to
+ the browser part of zope.publisher.
+
+ - Remove deprecated code.
+
+ - Use built-in set class instead of the deprecated sets.Set and thus
+ don't cause deprecation warning in Python 2.6.
+
+ 3.5.1 (2009-01-31)
+ ------------------
+
+ - Import ISite from zope.location.interfaces instead of deprecated place
+ in zope.app.component.interfaces.
+
+ 3.5.0 (2008-10-09)
+ ------------------
+
+ - Now ``zope.app.publication.zopepublication.ZopePublication`` annotates the
+ request with the connection to the main ZODB when ``getApplication`` is
+ called.
+
+ - Removed support for non-existent Zope versions.
+
+
+ 3.4.3 (2007-11-01)
+ ------------------
+
+ - Removed unused imports.
+
+ - Resolve ``ZopeSecurityPolicy`` deprecation warning.
+
+
+ 3.4.2 (2007-09-26)
+ ------------------
+
+ - Added missing files to egg distribution.
+
+
+ 3.4.1 (2007-09-26)
+ ------------------
+
+ - Added missing files to egg distribution.
+
+
+ 3.4.0 (2007-09-25)
+ ------------------
+
+ - Initial documented release.
+
+ - Reflect changes form ``zope.app.error`` refactoring.
+
+Keywords: zope3 publication
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Zope Public License
+Classifier: Programming Language :: Python
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Framework :: Zope3
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/SOURCES.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/SOURCES.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/SOURCES.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,48 @@
+CHANGES.txt
+README.txt
+bootstrap.py
+buildout.cfg
+setup.py
+src/zope/__init__.py
+src/zope.app.publication.egg-info/PKG-INFO
+src/zope.app.publication.egg-info/SOURCES.txt
+src/zope.app.publication.egg-info/dependency_links.txt
+src/zope.app.publication.egg-info/namespace_packages.txt
+src/zope.app.publication.egg-info/not-zip-safe
+src/zope.app.publication.egg-info/requires.txt
+src/zope.app.publication.egg-info/top_level.txt
+src/zope/app/__init__.py
+src/zope/app/publication/__init__.py
+src/zope/app/publication/browser.py
+src/zope/app/publication/configure.zcml
+src/zope/app/publication/ftesting.zcml
+src/zope/app/publication/ftp.py
+src/zope/app/publication/http.py
+src/zope/app/publication/httpfactory.py
+src/zope/app/publication/httpfactory.txt
+src/zope/app/publication/interfaces.py
+src/zope/app/publication/meta.zcml
+src/zope/app/publication/metaconfigure.py
+src/zope/app/publication/metadirectives.py
+src/zope/app/publication/methodnotallowed.txt
+src/zope/app/publication/notfound.txt
+src/zope/app/publication/publicationtraverse.py
+src/zope/app/publication/requestpublicationfactories.py
+src/zope/app/publication/requestpublicationregistry.py
+src/zope/app/publication/soap.py
+src/zope/app/publication/testing.py
+src/zope/app/publication/traversers.py
+src/zope/app/publication/xmlrpc.py
+src/zope/app/publication/zopepublication.py
+src/zope/app/publication/tests/__init__.py
+src/zope/app/publication/tests/ftest_zcml_dependencies.zcml
+src/zope/app/publication/tests/test_browserpublication.py
+src/zope/app/publication/tests/test_dependencies.py
+src/zope/app/publication/tests/test_functional.py
+src/zope/app/publication/tests/test_http.py
+src/zope/app/publication/tests/test_httpfactory.py
+src/zope/app/publication/tests/test_requestpublicationfactories.py
+src/zope/app/publication/tests/test_requestpublicationregistry.py
+src/zope/app/publication/tests/test_simplecomponenttraverser.py
+src/zope/app/publication/tests/test_xmlrpcpublication.py
+src/zope/app/publication/tests/test_zopepublication.py
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/SOURCES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/dependency_links.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/dependency_links.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/dependency_links.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/dependency_links.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/namespace_packages.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/namespace_packages.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/namespace_packages.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,2 @@
+zope
+zope.app
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/namespace_packages.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/not-zip-safe
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/not-zip-safe (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/not-zip-safe 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/requires.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/requires.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/requires.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,21 @@
+zope.interface
+ZODB3
+zope.authentication
+zope.component [zcml]
+zope.deprecation
+zope.error
+zope.i18n
+zope.browser>=1.2
+zope.publisher>=3.8.0
+zope.traversing>=3.7.0
+setuptools
+
+[test]
+zope.app.testing
+zope.app.securitypolicy
+zope.app.zcmlfiles>=3.5.4
+zope.app.dav
+zope.app.publisher
+zope.app.zptpage
+zope.principalregistry
+zope.app.applicationcontrol>=3.5.0
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/requires.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/top_level.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/top_level.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/top_level.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+zope
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.app.publication.egg-info/top_level.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/PKG-INFO
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/PKG-INFO (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/PKG-INFO 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,2537 @@
+Metadata-Version: 1.0
+Name: zope.component
+Version: 3.7.1dev
+Summary: Zope Component Architecture
+Home-page: http://pypi.python.org/pypi/zope.component
+Author: Zope Corporation and Contributors
+Author-email: zope-dev at zope.org
+License: ZPL 2.1
+Description: *****************************
+ zope.component Package Readme
+ *****************************
+
+ *This package is intended to be independently reusable in any Python
+ project. It is maintained by the* `Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
+
+ This package represents the core of the Zope Component Architecture.
+ Together with the 'zope.interface' package, it provides facilities for
+ defining, registering and looking up components.
+
+ .. contents::
+
+ Detailed Documentation
+ **********************
+
+ Zope Component Architecture
+ ===========================
+
+ This package, together with `zope.interface`, provides facilities for
+ defining, registering and looking up components. There are two basic
+ kinds of components: adapters and utilities.
+
+ Utilities
+ ---------
+
+ Utilities are just components that provide an interface and that are
+ looked up by an interface and a name. Let's look at a trivial utility
+ definition:
+
+ >>> from zope import interface
+
+ >>> class IGreeter(interface.Interface):
+ ... def greet():
+ ... "say hello"
+
+ >>> class Greeter:
+ ... interface.implements(IGreeter)
+ ...
+ ... def __init__(self, other="world"):
+ ... self.other = other
+ ...
+ ... def greet(self):
+ ... print "Hello", self.other
+
+ We can register an instance this class using `provideUtility` [1]_:
+
+ >>> from zope import component
+ >>> greet = Greeter('bob')
+ >>> component.provideUtility(greet, IGreeter, 'robert')
+
+ In this example we registered the utility as providing the `IGreeter`
+ interface with a name of 'bob'. We can look the interface up with
+ either `queryUtility` or `getUtility`:
+
+ >>> component.queryUtility(IGreeter, 'robert').greet()
+ Hello bob
+
+ >>> component.getUtility(IGreeter, 'robert').greet()
+ Hello bob
+
+ `queryUtility` and `getUtility` differ in how failed lookups are handled:
+
+ >>> component.queryUtility(IGreeter, 'ted')
+ >>> component.queryUtility(IGreeter, 'ted', 42)
+ 42
+ >>> component.getUtility(IGreeter, 'ted')
+ ... # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass ...IGreeter>, 'ted')
+
+ If a component provides only one interface, as in the example above,
+ then we can omit the provided interface from the call to `provideUtility`:
+
+ >>> ted = Greeter('ted')
+ >>> component.provideUtility(ted, name='ted')
+ >>> component.queryUtility(IGreeter, 'ted').greet()
+ Hello ted
+
+ The name defaults to an empty string:
+
+ >>> world = Greeter()
+ >>> component.provideUtility(world)
+ >>> component.queryUtility(IGreeter).greet()
+ Hello world
+
+ Adapters
+ --------
+
+ Adapters are components that are computed from other components to
+ adapt them to some interface. Because they are computed from other
+ objects, they are provided as factories, usually classes. Here, we'll
+ create a greeter for persons, so we can provide personalized greetings
+ for different people:
+
+ >>> class IPerson(interface.Interface):
+ ... name = interface.Attribute("Name")
+
+ >>> class PersonGreeter:
+ ...
+ ... component.adapts(IPerson)
+ ... interface.implements(IGreeter)
+ ...
+ ... def __init__(self, person):
+ ... self.person = person
+ ...
+ ... def greet(self):
+ ... print "Hello", self.person.name
+
+ The class defines a constructor that takes an argument for every
+ object adapted.
+
+ We used `component.adapts` to declare what we adapt. We can find
+ out if an object declares that it adapts anything using adaptedBy:
+
+ >>> list(component.adaptedBy(PersonGreeter)) == [IPerson]
+ True
+
+ If an object makes no declaration, then None is returned:
+
+ >>> component.adaptedBy(Greeter()) is None
+ True
+
+
+ If we declare the interfaces adapted and if we provide only one
+ interface, as in the example above, then we can provide the adapter
+ very simply [1]_:
+
+ >>> component.provideAdapter(PersonGreeter)
+
+ For adapters that adapt a single interface to a single interface
+ without a name, we can get the adapter by simply calling the
+ interface:
+
+ >>> class Person:
+ ... interface.implements(IPerson)
+ ...
+ ... def __init__(self, name):
+ ... self.name = name
+
+ >>> IGreeter(Person("Sally")).greet()
+ Hello Sally
+
+ We can also provide arguments to be very specific about what
+ how to register the adapter.
+
+ >>> class BobPersonGreeter(PersonGreeter):
+ ... name = 'Bob'
+ ... def greet(self):
+ ... print "Hello", self.person.name, "my name is", self.name
+
+ >>> component.provideAdapter(
+ ... BobPersonGreeter, [IPerson], IGreeter, 'bob')
+
+ The arguments can also be provided as keyword arguments:
+
+ >>> class TedPersonGreeter(BobPersonGreeter):
+ ... name = "Ted"
+
+ >>> component.provideAdapter(
+ ... factory=TedPersonGreeter, adapts=[IPerson],
+ ... provides=IGreeter, name='ted')
+
+ For named adapters, use `queryAdapter`, or `getAdapter`:
+
+ >>> component.queryAdapter(Person("Sally"), IGreeter, 'bob').greet()
+ Hello Sally my name is Bob
+
+ >>> component.getAdapter(Person("Sally"), IGreeter, 'ted').greet()
+ Hello Sally my name is Ted
+
+ If an adapter can't be found, `queryAdapter` returns a default value
+ and `getAdapter` raises an error:
+
+ >>> component.queryAdapter(Person("Sally"), IGreeter, 'frank')
+ >>> component.queryAdapter(Person("Sally"), IGreeter, 'frank', 42)
+ 42
+ >>> component.getAdapter(Person("Sally"), IGreeter, 'frank')
+ ... # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (...Person...>, <...IGreeter>, 'frank')
+
+ Adapters can adapt multiple objects:
+
+ >>> class TwoPersonGreeter:
+ ...
+ ... component.adapts(IPerson, IPerson)
+ ... interface.implements(IGreeter)
+ ...
+ ... def __init__(self, person, greeter):
+ ... self.person = person
+ ... self.greeter = greeter
+ ...
+ ... def greet(self):
+ ... print "Hello", self.person.name
+ ... print "my name is", self.greeter.name
+
+ >>> component.provideAdapter(TwoPersonGreeter)
+
+ To look up a multi-adapter, use either `queryMultiAdapter` or
+ `getMultiAdapter`:
+
+ >>> component.queryMultiAdapter((Person("Sally"), Person("Bob")),
+ ... IGreeter).greet()
+ Hello Sally
+ my name is Bob
+
+ Adapters need not be classes. Any callable will do. We use the
+ adapter decorator (in the Python 2.4 decorator sense) to declare that
+ a callable object adapts some interfaces (or classes):
+
+ >>> class IJob(interface.Interface):
+ ... "A job"
+
+ >>> class Job:
+ ... interface.implements(IJob)
+
+ >>> def personJob(person):
+ ... return getattr(person, 'job', None)
+ >>> personJob = interface.implementer(IJob)(personJob)
+ >>> personJob = component.adapter(IPerson)(personJob)
+
+ In Python 2.4, the example can be written:
+
+ >>> @interface.implementer(IJob)
+ ... @component.adapter(IPerson)
+ ... def personJob(person):
+ ... return getattr(person, 'job', None)
+
+ which looks a bit nicer.
+
+ In this example, the personJob function simply returns the person's
+ `job` attribute if present, or None if it's not present. An adapter
+ factory can return None to indicate that adaptation wasn't possible.
+ Let's register this adapter and try it out:
+
+ >>> component.provideAdapter(personJob)
+ >>> sally = Person("Sally")
+ >>> IJob(sally) # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', ...
+
+ The adaptation failed because sally didn't have a job. Let's give her
+ one:
+
+ >>> job = Job()
+ >>> sally.job = job
+ >>> IJob(sally) is job
+ True
+
+ Subscription Adapters
+ ---------------------
+
+ Unlike regular adapters, subscription adapters are used when we want
+ all of the adapters that adapt an object to a particular adapter.
+
+ Consider a validation problem. We have objects and we want to assess
+ whether they meet some sort of standards. We define a validation
+ interface:
+
+ >>> class IValidate(interface.Interface):
+ ... def validate(ob):
+ ... """Determine whether the object is valid
+ ...
+ ... Return a string describing a validation problem.
+ ... An empty string is returned to indicate that the
+ ... object is valid.
+ ... """
+
+ Perhaps we have documents:
+
+ >>> class IDocument(interface.Interface):
+ ... summary = interface.Attribute("Document summary")
+ ... body = interface.Attribute("Document text")
+
+ >>> class Document:
+ ... interface.implements(IDocument)
+ ... def __init__(self, summary, body):
+ ... self.summary, self.body = summary, body
+
+ Now, we may want to specify various validation rules for
+ documents. For example, we might require that the summary be a single
+ line:
+
+ >>> class SingleLineSummary:
+ ... component.adapts(IDocument)
+ ... interface.implements(IValidate)
+ ...
+ ... def __init__(self, doc):
+ ... self.doc = doc
+ ...
+ ... def validate(self):
+ ... if '\n' in self.doc.summary:
+ ... return 'Summary should only have one line'
+ ... else:
+ ... return ''
+
+ Or we might require the body to be at least 1000 characters in length:
+
+ >>> class AdequateLength:
+ ... component.adapts(IDocument)
+ ... interface.implements(IValidate)
+ ...
+ ... def __init__(self, doc):
+ ... self.doc = doc
+ ...
+ ... def validate(self):
+ ... if len(self.doc.body) < 1000:
+ ... return 'too short'
+ ... else:
+ ... return ''
+
+ We can register these as subscription adapters [1]_:
+
+ >>> component.provideSubscriptionAdapter(SingleLineSummary)
+ >>> component.provideSubscriptionAdapter(AdequateLength)
+
+ We can then use the subscribers to validate objects:
+
+ >>> doc = Document("A\nDocument", "blah")
+ >>> [adapter.validate()
+ ... for adapter in component.subscribers([doc], IValidate)
+ ... if adapter.validate()]
+ ['Summary should only have one line', 'too short']
+
+ >>> doc = Document("A\nDocument", "blah" * 1000)
+ >>> [adapter.validate()
+ ... for adapter in component.subscribers([doc], IValidate)
+ ... if adapter.validate()]
+ ['Summary should only have one line']
+
+ >>> doc = Document("A Document", "blah")
+ >>> [adapter.validate()
+ ... for adapter in component.subscribers([doc], IValidate)
+ ... if adapter.validate()]
+ ['too short']
+
+ Handlers
+ --------
+
+ Handlers are subscription adapter factories that don't produce
+ anything. They do all of their work when called. Handlers
+ are typically used to handle events.
+
+ Event subscribers are different from other subscription adapters in
+ that the caller of event subscribers doesn't expect to interact with
+ them in any direct way. For example, an event publisher doesn't
+ expect to get any return value. Because subscribers don't need to
+ provide an API to their callers, it is more natural to define them
+ with functions, rather than classes. For example, in a
+ document-management system, we might want to record creation times for
+ documents:
+
+ >>> import datetime
+
+ >>> def documentCreated(event):
+ ... event.doc.created = datetime.datetime.utcnow()
+
+ In this example, we have a function that takes an event and performs
+ some processing. It doesn't actually return anything. This is a
+ special case of a subscription adapter that adapts an event to
+ nothing. All of the work is done when the adapter "factory" is
+ called. We call subscribers that don't actually create anything
+ "handlers". There are special APIs for registering and calling
+ them.
+
+ To register the subscriber above, we define a document-created event:
+
+ >>> class IDocumentCreated(interface.Interface):
+ ... doc = interface.Attribute("The document that was created")
+
+ >>> class DocumentCreated:
+ ... interface.implements(IDocumentCreated)
+ ...
+ ... def __init__(self, doc):
+ ... self.doc = doc
+
+ We'll also change our handler definition to:
+
+ >>> def documentCreated(event):
+ ... event.doc.created = datetime.datetime.utcnow()
+
+ >>> documentCreated = component.adapter(IDocumentCreated)(documentCreated)
+
+ Note that in Python 2.4, this can be written:
+
+ >>> @component.adapter(IDocumentCreated)
+ ... def documentCreated(event):
+ ... event.doc.created = datetime.datetime.utcnow()
+
+ This marks the handler as an adapter of `IDocumentCreated` events.
+
+ Now we'll register the handler [1]_:
+
+ >>> component.provideHandler(documentCreated)
+
+ Now, if we can create an event and use the `handle` function to call
+ handlers registered for the event:
+
+ >>> component.handle(DocumentCreated(doc))
+ >>> doc.created.__class__.__name__
+ 'datetime'
+
+
+
+ .. [1] CAUTION: This API should only be used from test or
+ application-setup code. This API shouldn't be used by regular
+ library modules, as component registration is a configuration
+ activity.
+
+ Events
+ ======
+
+ The Component Architecture provides a way to dispatch events to event
+ handlers. Event handlers are registered as *subscribers*
+ a.k.a. *handlers*.
+
+ Before we can start we need to import ``zope.component.event`` to make
+ the dispatching effective:
+
+ >>> import zope.component.event
+
+ Consider two event classes:
+
+ >>> class Event1(object):
+ ... pass
+
+ >>> class Event2(Event1):
+ ... pass
+
+ Now consider two handlers for these event classes:
+
+ >>> called = []
+
+ >>> import zope.component
+ >>> @zope.component.adapter(Event1)
+ ... def handler1(event):
+ ... called.append(1)
+
+ >>> @zope.component.adapter(Event2)
+ ... def handler2(event):
+ ... called.append(2)
+
+ We can register them with the Component Architecture:
+
+ >>> zope.component.provideHandler(handler1)
+ >>> zope.component.provideHandler(handler2)
+
+ Now let's go through the events. We'll see that the handlers have been
+ called accordingly:
+
+ >>> from zope.event import notify
+ >>> notify(Event1())
+ >>> called
+ [1]
+
+ >>> del called[:]
+ >>> notify(Event2())
+ >>> called.sort()
+ >>> called
+ [1, 2]
+
+
+
+ Object events
+ -------------
+
+
+ The ``objectEventNotify`` function is a subscriber to dispatch
+ ObjectEvents to interested adapters.
+
+ First create an object class:
+
+ >>> class IUseless(zope.interface.Interface):
+ ... """Useless object"""
+
+ >>> class UselessObject(object):
+ ... """Useless object"""
+ ... zope.interface.implements(IUseless)
+
+ Then create an event class:
+
+ >>> class IObjectThrownEvent(zope.component.interfaces.IObjectEvent):
+ ... """An object has been thrown away"""
+
+ >>> class ObjectThrownEvent(zope.component.interfaces.ObjectEvent):
+ ... """An object has been thrown away"""
+ ... zope.interface.implements(IObjectThrownEvent)
+
+ Create an object and an event:
+
+ >>> hammer = UselessObject()
+ >>> event = ObjectThrownEvent(hammer)
+
+ Then notify the event to the subscribers.
+ Since the subscribers list is empty, nothing happens.
+
+ >>> zope.component.event.objectEventNotify(event)
+
+ Now create an handler for the event:
+
+ >>> events = []
+ >>> def record(*args):
+ ... events.append(args)
+
+ >>> zope.component.provideHandler(record, [IUseless, IObjectThrownEvent])
+
+ The event is notified to the subscriber:
+
+ >>> zope.component.event.objectEventNotify(event)
+ >>> events == [(hammer, event)]
+ True
+
+ Following test demonstrates how a subscriber can raise an exception
+ to prevent an action.
+
+ >>> zope.component.provideHandler(zope.component.event.objectEventNotify)
+
+ Let's create a container:
+
+ >>> class ToolBox(dict):
+ ... def __delitem__(self, key):
+ ... notify(ObjectThrownEvent(self[key]))
+ ... return super(ToolBox,self).__delitem__(key)
+
+ >>> container = ToolBox()
+
+ And put the object into the container:
+
+ >>> container['Red Hammer'] = hammer
+
+ Create an handler function that will raise an error when called:
+
+ >>> class Veto(Exception):
+ ... pass
+
+ >>> def callback(item, event):
+ ... assert(item == event.object)
+ ... raise Veto
+
+ Register the handler:
+
+ >>> zope.component.provideHandler(callback, [IUseless, IObjectThrownEvent])
+
+ Then if we try to remove the object, an ObjectThrownEvent is fired:
+
+ >>> del container['Red Hammer']
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ raise Veto
+ Veto
+
+ Factories
+ =========
+
+
+ The Factory Class
+ -----------------
+
+ >>> from zope.interface import Interface
+ >>> class IFunction(Interface):
+ ... pass
+
+ >>> class IKlass(Interface):
+ ... pass
+
+ >>> from zope.interface import implements
+ >>> class Klass(object):
+ ... implements(IKlass)
+ ...
+ ... def __init__(self, *args, **kw):
+ ... self.args = args
+ ... self.kw = kw
+
+ >>> from zope.component.factory import Factory
+ >>> factory = Factory(Klass, 'Klass', 'Klassier')
+ >>> factory2 = Factory(lambda x: x, 'Func', 'Function')
+ >>> factory3 = Factory(lambda x: x, 'Func', 'Function', (IFunction,))
+
+ Calling a Factory
+ ~~~~~~~~~~~~~~~~~
+
+ Here we test whether the factory correctly creates the objects and
+ including the correct handling of constructor elements.
+
+ First we create a factory that creates instanace of the `Klass` class:
+
+ >>> factory = Factory(Klass, 'Klass', 'Klassier')
+
+ Now we use the factory to create the instance
+
+ >>> kl = factory(1, 2, foo=3, bar=4)
+
+ and make sure that the correct class was used to create the object:
+
+ >>> kl.__class__
+ <class 'Klass'>
+
+ Since we passed in a couple positional and keyword arguments
+
+ >>> kl.args
+ (1, 2)
+ >>> kl.kw
+ {'foo': 3, 'bar': 4}
+
+ >>> factory2(3)
+ 3
+ >>> factory3(3)
+ 3
+
+
+ Title and Description
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ >>> factory.title
+ 'Klass'
+ >>> factory.description
+ 'Klassier'
+ >>> factory2.title
+ 'Func'
+ >>> factory2.description
+ 'Function'
+ >>> factory3.title
+ 'Func'
+ >>> factory3.description
+ 'Function'
+
+
+ Provided Interfaces
+ ~~~~~~~~~~~~~~~~~~~
+
+ >>> implemented = factory.getInterfaces()
+ >>> implemented.isOrExtends(IKlass)
+ True
+ >>> list(implemented)
+ [<InterfaceClass __builtin__.IKlass>]
+
+ >>> implemented2 = factory2.getInterfaces()
+ >>> list(implemented2)
+ []
+
+ >>> implemented3 = factory3.getInterfaces()
+ >>> list(implemented3)
+ [<InterfaceClass __builtin__.IFunction>]
+
+
+ The Component Architecture Factory API
+ --------------------------------------
+
+ >>> import zope.component
+ >>> factory = Factory(Klass, 'Klass', 'Klassier')
+ >>> gsm = zope.component.getGlobalSiteManager()
+
+ >>> from zope.component.interfaces import IFactory
+ >>> gsm.registerUtility(factory, IFactory, 'klass')
+
+ Creating an Object
+ ~~~~~~~~~~~~~~~~~~
+
+ >>> kl = zope.component.createObject('klass', 1, 2, foo=3, bar=4)
+ >>> isinstance(kl, Klass)
+ True
+ >>> kl.args
+ (1, 2)
+ >>> kl.kw
+ {'foo': 3, 'bar': 4}
+
+ Accessing Provided Interfaces
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ >>> implemented = zope.component.getFactoryInterfaces('klass')
+ >>> implemented.isOrExtends(IKlass)
+ True
+ >>> [iface for iface in implemented]
+ [<InterfaceClass __builtin__.IKlass>]
+
+ List of All Factories
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ >>> [(name, fac.__class__) for name, fac in
+ ... zope.component.getFactoriesFor(IKlass)]
+ [(u'klass', <class 'zope.component.factory.Factory'>)]
+
+
+ Component-Management objects
+ ============================
+
+ Component-management objects provide a higher-level
+ component-management API over the basic adapter-registration API
+ provided by the zope.interface package. In particular, it provides:
+
+ - utilities
+
+ - support for computing adapters, rather than just looking up adapter
+ factories.
+
+ - management of registration comments
+
+ The zope.component.registry.Components class provides an
+ implementation of zope.component.interfaces.IComponents that provides
+ these features.
+
+ >>> from zope.component import registry
+ >>> from zope.component import tests
+ >>> components = registry.Components('comps')
+
+ As components are registered, events are generated. Let's register
+ an event subscriber, so we can see the events generated:
+
+ >>> import zope.event
+ >>> def logevent(event):
+ ... print event
+ >>> zope.event.subscribers.append(logevent)
+
+ Utilities
+ ---------
+
+ You can register Utilities using registerUtility:
+
+ >>> components.registerUtility(tests.U1(1))
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 1, None, u'')
+
+ Here we didn't specify an interface or name. An unnamed utility was
+ registered for interface I1, since that is only interface implemented
+ by the U1 class:
+
+ >>> components.getUtility(tests.I1)
+ U1(1)
+
+ You can also register a utility using a factory instead of a utility instance:
+
+ >>> def factory():
+ ... return tests.U1(1)
+ >>> components.registerUtility(factory=factory)
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 1, <function factory at <SOME ADDRESS>>, u'')
+
+
+ If a component implements other than one interface or no interface,
+ then an error will be raised:
+
+ >>> components.registerUtility(tests.U12(2))
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The utility doesn't provide a single interface and
+ no provided interface was specified.
+
+ >>> components.registerUtility(tests.A)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The utility doesn't provide a single interface and
+ no provided interface was specified.
+
+
+ We can provide an interface if desired:
+
+ >>> components.registerUtility(tests.U12(2), tests.I2)
+ Registered event:
+ UtilityRegistration(<Components comps>, I2, u'', 2, None, u'')
+
+ and we can specify a name:
+
+ >>> components.registerUtility(tests.U12(3), tests.I2, u'three')
+ Registered event:
+ UtilityRegistration(<Components comps>, I2, u'three', 3, None, u'')
+
+ >>> components.getUtility(tests.I2)
+ U12(2)
+
+ >>> components.getUtility(tests.I2, 'three')
+ U12(3)
+
+ If you try to get a utility that doesn't exist, you'll get a component
+ lookup error:
+
+ >>> components.getUtility(tests.I3)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError:
+ (<InterfaceClass zope.component.tests.I3>, u'')
+
+ Unless you use queryUtility:
+
+ >>> components.queryUtility(tests.I3)
+ >>> components.queryUtility(tests.I3, default=42)
+ 42
+
+ You can get information about registered utilities with the
+ registeredUtilities method:
+
+ >>> for registration in sorted(components.registeredUtilities()):
+ ... print registration.provided, registration.name
+ ... print registration.component, registration.info
+ <InterfaceClass zope.component.tests.I1>
+ U1(1)
+ <InterfaceClass zope.component.tests.I2>
+ U12(2)
+ <InterfaceClass zope.component.tests.I2> three
+ U12(3)
+
+ Duplicate registrations replace existing ones:
+
+ >>> components.registerUtility(tests.U1(4), info=u'use 4 now')
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 4, None, u'use 4 now')
+ >>> components.getUtility(tests.I1)
+ U1(4)
+
+ >>> for registration in sorted(components.registeredUtilities()):
+ ... print registration.provided, registration.name
+ ... print registration.component, registration.info
+ <InterfaceClass zope.component.tests.I1>
+ U1(4) use 4 now
+ <InterfaceClass zope.component.tests.I2>
+ U12(2)
+ <InterfaceClass zope.component.tests.I2> three
+ U12(3)
+
+ As shown in the this example, you can provide an "info" argumemnt when
+ registering utilities. This provides extra documentation about the
+ registration itself that is shown when listing registrations.
+
+ You can also unregister utilities:
+
+ >>> components.unregisterUtility(provided=tests.I1)
+ Unregistered event:
+ UtilityRegistration(<Components comps>, I1, u'', 4, None, u'use 4 now')
+ True
+
+ A boolean is returned indicating whether anything changed:
+
+ >>> components.queryUtility(tests.I1)
+ >>> for registration in sorted(components.registeredUtilities()):
+ ... print registration.provided, registration.name
+ ... print registration.component, registration.info
+ <InterfaceClass zope.component.tests.I2>
+ U12(2)
+ <InterfaceClass zope.component.tests.I2> three
+ U12(3)
+
+ When you unregister, you can specify a component. If the component
+ doesn't match the one registered, then nothing happens:
+
+ >>> u5 = tests.U1(5)
+ >>> components.registerUtility(u5)
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+ >>> components.unregisterUtility(tests.U1(6))
+ False
+ >>> components.queryUtility(tests.I1)
+ U1(5)
+ >>> components.unregisterUtility(u5)
+ Unregistered event:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+ True
+ >>> components.queryUtility(tests.I1)
+
+ You can get the name and utility for all of the utilities that provide
+ an interface using getUtilitiesFor:
+
+ >>> sorted(components.getUtilitiesFor(tests.I2))
+ [(u'', U12(2)), (u'three', U12(3))]
+
+ getAllUtilitiesRegisteredFor is similar to getUtilitiesFor except that
+ it includes utilities that are overridden. For example, we'll
+ register a utility that for an extending interface of I2:
+
+ >>> util = tests.U('ext')
+ >>> components.registerUtility(util, tests.I2e)
+ Registered event:
+ UtilityRegistration(<Components comps>, I2e, u'', ext, None, u'')
+
+ We don't get the new utility for getUtilitiesFor:
+
+ >>> sorted(components.getUtilitiesFor(tests.I2))
+ [(u'', U12(2)), (u'three', U12(3))]
+
+ but we do get it from getAllUtilitiesRegisteredFor:
+
+ >>> sorted(map(str, components.getAllUtilitiesRegisteredFor(tests.I2)))
+ ['U(ext)', 'U12(2)', 'U12(3)']
+
+ Removing a utility also makes it disappear from getUtilitiesFor:
+
+ >>> components.unregisterUtility(util, tests.I2e)
+ Unregistered event:
+ UtilityRegistration(<Components comps>, I2e, u'', ext, None, u'')
+ True
+ >>> list(components.getAllUtilitiesRegisteredFor(tests.I2e))
+ []
+
+ Adapters
+ --------
+
+ You can register adapters with registerAdapter:
+
+ >>> components.registerAdapter(tests.A12_1)
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+
+ Here, we didn't specify required interfaces, a provided interface, or
+ a name. The required interfaces were determined from the factory
+ s __component_adapts__ attribute and the provided interface was
+ determined by introspecting what the factory implements.
+
+ >>> components.getMultiAdapter((tests.U1(6), tests.U12(7)), tests.IA1)
+ A12_1(U1(6), U12(7))
+
+ If a factory implements more than one interface, an exception will be
+ raised:
+
+ >>> components.registerAdapter(tests.A1_12)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ Unless the provided interface is specified:
+
+ >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+
+ If a factory doesn't declare an implemented interface, an exception will be
+ raised:
+
+ >>> components.registerAdapter(tests.A12_)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ Unless the provided interface is specified:
+
+ >>> components.registerAdapter(tests.A12_, provided=tests.IA2)
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA2, u'', A12_, u'')
+
+ The required interface needs to be specified in the registration if
+ the factory doesn't have a __component_adapts__ attribute:
+
+ >>> components.registerAdapter(tests.A_2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't have a __component_adapts__
+ attribute and no required specifications were specified
+
+ Unless the required specifications specified:
+
+ >>> components.registerAdapter(tests.A_2, required=[tests.I3])
+ Registered event:
+ AdapterRegistration(<Components comps>, [I3], IA2, u'', A_2, u'')
+
+ Classes can be specified in place of specifications, in which case the
+ implementedBy specification for the class is used:
+
+ >>> components.registerAdapter(tests.A_3, required=[tests.U],
+ ... info="Really class specific")
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ AdapterRegistration(<Components comps>, [zope.component.tests.U], IA3, u'',
+ A_3, 'Really class specific')
+
+ We can see the adapters that have been registered using the
+ registeredAdapters method:
+
+ >>> for registration in sorted(components.registeredAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<InterfaceClass zope.component.tests.I1>,
+ <InterfaceClass zope.component.tests.I2>)
+ <InterfaceClass zope.component.tests.IA1>
+ zope.component.tests.A12_1
+ (<InterfaceClass zope.component.tests.I1>,
+ <InterfaceClass zope.component.tests.I2>)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A12_
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_12
+ (<InterfaceClass zope.component.tests.I3>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A_2
+ (<implementedBy zope.component.tests.U>,)
+ <InterfaceClass zope.component.tests.IA3>
+ zope.component.tests.A_3 Really class specific
+
+ As with utilities, we can provide registration information when
+ registering adapters.
+
+ If you try to fetch an adapter that isn't registered, you'll get a
+ component-lookup error:
+
+ >>> components.getMultiAdapter((tests.U(8), ), tests.IA1)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: ((U(8),),
+ <InterfaceClass zope.component.tests.IA1>, u'')
+
+ unless you use queryAdapter:
+
+ >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1)
+ >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1, default=42)
+ 42
+
+ When looking up an adapter for a single object, you can use the
+ slightly simpler getAdapter and queryAdapter calls:
+
+ >>> components.getAdapter(tests.U1(9), tests.IA2)
+ A1_12(U1(9))
+
+ >>> components.queryAdapter(tests.U1(9), tests.IA2)
+ A1_12(U1(9))
+
+ >>> components.getAdapter(tests.U(8), tests.IA1)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (U(8),
+ <InterfaceClass zope.component.tests.IA1>, u'')
+
+ >>> components.queryAdapter(tests.U(8), tests.IA2)
+ >>> components.queryAdapter(tests.U(8), tests.IA2, default=42)
+ 42
+
+ You can unregister an adapter. If a factory is provided and if the
+ rewuired and provided interfaces, can be infered, then they need not
+ be provided:
+
+ >>> components.unregisterAdapter(tests.A12_1)
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+ True
+
+ >>> for registration in sorted(components.registeredAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<InterfaceClass zope.component.tests.I1>,
+ <InterfaceClass zope.component.tests.I2>)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A12_
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_12
+ (<InterfaceClass zope.component.tests.I3>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A_2
+ (<implementedBy zope.component.tests.U>,)
+ <InterfaceClass zope.component.tests.IA3>
+ zope.component.tests.A_3 Really class specific
+
+ A boolean is returned indicating whether a change was made.
+
+ If a factory implements more than one interface, an exception will be
+ raised:
+
+ >>> components.unregisterAdapter(tests.A1_12)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ Unless the provided interface is specified:
+
+ >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+ True
+
+ If a factory doesn't declare an implemented interface, an exception will be
+ raised:
+
+ >>> components.unregisterAdapter(tests.A12_)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ Unless the provided interface is specified:
+
+ >>> components.unregisterAdapter(tests.A12_, provided=tests.IA2)
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA2, u'', A12_, u'')
+ True
+
+ The required interface needs to be specified if the factory doesn't
+ have a __component_adapts__ attribute:
+
+ >>> components.unregisterAdapter(tests.A_2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't have a __component_adapts__
+ attribute and no required specifications were specified
+
+ >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I3], IA2, u'', A_2, u'')
+ True
+
+ >>> for registration in sorted(components.registeredAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<implementedBy zope.component.tests.U>,)
+ <InterfaceClass zope.component.tests.IA3>
+ zope.component.tests.A_3 Really class specific
+
+ If a factory is unregistered that is not registered, False is
+ returned:
+
+
+ >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
+ False
+ >>> components.unregisterAdapter(tests.A12_1, required=[tests.U])
+ False
+
+ The factory can be omitted, to unregister *any* factory that matches
+ specified required and provided interfaces:
+
+ >>> components.unregisterAdapter(required=[tests.U], provided=tests.IA3)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [zope.component.tests.U],
+ IA3, u'', A_3, 'Really class specific')
+ True
+
+ >>> for registration in sorted(components.registeredAdapters()):
+ ... print registration
+
+ Adapters can be named:
+
+ >>> components.registerAdapter(tests.A1_12, provided=tests.IA2,
+ ... name=u'test')
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'test', A1_12, u'')
+
+ >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2)
+ >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2, name=u'test')
+ A1_12(U1(9))
+
+ >>> components.queryAdapter(tests.U1(9), tests.IA2)
+ >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test')
+ A1_12(U1(9))
+ >>> components.getAdapter(tests.U1(9), tests.IA2, name=u'test')
+ A1_12(U1(9))
+
+ It is possible to look up all of the adapters that provide an
+ interface:
+
+ >>> components.registerAdapter(tests.A1_23, provided=tests.IA2,
+ ... name=u'test 2')
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'test 2', A1_23, u'')
+
+ >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+
+ >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ),
+ ... tests.IA2)):
+ ... print name, adapter
+ A1_12(U1(9))
+ test A1_12(U1(9))
+ test 2 A1_23(U1(9))
+
+
+ getAdapters is most commonly used as the basis of menu systems.
+
+ If an adapter factory returns None, it is equivalent to there being no
+ factory:
+
+ >>> components.registerAdapter(tests.noop,
+ ... required=[tests.IA1], provided=tests.IA2,
+ ... name=u'test noop')
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ AdapterRegistration(<Components comps>, [IA1], IA2, u'test noop',
+ noop, u'')
+ >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test noop')
+
+ >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+
+ >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ),
+ ... tests.IA2)):
+ ... print name, adapter
+ A1_12(U1(9))
+ test A1_12(U1(9))
+ test 2 A1_23(U1(9))
+
+
+ >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2,
+ ... name=u'test')
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'test', A1_12, u'')
+ True
+ >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
+ Unregistered event:
+ AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+ True
+ >>> for registration in sorted(components.registeredAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2> test 2
+ zope.component.tests.A1_23
+ (<InterfaceClass zope.component.tests.IA1>,)
+ <InterfaceClass zope.component.tests.IA2> test noop
+ <function noop at 0xb79a1064>
+
+
+ Subscribers
+ -----------
+
+ Subscribers provide a way to get multiple adapters of a given type.
+ In this regard, subscribers are like named adapters, except that there
+ isn't any concept of the most specific adapter for a given name.
+
+ Subscribers are registered by calling registerSubscriptionAdapter:
+
+ >>> components.registerSubscriptionAdapter(tests.A1_2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
+
+ >>> components.registerSubscriptionAdapter(
+ ... tests.A1_12, provided=tests.IA2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
+
+ >>> components.registerSubscriptionAdapter(
+ ... tests.A, [tests.I1], tests.IA2,
+ ... info='a sample comment')
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'',
+ A, 'a sample comment')
+
+ The same rules, with regard to when required and provided interfaces
+ have to be specified apply as with adapters:
+
+ >>> components.registerSubscriptionAdapter(tests.A1_12)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ >>> components.registerSubscriptionAdapter(tests.A)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single interface and
+ no provided interface was specified.
+
+ >>> components.registerSubscriptionAdapter(tests.A, required=[tests.IA1])
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single interface
+ and no provided interface was specified.
+
+ Note that we provided the info argument as a keyword argument above.
+ That's because there is a name argument that's reserved for future
+ use. We can give a name, as long as it is an empty string:
+
+ >>> components.registerSubscriptionAdapter(
+ ... tests.A, [tests.I1], tests.IA2, u'', 'a sample comment')
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'',
+ A, 'a sample comment')
+
+ >>> components.registerSubscriptionAdapter(
+ ... tests.A, [tests.I1], tests.IA2, u'oops', 'a sample comment')
+ Traceback (most recent call last):
+ ...
+ TypeError: Named subscribers are not yet supported
+
+ Subscribers are looked up using the subscribers method:
+
+ >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+ ... print s
+ A1_2(U1(1))
+ A1_12(U1(1))
+ A(U1(1),)
+ A(U1(1),)
+
+ Note that, because we created multiple subscriptions for A, we got multiple
+ subscriber instances.
+
+ As with normal adapters, if a factory returns None, the result is skipped:
+
+ >>> components.registerSubscriptionAdapter(
+ ... tests.noop, [tests.I1], tests.IA2)
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', noop, u'')
+
+ >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+ ... print s
+ A1_2(U1(1))
+ A1_12(U1(1))
+ A(U1(1),)
+ A(U1(1),)
+
+ We can get registration information for subscriptions:
+
+ >>> for registration in sorted(
+ ... components.registeredSubscriptionAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A a sample comment
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A a sample comment
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_12
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_2
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ <function noop at 0xb796ff7c>
+
+ We can also unregister subscriptions in much the same way we can for adapters:
+
+ >>> components.unregisterSubscriptionAdapter(tests.A1_2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Unregistered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, '')
+ True
+
+ >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+ ... print s
+ A1_12(U1(1))
+ A(U1(1),)
+ A(U1(1),)
+
+ >>> for registration in sorted(
+ ... components.registeredSubscriptionAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A a sample comment
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A a sample comment
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_12
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ <function noop at 0xb796ff7c>
+
+ >>> components.unregisterSubscriptionAdapter(
+ ... tests.A, [tests.I1], tests.IA2)
+ Unregistered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A, '')
+ True
+
+ >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+ ... print s
+ A1_12(U1(1))
+
+ >>> for registration in sorted(
+ ... components.registeredSubscriptionAdapters()):
+ ... print registration.required
+ ... print registration.provided, registration.name
+ ... print registration.factory, registration.info
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ zope.component.tests.A1_12
+ (<InterfaceClass zope.component.tests.I1>,)
+ <InterfaceClass zope.component.tests.IA2>
+ <function noop at 0xb796ff7c>
+
+ Note here that both registrations for A were removed.
+
+ If we omit the factory, we must specify the required and provided interfaces:
+
+ >>> components.unregisterSubscriptionAdapter(required=[tests.I1])
+ Traceback (most recent call last):
+ ...
+ TypeError: Must specify one of factory and provided
+
+ >>> components.unregisterSubscriptionAdapter(provided=tests.IA2)
+ Traceback (most recent call last):
+ ...
+ TypeError: Must specify one of factory and required
+
+ >>> components.unregisterSubscriptionAdapter(
+ ... required=[tests.I1], provided=tests.IA2)
+ Unregistered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', None, '')
+ True
+
+ >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
+ ... print s
+
+ >>> for registration in sorted(
+ ... components.registeredSubscriptionAdapters()):
+ ... print registration.factory
+
+ As when registering, an error is raised if the registration
+ information can't be determined from the factory and isn't specified:
+
+ >>> components.unregisterSubscriptionAdapter(tests.A1_12)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single
+ interface and no provided interface was specified.
+
+ >>> components.unregisterSubscriptionAdapter(tests.A)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single interface and
+ no provided interface was specified.
+
+ >>> components.unregisterSubscriptionAdapter(tests.A, required=[tests.IA1])
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't implement a single interface
+ and no provided interface was specified.
+
+ If you unregister something that's not registered, nothing will be
+ changed and False will be returned:
+
+
+ >>> components.unregisterSubscriptionAdapter(
+ ... required=[tests.I1], provided=tests.IA2)
+ False
+
+ Handlers
+ --------
+
+ Handlers are used when you want to perform some function in response
+ to an event. Handlers aren't expected to return anything when called
+ and are not registered to provide any interface.
+
+ >>> from zope import component
+ >>> @component.adapter(tests.I1)
+ ... def handle1(x):
+ ... print 'handle1', x
+
+ >>> components.registerHandler(handle1, info="First handler")
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ HandlerRegistration(<Components comps>, [I1], u'',
+ handle1, 'First handler')
+ >>> components.handle(tests.U1(1))
+ handle1 U1(1)
+
+ >>> @component.adapter(tests.I1, tests.I2)
+ ... def handle12(x, y):
+ ... print 'handle12', x, y
+
+ >>> components.registerHandler(handle12)
+ Registered event:
+ HandlerRegistration(<Components comps>, [I1, I2], u'', handle12, u'')
+ >>> components.handle(tests.U1(1), tests.U12(2))
+ handle12 U1(1) U12(2)
+
+ If a handler doesn't document interfaces it handles, then
+ the required interfaces must be specified:
+
+ >>> def handle(*objects):
+ ... print 'handle', objects
+
+ >>> components.registerHandler(handle)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't have a __component_adapts__
+ attribute and no required specifications were specified
+
+ >>> components.registerHandler(handle, required=[tests.I1],
+ ... info="a comment")
+ Registered event:
+ HandlerRegistration(<Components comps>, [I1], u'', handle, 'a comment')
+
+ Handlers can also be registered for classes:
+
+ >>> components.registerHandler(handle, required=[tests.U],
+ ... info="handle a class")
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ HandlerRegistration(<Components comps>, [zope.component.tests.U], u'',
+ handle, 'handle a class')
+
+
+ >>> components.handle(tests.U1(1))
+ handle (U1(1),)
+ handle1 U1(1)
+ handle (U1(1),)
+
+ We can list the handler registrations:
+
+ >>> for registration in components.registeredHandlers():
+ ... print registration.required
+ ... print registration.handler, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle1 at 0xb78f5bfc> First handler
+ (<InterfaceClass zope.component.tests.I1>,
+ <InterfaceClass zope.component.tests.I2>)
+ <function handle12 at 0xb78f5c34>
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle at 0xb78f5ca4> a comment
+ (<implementedBy zope.component.tests.U>,)
+ <function handle at 0xb78f5ca4> handle a class
+
+ and we can unregister handlers:
+
+ >>> components.unregisterHandler(required=[tests.U])
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Unregistered event:
+ HandlerRegistration(<Components comps>, [zope.component.tests.U], u'',
+ None, '')
+ True
+
+ >>> for registration in components.registeredHandlers():
+ ... print registration.required
+ ... print registration.handler, registration.info
+ ... # doctest: +NORMALIZE_WHITESPACE
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle1 at 0xb78f5bfc> First handler
+ (<InterfaceClass zope.component.tests.I1>,
+ <InterfaceClass zope.component.tests.I2>)
+ <function handle12 at 0xb78f5c34>
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle at 0xb78f5ca4> a comment
+
+ >>> components.unregisterHandler(handle12)
+ Unregistered event:
+ HandlerRegistration(<Components comps>, [I1, I2], u'', handle12, '')
+ True
+
+ >>> for registration in components.registeredHandlers():
+ ... print registration.required
+ ... print registration.handler, registration.info
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle1 at 0xb78f5bfc> First handler
+ (<InterfaceClass zope.component.tests.I1>,)
+ <function handle at 0xb78f5ca4> a comment
+
+ >>> components.unregisterHandler(handle12)
+ False
+
+ >>> components.unregisterHandler()
+ Traceback (most recent call last):
+ ...
+ TypeError: Must specify one of factory and required
+
+ >>> components.registerHandler(handle)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ TypeError: The adapter factory doesn't have a __component_adapts__
+ attribute and no required specifications were specified
+
+ Extending
+ ---------
+
+ Component-management objects can extend other component-management
+ objects.
+
+ >>> c1 = registry.Components('1')
+ >>> c1.__bases__
+ ()
+
+ >>> c2 = registry.Components('2', (c1, ))
+ >>> c2.__bases__ == (c1, )
+ True
+
+ >>> c1.registerUtility(tests.U1(1))
+ Registered event:
+ UtilityRegistration(<Components 1>, I1, u'', 1, None, u'')
+
+ >>> c1.queryUtility(tests.I1)
+ U1(1)
+ >>> c2.queryUtility(tests.I1)
+ U1(1)
+ >>> c1.registerUtility(tests.U1(2))
+ Registered event:
+ UtilityRegistration(<Components 1>, I1, u'', 2, None, u'')
+
+ >>> c2.queryUtility(tests.I1)
+ U1(2)
+
+ We can use multiple inheritence:
+
+ >>> c3 = registry.Components('3', (c1, ))
+ >>> c4 = registry.Components('4', (c2, c3))
+ >>> c4.queryUtility(tests.I1)
+ U1(2)
+
+ >>> c1.registerUtility(tests.U12(1), tests.I2)
+ Registered event:
+ UtilityRegistration(<Components 1>, I2, u'', 1, None, u'')
+
+ >>> c4.queryUtility(tests.I2)
+ U12(1)
+
+ >>> c3.registerUtility(tests.U12(3), tests.I2)
+ Registered event:
+ UtilityRegistration(<Components 3>, I2, u'', 3, None, u'')
+ >>> c4.queryUtility(tests.I2)
+ U12(3)
+
+ >>> c1.registerHandler(handle1, info="First handler")
+ Registered event:
+ HandlerRegistration(<Components 1>, [I1], u'', handle1, 'First handler')
+
+ >>> c2.registerHandler(handle, required=[tests.U])
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ HandlerRegistration(<Components 2>, [zope.component.tests.U], u'',
+ handle, u'')
+
+ >>> @component.adapter(tests.I1)
+ ... def handle3(x):
+ ... print 'handle3', x
+ >>> c3.registerHandler(handle3)
+ Registered event:
+ HandlerRegistration(<Components 3>, [I1], u'', handle3, u'')
+
+ >>> @component.adapter(tests.I1)
+ ... def handle4(x):
+ ... print 'handle4', x
+ >>> c4.registerHandler(handle4)
+ Registered event:
+ HandlerRegistration(<Components 4>, [I1], u'', handle4, u'')
+
+ >>> c4.handle(tests.U1(1))
+ handle1 U1(1)
+ handle3 U1(1)
+ handle (U1(1),)
+ handle4 U1(1)
+
+ Redispatch of registration events
+ ---------------------------------
+
+ Some handlers are available that, if registered, redispatch
+ registration events to the objects being registered. They depend on
+ being dispatched to by the object-event dispatcher:
+
+ >>> from zope import component
+ >>> import zope.component.event
+ >>> zope.component.getGlobalSiteManager().registerHandler(
+ ... zope.component.event.objectEventNotify)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [IObjectEvent], u'', objectEventNotify, u'')
+
+ To see this, we'll first register a multi-handler to show is when
+ handlers are called on 2 objects:
+
+ >>> @zope.component.adapter(None, None)
+ ... def double_handler(o1, o2):
+ ... print 'Double dispatch:'
+ ... print ' ', o1
+ ... print ' ', o2
+ >>> zope.component.getGlobalSiteManager().registerHandler(double_handler)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Double dispatch:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [Interface, Interface], u'', double_handler, u'')
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [Interface, Interface], u'', double_handler, u'')
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [Interface, Interface], u'', double_handler, u'')
+
+ In the example above, the double_handler reported it's own registration. :)
+
+ Now we'll register our handlers:
+
+ >>> zope.component.getGlobalSiteManager().registerHandler(
+ ... registry.dispatchUtilityRegistrationEvent)
+ ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Double dispatch:
+ ...
+
+ >>> zope.component.getGlobalSiteManager().registerHandler(
+ ... registry.dispatchAdapterRegistrationEvent)
+ ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Double dispatch:
+ ...
+
+ >>> zope.component.getGlobalSiteManager().registerHandler(
+ ... registry.dispatchSubscriptionAdapterRegistrationEvent)
+ ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Double dispatch:
+ ...
+
+ >>> zope.component.getGlobalSiteManager().registerHandler(
+ ... registry.dispatchHandlerRegistrationEvent)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Double dispatch:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [IHandlerRegistration, IRegistrationEvent], u'',
+ dispatchHandlerRegistrationEvent, u'')
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [IHandlerRegistration, IRegistrationEvent], u'',
+ dispatchHandlerRegistrationEvent, u'')
+ Double dispatch:
+ <function dispatchHandlerRegistrationEvent at 0xb799f72c>
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [IHandlerRegistration, IRegistrationEvent], u'',
+ dispatchHandlerRegistrationEvent, u'')
+ Registered event:
+ HandlerRegistration(<BaseGlobalComponents base>,
+ [IHandlerRegistration, IRegistrationEvent], u'',
+ dispatchHandlerRegistrationEvent, u'')
+
+ In the last example above, we can see that the registration of
+ dispatchHandlerRegistrationEvent was handled by
+ dispatchHandlerRegistrationEvent and redispatched. This can be seen
+ in the second double-dispatch output, where the first argument is the
+ object being registered, which is dispatchHandlerRegistrationEvent.
+
+ If we change some other registrations, we can the double dispatch
+ taking place:
+
+ >>> components.registerUtility(u5)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Double dispatch:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+ Double dispatch:
+ U1(5)
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+ Registered event:
+ UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
+
+ >>> components.registerAdapter(tests.A12_1)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Double dispatch:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+ Double dispatch:
+ zope.component.tests.A12_1
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+ Registered event:
+ AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
+
+ >>> components.registerSubscriptionAdapter(tests.A1_2)
+ ... # doctest: +NORMALIZE_WHITESPACE
+ Double dispatch:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
+ Double dispatch:
+ zope.component.tests.A1_2
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
+ Registered event:
+ SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
+
+ Persistent Component Management
+ ===============================
+
+ Persistent component management allows persistent management of
+ components. From a usage point of view, there shouldn't be any new
+ behavior beyond what's described in registry.txt.
+
+ The Zope 3 Component Architecture (Socket Example)
+ ==================================================
+
+ The component architecture provides an application framework that provides its
+ functionality through loosely-connected components. A *component* can be any
+ Python object and has a particular purpose associated with it. Thus, in a
+ component-based applications you have many small component in contrast to
+ classical object-oriented development, where you have a few big objects.
+
+ Components communicate via specific APIs, which are formally defined by
+ interfaces, which are provided by the `zope.interface` package. *Interfaces*
+ describe the methods and properties that a component is expected to
+ provide. They are also used as a primary mean to provide developer-level
+ documentation for the components. For more details about interfaces see
+ `zope/interface/README.txt`.
+
+ The two main types of components are *adapters* and *utilities*. They will be
+ discussed in detail later in this document. Both component types are managed
+ by the *site manager*, with which you can register and access these
+ components. However, most of the site manager's functionality is hidden behind
+ the component architecture's public API, which is documented in
+ `IComponentArchitecture`.
+
+
+ Adapters
+ --------
+
+ Adapters are a well-established pattern. An *adapter* uses an object providing
+ one interface to produce an object that provides another interface. Here an
+ example: Imagine that you purchased an electric shaver in the US, and thus
+ you require the US socket type. You are now traveling in Germany, where another
+ socket style is used. You will need a device, an adapter, that converts from
+ the German to the US socket style.
+
+ The functionality of adapters is actually natively provided by the
+ `zope.interface` package and is thus well documented there. The `human.txt`
+ file provides a gentle introduction to adapters, whereby `adapter.txt` is
+ aimed at providing a comprehensive insight into adapters, but is too abstract
+ for many as an initial read. Thus, we will only explain adapters in the context
+ of the component architecture's API.
+
+ So let's say that we have a German socket
+
+ >>> from zope.interface import Interface, implements
+
+ >>> class IGermanSocket(Interface):
+ ... pass
+
+ >>> class Socket(object):
+ ... def __repr__(self):
+ ... return '<instance of %s>' %self.__class__.__name__
+
+ >>> class GermanSocket(Socket):
+ ... """German wall socket."""
+ ... implements(IGermanSocket)
+
+ and we want to convert it to an US socket
+
+ >>> class IUSSocket(Interface):
+ ... pass
+
+ so that our shaver can be used in Germany. So we go to a German electronics
+ store to look for an adapter that we can plug in the wall:
+
+ >>> class GermanToUSSocketAdapter(Socket):
+ ... implements(IUSSocket)
+ ... __used_for__ = IGermanSocket
+ ...
+ ... def __init__(self, socket):
+ ... self.context = socket
+
+ Note that I could have called the passed in socket any way I like, but
+ `context` is the standard name accepted.
+
+
+ Single Adapters
+ ~~~~~~~~~~~~~~~
+
+ Before we can use the adapter, we have to buy it and make it part of our
+ inventory. In the component architecture we do this by registering the adapter
+ with the framework, more specifically with the global site manager:
+
+ >>> import zope.component
+ >>> gsm = zope.component.getGlobalSiteManager()
+ >>> gsm.registerAdapter(GermanToUSSocketAdapter, (IGermanSocket,), IUSSocket)
+
+ `zope.component` is the component architecture API that is being
+ presented by this file. You registered an adapter from `IGermanSocket`
+ to `IUSSocket` having no name (thus the empty string).
+
+ Anyways, you finally get back to your hotel room and shave, since you have not
+ been able to shave in the plane. In the bathroom you discover a socket:
+
+ >>> bathroomDE = GermanSocket()
+ >>> IGermanSocket.providedBy(bathroomDE)
+ True
+
+ You now insert the adapter in the German socket
+
+ >>> bathroomUS = zope.component.getAdapter(bathroomDE, IUSSocket, '')
+
+ so that the socket now provides the US version:
+
+ >>> IUSSocket.providedBy(bathroomUS)
+ True
+
+ Now you can insert your shaver and get on with your day.
+
+ After a week you travel for a couple of days to the Prague and you notice that
+ the Czech have yet another socket type:
+
+ >>> class ICzechSocket(Interface):
+ ... pass
+
+ >>> class CzechSocket(Socket):
+ ... implements(ICzechSocket)
+
+ >>> czech = CzechSocket()
+
+ You try to find an adapter for your shaver in your bag, but you fail, since
+ you do not have one:
+
+ >>> zope.component.getAdapter(czech, IUSSocket, '') \
+ ... #doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<instance of CzechSocket>,
+ <InterfaceClass __builtin__.IUSSocket>,
+ '')
+
+ or the more graceful way:
+
+ >>> marker = object()
+ >>> socket = zope.component.queryAdapter(czech, IUSSocket, '', marker)
+ >>> socket is marker
+ True
+
+ In the component architecture API any `get*` method will fail with a specific
+ exception, if a query failed, whereby methods starting with `query*` will
+ always return a `default` value after a failure.
+
+
+ Named Adapters
+ ~~~~~~~~~~~~~~
+
+ You are finally back in Germany. You also brought your DVD player and a couple
+ DVDs with you, which you would like to watch. Your shaver was able to convert
+ automatically from 110 volts to 240 volts, but your DVD player cannot. So you
+ have to buy another adapter that also handles converting the voltage and the
+ frequency of the AC current:
+
+ >>> class GermanToUSSocketAdapterAndTransformer(object):
+ ... implements(IUSSocket)
+ ... __used_for__ = IGermanSocket
+ ...
+ ... def __init__(self, socket):
+ ... self.context = socket
+
+ Now, we need a way to keep the two adapters apart. Thus we register them with
+ a name:
+
+ >>> gsm.registerAdapter(GermanToUSSocketAdapter,
+ ... (IGermanSocket,), IUSSocket, 'shaver',)
+ >>> gsm.registerAdapter(GermanToUSSocketAdapterAndTransformer,
+ ... (IGermanSocket,), IUSSocket, 'dvd')
+
+ Now we simply look up the adapters using their labels (called *name*):
+
+ >>> socket = zope.component.getAdapter(bathroomDE, IUSSocket, 'shaver')
+ >>> socket.__class__ is GermanToUSSocketAdapter
+ True
+
+ >>> socket = zope.component.getAdapter(bathroomDE, IUSSocket, 'dvd')
+ >>> socket.__class__ is GermanToUSSocketAdapterAndTransformer
+ True
+
+ Clearly, we do not have an adapter for the MP3 player
+
+ >>> zope.component.getAdapter(bathroomDE, IUSSocket, 'mp3') \
+ ... #doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<instance of GermanSocket>,
+ <InterfaceClass __builtin__.IUSSocket>,
+ 'mp3')
+
+ but you could use the 'dvd' adapter in this case of course. ;)
+
+ Sometimes you want to know all adapters that are available. Let's say you want
+ to know about all the adapters that convert a German to a US socket type:
+
+ >>> sockets = list(zope.component.getAdapters((bathroomDE,), IUSSocket))
+ >>> len(sockets)
+ 3
+ >>> names = [name for name, socket in sockets]
+ >>> names.sort()
+ >>> names
+ [u'', u'dvd', u'shaver']
+
+ `zope.component.getAdapters()` returns a list of tuples. The first
+ entry of the tuple is the name of the adapter and the second is the
+ adapter itself.
+
+
+ Multi-Adapters
+ ~~~~~~~~~~~~~~
+
+ After watching all the DVDs you brought at least twice, you get tired of them
+ and you want to listen to some music using your MP3 player. But darn, the MP3
+ player plug has a ground pin and all the adapters you have do not support
+ that:
+
+ >>> class IUSGroundedSocket(IUSSocket):
+ ... pass
+
+ So you go out another time to buy an adapter. This time, however, you do not
+ buy yet another adapter, but a piece that provides the grounding plug:
+
+ >>> class IGrounder(Interface):
+ ... pass
+
+ >>> class Grounder(object):
+ ... implements(IGrounder)
+ ... def __repr__(self):
+ ... return '<instance of Grounder>'
+
+
+ Then together they will provided a grounded us socket:
+
+ >>> class GroundedGermanToUSSocketAdapter(object):
+ ... implements(IUSGroundedSocket)
+ ... __used_for__ = (IGermanSocket, IGrounder)
+ ... def __init__(self, socket, grounder):
+ ... self.socket, self.grounder = socket, grounder
+
+ You now register the combination, so that you know you can create a
+ `IUSGroundedSocket`:
+
+ >>> gsm.registerAdapter(GroundedGermanToUSSocketAdapter,
+ ... (IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3')
+
+ Given the grounder
+
+ >>> grounder = Grounder()
+
+ and a German socket
+
+ >>> livingroom = GermanSocket()
+
+ we can now get a grounded US socket:
+
+ >>> socket = zope.component.getMultiAdapter((livingroom, grounder),
+ ... IUSGroundedSocket, 'mp3')
+
+ >>> socket.__class__ is GroundedGermanToUSSocketAdapter
+ True
+ >>> socket.socket is livingroom
+ True
+ >>> socket.grounder is grounder
+ True
+
+ Of course, you do not have a 'dvd' grounded US socket available:
+
+ >>> zope.component.getMultiAdapter((livingroom, grounder),
+ ... IUSGroundedSocket, 'dvd') \
+ ... #doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: ((<instance of GermanSocket>,
+ <instance of Grounder>),
+ <InterfaceClass __builtin__.IUSGroundedSocket>,
+ 'dvd')
+
+
+ >>> socket = zope.component.queryMultiAdapter(
+ ... (livingroom, grounder), IUSGroundedSocket, 'dvd', marker)
+ >>> socket is marker
+ True
+
+ Again, you might want to read `adapter.txt` in `zope.interface` for a more
+ comprehensive coverage of multi-adapters.
+
+ Subscribers
+ -----------
+
+ While subscribers are directly supported by the adapter registry and are
+ adapters for all theoretical purposes, practically it might be better to think
+ of them as separate components. Subscribers are particularly useful for
+ events.
+
+ Let's say one of our adapters overheated and caused a small fire:
+
+ >>> class IFire(Interface):
+ ... pass
+
+ >>> class Fire(object):
+ ... implements(IFire)
+
+ >>> fire = Fire()
+
+ We want to use all available objects to put out the fire:
+
+ >>> class IFireExtinguisher(Interface):
+ ... def extinguish():
+ ... pass
+
+ >>> class FireExtinguisher(object):
+ ... def __init__(self, fire):
+ ... pass
+ ... def extinguish(self):
+ ... "Place extinguish code here."
+ ... print 'Used ' + self.__class__.__name__ + '.'
+
+ Here some specific methods to put out the fire:
+
+ >>> class PowderExtinguisher(FireExtinguisher):
+ ... pass
+ >>> gsm.registerSubscriptionAdapter(PowderExtinguisher,
+ ... (IFire,), IFireExtinguisher)
+
+ >>> class Blanket(FireExtinguisher):
+ ... pass
+ >>> gsm.registerSubscriptionAdapter(Blanket, (IFire,), IFireExtinguisher)
+
+ >>> class SprinklerSystem(FireExtinguisher):
+ ... pass
+ >>> gsm.registerSubscriptionAdapter(SprinklerSystem,
+ ... (IFire,), IFireExtinguisher)
+
+ Now let use all these things to put out the fire:
+
+ >>> extinguishers = zope.component.subscribers((fire,), IFireExtinguisher)
+ >>> extinguishers.sort()
+ >>> for extinguisher in extinguishers:
+ ... extinguisher.extinguish()
+ Used Blanket.
+ Used PowderExtinguisher.
+ Used SprinklerSystem.
+
+ If no subscribers are found for a particular object, then an empty list is
+ returned:
+
+ >>> zope.component.subscribers((object(),), IFireExtinguisher)
+ []
+
+
+ Utilities
+ ---------
+
+ Utilities are the second type of component, the component architecture
+ implements. *Utilities* are simply components that provide an interface. When
+ you register an utility, you always register an instance (in contrast to a
+ factory for adapters) since the initialization and setup process of a utility
+ might be complex and is not well defined. In some ways a utility is much more
+ fundamental than an adapter, because an adapter cannot be used without another
+ component, but a utility is always self-contained. I like to think of
+ utilities as the foundation of your application and adapters as components
+ extending beyond this foundation.
+
+ Back to our story...
+
+ After your vacation is over you fly back home to Tampa, Florida. But it is
+ August now, the middle of the Hurricane season. And, believe it or not, you are
+ worried that you will not be able to shave when the power goes out for several
+ days. (You just hate wet shavers.)
+
+ So you decide to go to your favorite hardware store and by a Diesel-powered
+ electric generator. The generator provides of course a US-style socket:
+
+ >>> class Generator(object):
+ ... implements(IUSSocket)
+ ... def __repr__(self):
+ ... return '<instance of Generator>'
+
+ >>> generator = Generator()
+
+ Like for adapters, we now have to add the newly-acquired generator to our
+ inventory by registering it as a utility:
+
+ >>> gsm.registerUtility(generator, IUSSocket)
+
+ We can now get the utility using
+
+ >>> utility = zope.component.getUtility(IUSSocket)
+ >>> utility is generator
+ True
+
+ As you can see, it is very simple to register and retrieve utilities. If a
+ utility does not exist for a particular interface, such as the German socket,
+ then the lookup fails
+
+ >>> zope.component.getUtility(IGermanSocket)
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass __builtin__.IGermanSocket>, '')
+
+ or more gracefully when specifying a default value:
+
+ >>> default = object()
+ >>> utility = zope.component.queryUtility(IGermanSocket, default=default)
+ >>> utility is default
+ True
+
+ Note: The only difference between `getUtility()` and `queryUtility()` is the
+ fact that you can specify a default value for the latter function, so that it
+ will never cause a `ComponentLookupError`.
+
+
+ Named Utilities
+ ~~~~~~~~~~~~~~~
+
+ It is often desirable to have several utilities providing the same interface
+ per site. This way you can implement any sort of registry using utilities. For
+ this reason, utilities -- like adapters -- can be named.
+
+ In the context of our story, we might want to do the following: You really do
+ not trust gas stations either. What if the roads are blocked after a hurricane
+ and the gas stations run out of oil. So you look for another renewable power
+ source. Then you think about solar panels! After a storm there is usually very
+ nice weather, so why not? Via the Web you order a set of 110V/120W solar
+ panels that provide a regular US-style socket as output:
+
+ >>> class SolarPanel(object):
+ ... implements(IUSSocket)
+ ... def __repr__(self):
+ ... return '<instance of Solar Panel>'
+
+ >>> panel = SolarPanel()
+
+ Once it arrives, we add it to our inventory:
+
+ >>> gsm.registerUtility(panel, IUSSocket, 'Solar Panel')
+
+ You can now access the solar panel using
+
+ >>> utility = zope.component.getUtility(IUSSocket, 'Solar Panel')
+ >>> utility is panel
+ True
+
+ Of course, if a utility is not available, then the lookup will simply fail
+
+ >>> zope.component.getUtility(IUSSocket, 'Wind Mill')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass __builtin__.IUSSocket>, 'Wind Mill')
+
+ or more gracefully when specifying a default value:
+
+ >>> default = object()
+ >>> utility = zope.component.queryUtility(IUSSocket, 'Wind Mill',
+ ... default=default)
+ >>> utility is default
+ True
+
+ Now you want to look at all the utilities you have for a particular kind. The
+ following API function will return a list of name/utility pairs:
+
+ >>> utils = list(zope.component.getUtilitiesFor(IUSSocket))
+ >>> utils.sort()
+ >>> utils #doctest: +NORMALIZE_WHITESPACE
+ [(u'', <instance of Generator>),
+ (u'Solar Panel', <instance of Solar Panel>)]
+
+ Another method of looking up all utilities is by using
+ `getAllUtilitiesRegisteredFor(iface)`. This function will return an iterable
+ of utilities (without names); however, it will also return overridden
+ utilities. If you are not using multiple site managers, you will not actually
+ need this method.
+
+ >>> utils = list(zope.component.getAllUtilitiesRegisteredFor(IUSSocket))
+ >>> utils.sort()
+ >>> utils
+ [<instance of Generator>, <instance of Solar Panel>]
+
+
+ Factories
+ ~~~~~~~~~
+
+ A *factory* is a special kind of utility that exists to create other
+ components. A factory is always identified by a name. It also provides a title
+ and description and is able to tell the developer what interfaces the created
+ object will provide. The advantage of using a factory to create an object
+ instead of directly instantiating a class or executing any other callable is
+ that we can refer to the factory by name. As long as the name stays fixed, the
+ implementation of the callable can be renamed or moved without a breakage in
+ code.
+
+ Let's say that our solar panel comes in parts and they have to be
+ assembled. This assembly would be done by a factory, so let's create one for
+ the solar panel. To do this, we can use a standard implementation of the
+ `IFactory` interface:
+
+ >>> from zope.component.factory import Factory
+ >>> factory = Factory(SolarPanel,
+ ... 'Solar Panel',
+ ... 'This factory creates a solar panel.')
+
+ Optionally, I could have also specified the interfaces that the created object
+ will provide, but the factory class is smart enough to determine the
+ implemented interface from the class. We now register the factory:
+
+ >>> from zope.component.interfaces import IFactory
+ >>> gsm.registerUtility(factory, IFactory, 'SolarPanel')
+
+ We can now get a list of interfaces the produced object will provide:
+
+ >>> ifaces = zope.component.getFactoryInterfaces('SolarPanel')
+ >>> IUSSocket in ifaces
+ True
+
+ By the way, this is equivalent to
+
+ >>> ifaces2 = factory.getInterfaces()
+ >>> ifaces is ifaces2
+ True
+
+ Of course you can also just create an object:
+
+ >>> panel = zope.component.createObject('SolarPanel')
+ >>> panel.__class__ is SolarPanel
+ True
+
+ Note: Ignore the first argument (`None`) for now; it is the context of the
+ utility lookup, which is usually an optional argument, but cannot be in this
+ case, since all other arguments beside the `name` are passed in as arguments
+ to the specified callable.
+
+ Once you register several factories
+
+ >>> gsm.registerUtility(Factory(Generator), IFactory, 'Generator')
+
+ you can also determine, which available factories will create objects
+ providing a certain interface:
+
+ >>> factories = zope.component.getFactoriesFor(IUSSocket)
+ >>> factories = [(name, factory.__class__) for name, factory in factories]
+ >>> factories.sort()
+ >>> factories #doctest: +NORMALIZE_WHITESPACE
+ [(u'Generator', <class 'zope.component.factory.Factory'>),
+ (u'SolarPanel', <class 'zope.component.factory.Factory'>)]
+
+
+ Site Managers
+ -------------
+
+ Why do we need site managers? Why is the component architecture API not
+ sufficient? Some applications, including Zope 3, have a concept of
+ locations. It is often desirable to have different configurations for these
+ location; this can be done by overwriting existing or adding new component
+ registrations. Site managers in locations below the root location, should be
+ able to delegate requests to their parent locations. The root site manager is
+ commonly known as *global site manager*, since it is always available. You can
+ always get the global site manager using the API:
+
+ >>> gsm = zope.component.getGlobalSiteManager()
+
+ >>> from zope.component import globalSiteManager
+ >>> gsm is globalSiteManager
+ True
+ >>> from zope.component.interfaces import IComponentLookup
+ >>> IComponentLookup.providedBy(gsm)
+ True
+ >>> from zope.component.interfaces import IComponents
+ >>> IComponents.providedBy(gsm)
+ True
+
+ You can also lookup at site manager in a given context. The only requirement
+ is that the context can be adapted to a site manager. So let's create a
+ special site manager:
+
+ >>> from zope.component.globalregistry import BaseGlobalComponents
+ >>> sm = BaseGlobalComponents()
+
+ Now we create a context that adapts to the site manager via the `__conform__`
+ method as specified in PEP 246.
+
+ >>> class Context(object):
+ ... def __init__(self, sm):
+ ... self.sm = sm
+ ... def __conform__(self, interface):
+ ... if interface.isOrExtends(IComponentLookup):
+ ... return self.sm
+
+ We now instantiate the `Context` with our special site manager:
+
+ >>> context = Context(sm)
+ >>> context.sm is sm
+ True
+
+ We can now ask for the site manager of this context:
+
+ >>> lsm = zope.component.getSiteManager(context)
+ >>> lsm is sm
+ True
+
+ The site manager instance `lsm` is formally known as a *local site manager* of
+ `context`.
+
+ CHANGES
+ *******
+
+ 3.7.1 (unreleased)
+ ==================
+
+ - Nothing changed yet.
+
+
+ 3.7.0 (2009-05-21)
+ ==================
+
+ - The HookableTests were not run by the testrunner.
+
+ - Add in zope:view and zope:resource implementations into
+ zope.component.zcml (dependency loaded with zope.component [zcml]).
+
+ 3.6.0 (2009-03-12)
+ ==================
+
+ - IMPORTANT: the interfaces that were defined in the
+ zope.component.bbb.interfaces and deprecated for years are
+ now (re)moved. However, some packages, including part of zope
+ framework were still using those interfaces. They will be adapted
+ for this change. If you were using some of those interfaces, you
+ need to adapt your code as well:
+
+ - The IView and IDefaultViewName were moved to zope.publisher.interfaces.
+
+ - The IResource was moved to zope.app.publisher.interfaces.
+
+ - IContextDependent, IPresentation, IPresentationRequest,
+ IResourceFactory, IViewFactory were removed completely.
+
+ If you used IViewFactory in context of zope.app.form, there's now
+ IWidgetFactory in the zope.app.form.interfaces instead.
+
+ - Add getNextUtility/queryNextUtility functions that used to be in zope.site
+ earlier (and in zope.app.component even more earlier).
+
+ - Added a pure-Python 'hookable' implementation, for use when
+ 'zope.hookable' is not present.
+
+ - Removed use of 'zope.deferredimport' by breaking import cycles.
+
+ - Cleanup package documentation and changelog a bit. Add sphinx-based
+ documentation building command to the buildout.
+
+ - Remove deprecated code.
+
+ - Change package's mailing list address to zope-dev at zope.org, because
+ zope3-dev at zope.org is now retired.
+
+ 3.5.1 (2008-07-25)
+ ==================
+
+ - Fix bug introduced in 3.5.0: <utility factory="..."> no longer supported
+ interfaces declared in Python and always wanted an explicit provides="..."
+ attribute. https://bugs.launchpad.net/zope3/+bug/251865
+
+ 3.5.0 (2008-07-25)
+ ==================
+
+ - Support registration of utilities via factories through the component registry
+ and return factory information in the registration information. This fixes
+ https://bugs.launchpad.net/zope3/+bug/240631
+
+ - Optimized un/registerUtility via storing an optimized data structure for
+ efficient retrieval of already registered utilities. This avoids looping over
+ all utilities when registering a new one.
+
+ 3.4.0 (2007-09-29)
+ ==================
+
+ No further changes since 3.4.0a1.
+
+ 3.4.0a1 (2007-04-22)
+ ====================
+
+ Corresponds to zope.component from Zope 3.4.0a1.
+
+ - In the Zope 3.3.x series, ``zope.component`` was simplified yet once
+ more. See http://wiki.zope.org/zope3/LocalComponentManagementSimplification
+ for the proposal describing the changes.
+
+ 3.2.0.2 (2006-04-15)
+ ====================
+
+ - Fix packaging bug: 'package_dir' must be a *relative* path.
+
+ 3.2.0.1 (2006-04-14)
+ ====================
+
+ - Packaging change: suppress inclusion of 'setup.cfg' in 'sdist' builds.
+
+ 3.2.0 (2006-01-05)
+ ==================
+
+ Corresponds to the verison of the zope.component package shipped as part of
+ the Zope 3.2.0 release.
+
+ - Deprecated services and related APIs. The adapter and utility registries
+ are now available directly via the site manager's 'adapters' and 'utilities'
+ attributes, respectively. Services are accessible, but deprecated, and
+ will be removed in Zope 3.3.
+
+ - Deprectaed all presentation-related APIs, including all view-related
+ API functions. Use the adapter API functions instead.
+ See http://dev.zope.org/Zope3/ImplementViewsAsAdapters`
+
+ - Deprecated 'contextdependent' package: site managers are now looked up
+ via a thread global, set during URL traversal. The 'context' argument
+ is now always optional, and should no longer be passed.
+
+ 3.0.0 (2004-11-07)
+ ==================
+
+ Corresponds to the verison of the zope.component package shipped as part of
+ the Zope X3.0.0 release.
+
+ Download
+ ********
+
+Platform: UNKNOWN
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/SOURCES.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/SOURCES.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/SOURCES.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,44 @@
+CHANGES.txt
+README.txt
+bootstrap.py
+buildout.cfg
+setup.py
+src/zope/__init__.py
+src/zope.component.egg-info/PKG-INFO
+src/zope.component.egg-info/SOURCES.txt
+src/zope.component.egg-info/dependency_links.txt
+src/zope.component.egg-info/namespace_packages.txt
+src/zope.component.egg-info/not-zip-safe
+src/zope.component.egg-info/requires.txt
+src/zope.component.egg-info/top_level.txt
+src/zope/component/README.txt
+src/zope/component/__init__.py
+src/zope/component/_api.py
+src/zope/component/_declaration.py
+src/zope/component/configure.zcml
+src/zope/component/event.py
+src/zope/component/event.txt
+src/zope/component/eventtesting.py
+src/zope/component/factory.py
+src/zope/component/factory.txt
+src/zope/component/globalregistry.py
+src/zope/component/hookable.py
+src/zope/component/index.txt
+src/zope/component/interface.py
+src/zope/component/interfaces.py
+src/zope/component/meta.zcml
+src/zope/component/nexttesting.py
+src/zope/component/persistentregistry.py
+src/zope/component/persistentregistry.txt
+src/zope/component/registry.py
+src/zope/component/registry.txt
+src/zope/component/socketexample.txt
+src/zope/component/standalonetests.py
+src/zope/component/testing.py
+src/zope/component/tests.py
+src/zope/component/zcml.py
+src/zope/component/zcml.txt
+src/zope/component/testfiles/__init__.py
+src/zope/component/testfiles/adapter.py
+src/zope/component/testfiles/components.py
+src/zope/component/testfiles/views.py
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/SOURCES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/dependency_links.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/dependency_links.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/dependency_links.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/dependency_links.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/namespace_packages.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/namespace_packages.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/namespace_packages.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+zope
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/namespace_packages.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/not-zip-safe
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/not-zip-safe (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/not-zip-safe 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/requires.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/requires.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/requires.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,24 @@
+setuptools
+zope.interface
+zope.event
+
+[test]
+ZODB3
+zope.testing
+zope.hookable
+zope.location
+
+[docs]
+z3c.recipe.sphinxdoc
+
+[zcml]
+zope.configuration
+zope.security
+zope.proxy
+zope.i18nmessageid
+
+[persistentregistry]
+ZODB3
+
+[hook]
+zope.hookable
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/requires.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/top_level.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/top_level.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/top_level.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+zope
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.component.egg-info/top_level.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/PKG-INFO
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/PKG-INFO (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/PKG-INFO 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,796 @@
+Metadata-Version: 1.0
+Name: zope.security
+Version: 3.6.4dev
+Summary: Zope3 Security Framework
+Home-page: http://pypi.python.org/pypi/zope.security
+Author: Zope Corporation and Contributors
+Author-email: zope-dev at zope.org
+License: ZPL 2.1
+Description: The Security framework provides a generic mechanism to implement security
+ policies on Python objects.
+
+ .. contents::
+
+ ==============
+ Zope3 Security
+ ==============
+
+ Introduction
+ ------------
+
+ The Security framework provides a generic mechanism to implement security
+ policies on Python objects. This introduction provides a tutorial of the
+ framework explaining concepts, design, and going through sample usage from the
+ perspective of a Python programmer using the framework outside of Zope.
+
+ Definitions
+ -----------
+
+ Principal
+ ~~~~~~~~~
+
+ A generalization of a concept of a user.
+
+ Permission
+ ~~~~~~~~~~
+
+ A kind of access, i.e. permission to READ vs. permission to WRITE.
+ Fundamentally the whole security framework is organized around checking
+ permissions on objects.
+
+ Purpose
+ -------
+
+ The security framework's primary purpose is to guard and check access to
+ Python objects. It does this by providing mechanisms for explicit and
+ implicit security checks on attribute access for objects. Attribute names are
+ mapped onto permission names when checking access and the implementation of
+ the security check is defined by the security policy, which receives the
+ object, the permission name, and an interaction.
+
+ Interactions are objects that represent the use of the system by one or more
+ principals. An interaction contains a list of participations, which
+ represents the way a single principal participates in the interaction. An
+ HTTP request is one example of a participation.
+
+ Its important to keep in mind that the policy provided is just a default, and
+ it can be substituted with one which doesn't care about principals or
+ interactions at all.
+
+ Framework Components
+ --------------------
+
+ Low Level Components
+ ~~~~~~~~~~~~~~~~~~~~
+
+ These components provide the infrastructure for guarding attribute access and
+ providing hooks into the higher level security framework.
+
+ Checkers
+ ~~~~~~~~
+
+ A checker is associated with an object kind, and provides the hooks that map
+ attribute checks onto permissions deferring to the security manager (which in
+ turn defers to the policy) to perform the check.
+
+ Additionally, checkers provide for creating proxies of objects associated with
+ the checker.
+
+ There are several implementation variants of checkers, such as checkers that
+ grant access based on attribute names.
+
+ Proxies
+ ~~~~~~~
+
+ Wrappers around Python objects that implicitly guard access to their wrapped
+ contents by delegating to their associated checker. Proxies are also viral in
+ nature, in that values returned by proxies are also proxied.
+
+ High Level Components
+ ---------------------
+
+ Security Management
+ ~~~~~~~~~~~~~~~~~~~
+
+ Provides accessors for setting up interactions and the global security policy.
+
+ Interaction
+ ~~~~~~~~~~~
+
+ Stores transient information on the list of participations.
+
+ Participation
+ ~~~~~~~~~~~~~
+
+ Stores information about a principal participating in the interaction.
+
+ Security Policy
+ ~~~~~~~~~~~~~~~
+
+ Provides a single method that accepts the object, the permission, and the
+ interaction of the access being checked and is used to implement the
+ application logic for the security framework.
+
+ Narrative (agent sandbox)
+ -------------------------
+
+ As an example we take a look at constructing a multi-agent distributed system,
+ and then adding a security layer using the Zope security model onto it.
+
+ Scenario
+ ~~~~~~~~
+
+ Our agent simulation consists of autonomous agents that live in various agent
+ homes/sandboxes and perform actions that access services available at their
+ current home. Agents carry around authentication tokens which signify their
+ level of access within any given home. Additionally agents attempt to migrate
+ from home to home randomly.
+
+ The agent simulation was constructed separately from any security aspects.
+ Now we want to define and integrate a security model into the simulation. The
+ full code for the simulation and the security model is available separately;
+ we present only relevant code snippets here for illustration as we go through
+ the implementation process.
+
+ For the agent simulation we want to add a security model such that we group
+ agents into two authentication groups, "norse legends", including the
+ principals thor, odin, and loki, and "greek men", including prometheus,
+ archimedes, and thucydides.
+
+ We associate permissions with access to services and homes. We differentiate
+ the homes such that certain authentication groups only have access to services
+ or the home itself based on the local settings of the home in which they
+ reside.
+
+ We define the homes/sandboxes
+
+ - origin - all agents start here, and have access to all
+ services here.
+
+ - valhalla - only agents in the authentication group 'norse
+ legend' can reside here.
+
+ - jail - all agents can come here, but only 'norse legend's
+ can leave or access services.
+
+
+ Process
+ ~~~~~~~
+
+ Loosely we define a process for implementing this security model
+
+ - mapping permissions onto actions
+
+ - mapping authentication tokens onto permissions
+
+ - implementing checkers and security policies that use our
+ authentication tokens and permissions.
+
+ - binding checkers to our simulation classes
+
+ - inserting the hooks into the original simulation code to add
+ proxy wrappers to automatically check security.
+
+ - inserting hooks into the original simulation to register the
+ agents as the active principal in an interaction.
+
+
+ Defining a Permission Model
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ We define the following permissions::
+
+ NotAllowed = 'Not Allowed'
+ Public = Checker.CheckerPublic
+ TransportAgent = 'Transport Agent'
+ AccessServices = 'Access Services'
+ AccessAgents = 'Access Agents'
+ AccessTimeService = 'Access Time Services'
+ AccessAgentService = 'Access Agent Service'
+ AccessHomeService = 'Access Home Service'
+
+ and create a dictionary database mapping homes to authentication groups which
+ are linked to associated permissions.
+
+
+ Defining and Binding Checkers
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Checkers are the foundational unit for the security framework. They define
+ what attributes can be accessed or set on a given instance. They can be used
+ implicitly via Proxy objects, to guard all attribute access automatically or
+ explicitly to check a given access for an operation.
+
+ Checker construction expects two functions or dictionaries, one is used to map
+ attribute names to permissions for attribute access and another to do the same
+ for setting attributes.
+
+ We use the following checker factory function::
+
+ def PermissionMapChecker(permissions_map={},
+ setattr_permission_func=NoSetAttr):
+ res = {}
+ for k,v in permissions_map.items():
+ for iv in v:
+ res[iv]=k
+ return checker.Checker(res.get, setattr_permission_func)
+
+ time_service_checker = PermissionMapChecker(
+ # permission : [methods]
+ {'AccessTimeService':['getTime']}
+ )
+
+ with the NoSetAttr function defined as a lambda which always return the
+ permission `NotAllowed`.
+
+ To bind the checkers to the simulation classes we register our checkers with
+ the security model's global checker registry::
+
+ import sandbox_simulation
+ from zope.security.checker import defineChecker
+ defineChecker(sandbox_simulation.TimeService, time_service_checker)
+
+
+ Defining a Security Policy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ We implement our security policy such that it checks the current agent's
+ authentication token against the given permission in the home of the object
+ being accessed::
+
+ class SimulationSecurityPolicy:
+
+ implements(ISecurityPolicy)
+
+ createInteraction = staticmethod(simpleinteraction.createInteraction)
+
+ def checkPermission(self, permission, object, interaction):
+
+ home = object.getHome()
+ db = getattr(SimulationSecurityDatabase, home.getId(), None)
+
+ if db is None:
+ return False
+
+ allowed = db.get('any', ())
+ if permission in allowed or ALL in allowed:
+ return True
+
+ if interaction is None:
+ return False
+ if not interaction.participations:
+ return False
+ for participation in interaction.participations:
+ token = participation.principal.getAuthenticationToken()
+ allowed = db.get(token, ())
+ if permission not in allowed:
+ return False
+
+ return True
+
+ There are no specific requirements for the interaction class, so we can just
+ use `zope.security.simpleinteraction.Interaction`.
+
+ Since an interaction can have more than one principal, we check that *all* of
+ them are given the necessary permission. This is not really necessary since
+ we only create interactions with a single active principal.
+
+ There is some additional code present to allow for shortcuts in defining the
+ permission database when defining permissions for all auth groups and all
+ permissions.
+
+
+ Integration
+ ~~~~~~~~~~~
+
+ At this point we have implemented our security model, and we need to integrate
+ it with our simulation model. We do so in three separate steps.
+
+ First we make it such that agents only access homes that are wrapped in a
+ security proxy. By doing this all access to homes and services (proxies have
+ proxied return values for their methods) is implicitly guarded by our security
+ policy.
+
+ The second step is that we want to associate the active agent with the
+ security context so the security policy will know which agent's authentication
+ token to validate against.
+
+ The third step is to set our security policy as the default policy for the
+ Zope security framework. It is possible to create custom security policies at
+ a finer grained than global, but such is left as an exercise for the reader.
+
+
+ Interaction Access
+ ~~~~~~~~~~~~~~~~~~
+
+ The *default* implementation of the interaction management interfaces defines
+ interactions on a per thread basis with a function for an accessor. This
+ model is not appropriate for all systems, as it restricts one to a single
+ active interaction per thread at any given moment. Reimplementing the
+ interaction access methods though is easily doable and is noted here for
+ completeness.
+
+
+ Perspectives
+ ~~~~~~~~~~~~
+
+ It's important to keep in mind that there is a lot more that is possible using
+ the security framework than what's been presented here. All of the
+ interactions are interface based, such that if you need to re-implement the
+ semantics to suite your application a new implementation of the interface will
+ be sufficient. Additional possibilities range from restricted interpreters
+ and dynamic loading of untrusted code to non Zope web application security
+ systems. Insert imagination here ;-).
+
+
+ Zope Perspective
+ ~~~~~~~~~~~~~~~~
+
+ A Zope3 programmer will never commonly need to interact with the low level
+ security framework. Zope3 defines a second security package over top the low
+ level framework and authentication sources and checkers are handled via zcml
+ registration. Still those developing Zope3 will hopefully find this useful as
+ an introduction into the underpinnings of the security framework.
+
+
+ Code
+ ~~~~
+
+ The complete code for this example is available.
+
+ - sandbox.py - the agent framework
+
+ - sandbox_security.py - the security implementation and binding to the agent
+ framework.
+
+
+ Authors
+ ~~~~~~~
+
+ - Kapil Thangavelu <hazmat at objectrealms.net>
+ - Guido Wesdorp <guido at infrae.com>
+ - Marius Gedminas <marius at pov.lt>
+
+
+
+ ======================
+ Untrusted interpreters
+ ======================
+
+ Untrusted programs are executed by untrusted interpreters. Untrusted
+ interpreters make use of security proxies to prevent un-mediated
+ access to assets. An untrusted interpreter defines an environment for
+ running untrusted programs. All objects within the environment are
+ either:
+
+ - "safe" objects created internally by the environment or created in
+ the course of executing the untrusted program, or
+
+ - "basic" objects
+
+ - security-proxied non-basic objects
+
+ The environment includes proxied functions for accessing objects
+ outside of the environment. These proxied functions provide the only
+ way to access information outside the environment. Because these
+ functions are proxied, as described below, any access to objects
+ outside the environment is mediated by the target security functions.
+
+ Safe objects are objects whose operations, except for attribute
+ retrieval, and methods access only information stored within the
+ objects or passed as arguments. Safe objects contained within the
+ interpreter environment can contain only information that is already
+ in the environment or computed directly from information that is
+ included in the environment. For this reason, safe objects created
+ within the environment cannot be used to directly access information
+ outside the environment.
+
+ Safe objects have some attributes that could (very) indirectly be used
+ to access assets. For this reason, an untrusted interpreter always
+ proxies the results of attribute accesses on a safe objects.
+
+ Basic objects are safe objects that are used to represent elemental
+ data values such as strings and numbers. Basic objects require a
+ lower level of protection than non-basic objects, as will be described
+ detail in a later section.
+
+ Security proxies mediate all object operations. Any operation
+ access is checked to see whether a subject is authorized to perform
+ the operation. All operation results other than basic objects are, in
+ turn, security proxied. Security proxies will be described in greater
+ detail in a later section. Any operation on a security proxy that
+ results in a non-basic object is also security proxied.
+
+ All external resources needed to perform an operation are security
+ proxied.
+
+ Let's consider the trusted interpreter for evaluating URLs. In
+ operation 1 of the example, the interpreter uses a proxied method for
+ getting the system root object. Because the method is proxied, the
+ result of calling the method and the operation is also proxied.
+
+ The interpreter has a function for traversing objects. This function
+ is proxied. When traversing an object, the function is passed an
+ object and a name. In operation 2, the function is passed the result
+ of operation 1, which is the proxied root object and the name 'A'. We
+ may traverse an object by invoking an operation on it. For example,
+ we may use an operation to get a sub-object. Because any operation on a
+ proxied object returns a proxied object or a basic object, the result
+ is either a proxied object or a basic object. Traversal may also look
+ up a component. For example, in operation 1, we might look up a
+ presentation component named "A" for the root object. In this case,
+ the external object is not proxied, but, when it is returned from the
+ traversal function, it is proxied (unless it is a a basic object)
+ because the traversal function is proxied, and the result of calling a
+ proxied function is proxied (unless the result is a basic object).
+ Operation 3 proceeds in the same way.
+
+ When we get to operation 4, we use a function for computing the
+ default presentation of the result of operation 3. As with traversal,
+ the result of getting the default presentation is either a proxied
+ object or a basic object because the function for getting the default
+ presentation is proxied.
+
+ When we get to the last operation, we have either a proxied object or a
+ basic object. If the result of operation 4 is a basic object, we
+ simply convert it to a string and return it as the result page. If
+ the result of operation 4 is a non-basic object, we invoke a render
+ operation on it and return the result as a string.
+
+ Note that an untrusted interpreter may or may not provide protection
+ against excessive resource usage. Different interpreters will provide
+ different levels of service with respect to limitations on resource
+ usage.
+
+ If an untrusted interpreter performs an attribute access, the trusted
+ interpreter must proxy the result unless the result is a basic object.
+
+ In summary, an untrusted interpreter assures that any access to assets
+ is mediated through security proxies by creating an environment to run
+ untrusted code and making sure that:
+
+ - The only way to access anything from outside of the environment is
+ to call functions that are proxied in the environment.
+
+ - Results of any attribute access in the environment are proxied
+ unless the results are basic objects.
+
+ Security proxies
+ ----------------
+
+ Security proxies are objects that wrap and mediate access to objects.
+
+ The Python programming language used by Zope defines a set of specific
+ named low-level operations. In addition to operations, Python objects
+ can have attributes, used to represent data and methods. Attributes
+ are accessed using a dot notation. Applications can, and usually do,
+ define methods to provide extended object behaviors. Methods are
+ accessed as attributes through the low-level operation named
+ "__getattribute__". The Python code::
+
+ a.b()
+
+ invokes 2 operations:
+
+ 1. Use the low-level `__getattribute__` operation with the name "b".
+
+ 2. Use the low-level '__call__' operation on the result of the first
+ operation.
+
+ For all operations except the `__getattribute__` and
+ `__setattribute__` operations, security proxies have a permission
+ value defined by the permission-declaration subsystem. Two special
+ permission values indicate that access is either forbidden (never
+ allowed) or public (always allowed). For all other permission values,
+ the authorization subsystem is used to decide whether the subject has
+ the permission for the proxied object. If the subject has the
+ permission, then access to the operation is allowed. Otherwise, access
+ is denied.
+
+ For getting or setting attributes, a proxy has permissions for getting
+ and a permission for setting attribute values for a given attribute
+ name. As described above, these permissions may be one of the two
+ special permission values indicating forbidden or public access, or
+ another permission value that must be checked with the authorization
+ system.
+
+ For all objects, Zope defines the following operations to be always public:
+
+ comparison
+ "__lt__", "__le__", "__eq__", "__gt__", "__ge__", "__ne__"
+
+ hash
+ "__hash__"
+
+ boolean value
+ "__nonzero__"
+
+ class introspection
+ "__class__"
+
+ interface introspection
+ "__providedBy__", "__implements__"
+
+ adaptation
+ "__conform__"
+
+ low-level string representation
+ "__repr__"
+
+ The result of an operation on a proxied object is a security proxy
+ unless the result is a basic value.
+
+ Basic objects
+ -------------
+
+ Basic objects are safe immutable objects that contain only immutable
+ subobjects. Examples of basic objects include:
+
+ - Strings,
+
+ - Integers (long and normal),
+
+ - Floating-point objects,
+
+ - Date-time objects,
+
+ - Boolean objects (True and False), and
+
+ - The special (nil) object, None.
+
+ Basic objects are safe, so, as described earlier, operations on basic
+ objects, other than attribute access, use only information contained
+ within the objects or information passed to them. For this reason,
+ basic objects cannot be used to access information outside of the
+ untrusted interpreter environment.
+
+ The decision not to proxy basic objects is largely an optimization.
+ It allows low-level safe computation to be performed without
+ unnecessary overhead,
+
+ Note that a basic object could contain sensitive information, but such
+ a basic object would need to be obtained by making a call on a proxied
+ object. Therefore, the access to the basic object in the first place
+ is mediated by the security functions.
+
+ Rationale for mutable safe objects
+ ----------------------------------
+
+ Some safe objects are not basic. For these objects, we proxy the
+ objects if they originate from outside of the environment. We do this
+ for two reasons:
+
+ 1. Non-basic objects from outside the environment need to be proxied
+ to prevent unauthorized access to information.
+
+ 2. We need to prevent un-mediated change of information from outside of
+ the environment.
+
+ We don't proxy safe objects created within the environment. This is
+ safe to do because such safe objects can contain and provide access to
+ information already in the environment. Sometimes the interpreter or
+ the interpreted program needs to be able to create simple data
+ containers to hold information computed in the course of the program
+ execution. Several safe container types are provided for this
+ purpose.
+
+
+ =======
+ CHANGES
+ =======
+
+ 3.6.4 (unreleased)
+ ------------------
+
+ - None so far.
+
+ 3.6.3 (2009-03-23)
+ ------------------
+
+ - Ensure that simple zope.schema's VocabularyRegistry is used for
+ PermissionVocabulary tests, because it's replaced implicitly in
+ environments with zope.app.schema installed that makes that tests
+ fail.
+
+ - Fixed a bug in DecoratedSecurityCheckerDescriptor which made
+ security-wrapping location proxied exception instances throw
+ exceptions on Python 2.5.
+ See https://bugs.launchpad.net/zope3/+bug/251848
+
+ 3.6.2 (2009-03-14)
+ ------------------
+
+ - Add zope.i18nmessageid.Message to non-proxied basic types. It's okay, because
+ messages are immutable. It was done by zope.app.security before.
+
+ - Add "__name__" and "__parent__" attributes to list of available by default.
+ This was also done by zope.app.security package before.
+
+ - Added PermissionsVocabulary and PermissionIdsVocabulary vocabularies
+ to the ``zope.security.permission`` module. They were moved from
+ the ``zope.app.security`` package.
+
+ - Add zcml permission definitions for most common and useful permissions,
+ like "zope.View" and "zope.ManageContent", as well as for the special
+ "zope.Public" permission. They are placed in a separate "permissions.zcml"
+ file, so it can be easily excluded/redefined. They are selected part of
+ permissions moved from ``zope.app.security`` and used by many zope.*
+ packages.
+
+ - Add `addCheckerPublic` helper function in ``zope.security.testing`` module
+ that registers the "zope.Public" permission as an IPermission utility.
+
+ - Add security declarations for the ``zope.security.permisson.Permission`` class.
+
+ - Improve test coverage.
+
+ 3.6.1 (2009-03-10)
+ ------------------
+
+ - Use ``from`` imports instead of ``zope.deferred`` to avoid circular
+ import problems, thus drop dependency on ``zope.deferredimport``.
+
+ - Raise NoInteraction when zope.security.checkPermission is called
+ without interaction being active (LP #301565).
+
+ - Don't define security checkers for deprecated set types from the
+ "sets" module on Python 2.6. It's discouraged to use them and
+ `set` and `frozenset` built-in types should be used instead.
+
+ - Change package's mailng list address to zope-dev at zope.org as
+ zope3-dev at zope.org is now retired.
+
+ - Remove old zpkg-related files.
+
+ 3.6.0 (2009-01-31)
+ ------------------
+
+ - Install decorated security checker support on LocationProxy from the
+ outside.
+
+ - Added support to bootstrap on Jython.
+
+ - Moved the `protectclass` module from `zope.app.security` to this
+ package to reduce the number of dependencies on `zope.app.security`.
+
+ - Moved the <module> directive implementation from `zope.app.security`
+ to this package.
+
+ - Moved the <class> directive implementation from `zope.app.component`
+ to this package.
+
+
+ 3.5.2 (2008-07-27)
+ ------------------
+
+ - Made C code compatible with Python 2.5 on 64bit architectures.
+
+
+ 3.5.1 (2008-06-04)
+ ------------------
+
+ - Add `frozenset`, `set`, `reversed`, and `sorted` to the list of safe
+ builtins.
+
+
+ 3.5.0 (2008-03-05)
+ ------------------
+
+ - Changed title for ``zope.security.management.system_user`` to be more
+ presentable.
+
+
+ 3.4.0 (2007-10-02)
+ ------------------
+
+ - Updated meta-data.
+
+
+ 3.4.0b5 (2007-08-15)
+ --------------------
+
+ - Bug: Fixed a circular import in the C implementation.
+
+
+ 3.4.0b4 (2007-08-14)
+ --------------------
+
+ - Bug: ``zope.security.management.system_user`` had an ugly/brittle id.
+
+
+ 3.4.0b3 (2007-08-14)
+ --------------------
+
+ - ``zope.security`` now works on Python 2.5
+
+ - Bug: ``zope.security.management.system_user`` wasn't a valid principal
+ (didn't provide IPrincipal).
+
+ - Bug: Fixed inclusion of doctest to use the doctest module from
+ ``zope.testing``. Now tests can be run multiple times without
+ breaking. (#98250)
+
+
+ 3.4.0b2 (2007-06-15)
+ --------------------
+
+ - Bug: Removed stack extraction in newInteraction. When using eggs this is an
+ extremly expensive function. The publisher is now more than 10 times faster
+ when using eggs and about twice as fast with a zope trunk checkout.
+
+
+ 3.4.0b1
+ -------
+
+ - Temporarily fixed the hidden (and accidental) dependency on zope.testing to
+ become optional.
+
+ Note: The releases between 3.2.0 and 3.4.0b1 where not tracked as an
+ individual package and have been documented in the Zope 3 changelog.
+
+
+ 3.2.0 (2006-01-05)
+ ------------------
+
+ - Corresponds to the verison of the zope.security package shipped as part of
+ the Zope 3.2.0 release.
+
+ - Removed deprecated helper functions, 'proxy.trustedRemoveSecurityProxy' and
+ 'proxy.getProxiedObject'.
+
+ - Made handling of 'management.{end,restore}Interaction' more careful w.r.t.
+ edge cases.
+
+ - Made behavior of 'canWrite' consistent with 'canAccess': if 'canAccess'
+ does not raise 'ForbiddenAttribute', then neither will 'canWrite'. See:
+ http://www.zope.org/Collectors/Zope3-dev/506
+
+ - Code style / documentation / test fixes.
+
+
+ 3.1.0 (2005-10-03)
+ ------------------
+
+ - Added support for use of the new Python 2.4 datatypes, 'set' and
+ 'frozenset', within checked code.
+
+ - C security proxy acquired a dependency on the 'proxy.h' header from the
+ 'zope.proxy' package.
+
+ - XXX: the spelling of the '#include' is bizarre! It seems to be related to
+ 'zpkg'-based builds, and should likely be revisited. For the moment, I have
+ linked in the 'zope.proxy' package into our own 'include' directory. See
+ the subversion checkin: http://svn.zope.org/Zope3/?rev=37882&view=rev
+
+ - Updated checker to avoid re-proxying objects which have and explicit
+ '__Security_checker__' assigned.
+
+ - Corresponds to the verison of the zope.security package shipped as part of
+ the Zope 3.1.0 release.
+
+ - Clarified contract of 'IChecker' to indicate that its 'check*' methods may
+ raise only 'Forbidden' or 'Unauthorized' exceptions.
+
+ - Added interfaces, ('IPrincipal', 'IGroupAwarePrincipal', 'IGroup', and
+ 'IPermission') specifying contracts of components in the security framework.
+
+ - Code style / documentation / test fixes.
+
+
+ 3.0.0 (2004-11-07)
+ ------------------
+
+ - Corresponds to the version of the zope.security package shipped as part of
+ the Zope X3.0.0 release.
+
+Keywords: zope security policy principal permission
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Zope Public License
+Classifier: Programming Language :: Python
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Framework :: Zope3
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/SOURCES.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/SOURCES.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/SOURCES.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,80 @@
+CHANGES.txt
+README.txt
+bootstrap.py
+buildout.cfg
+setup.py
+include/zope.proxy/DEPENDENCIES.cfg
+include/zope.proxy/SETUP.cfg
+include/zope.proxy/__init__.py
+include/zope.proxy/_zope_proxy_proxy.c
+include/zope.proxy/decorator.py
+include/zope.proxy/interfaces.py
+include/zope.proxy/proxy.h
+include/zope.proxy/tests/__init__.py
+include/zope.proxy/tests/test_decorator.py
+include/zope.proxy/tests/test_proxy.py
+src/zope/__init__.py
+src/zope.security.egg-info/PKG-INFO
+src/zope.security.egg-info/SOURCES.txt
+src/zope.security.egg-info/dependency_links.txt
+src/zope.security.egg-info/namespace_packages.txt
+src/zope.security.egg-info/not-zip-safe
+src/zope.security.egg-info/requires.txt
+src/zope.security.egg-info/top_level.txt
+src/zope/security/README.txt
+src/zope/security/__init__.py
+src/zope/security/_definitions.py
+src/zope/security/_proxy.c
+src/zope/security/_zope_security_checker.c
+src/zope/security/adapter.py
+src/zope/security/checker.py
+src/zope/security/configure.zcml
+src/zope/security/decorator.py
+src/zope/security/i18n.py
+src/zope/security/interfaces.py
+src/zope/security/management.py
+src/zope/security/meta.zcml
+src/zope/security/metaconfigure.py
+src/zope/security/metadirectives.py
+src/zope/security/permission.py
+src/zope/security/permissions.zcml
+src/zope/security/protectclass.py
+src/zope/security/proxy.py
+src/zope/security/setup.py
+src/zope/security/simplepolicies.py
+src/zope/security/testing.py
+src/zope/security/untrustedinterpreter.txt
+src/zope/security/zcml.py
+src/zope/security/examples/sandbox.py
+src/zope/security/examples/sandbox_security.py
+src/zope/security/tests/__init__.py
+src/zope/security/tests/adapter.py
+src/zope/security/tests/components.py
+src/zope/security/tests/emptymodule.py
+src/zope/security/tests/exampleclass.py
+src/zope/security/tests/module.py
+src/zope/security/tests/modulehookup.py
+src/zope/security/tests/redefineperms.zcml
+src/zope/security/tests/test_adapter.py
+src/zope/security/tests/test_checker.py
+src/zope/security/tests/test_contentdirective.py
+src/zope/security/tests/test_decorator.py
+src/zope/security/tests/test_directives.py
+src/zope/security/tests/test_location.py
+src/zope/security/tests/test_management.py
+src/zope/security/tests/test_module_directives.py
+src/zope/security/tests/test_permission.py
+src/zope/security/tests/test_protectclass.py
+src/zope/security/tests/test_protectsubclass.py
+src/zope/security/tests/test_proxy.py
+src/zope/security/tests/test_set_checkers.py
+src/zope/security/tests/test_simpleinteraction.py
+src/zope/security/tests/test_standard_checkers.py
+src/zope/security/untrustedpython/__init__.py
+src/zope/security/untrustedpython/builtins.py
+src/zope/security/untrustedpython/builtins.txt
+src/zope/security/untrustedpython/interpreter.py
+src/zope/security/untrustedpython/interpreter.txt
+src/zope/security/untrustedpython/rcompile.py
+src/zope/security/untrustedpython/rcompile.txt
+src/zope/security/untrustedpython/tests.py
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/SOURCES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/dependency_links.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/dependency_links.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/dependency_links.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/dependency_links.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/namespace_packages.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/namespace_packages.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/namespace_packages.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+zope
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/namespace_packages.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/not-zip-safe
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/not-zip-safe (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/not-zip-safe 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/requires.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/requires.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/requires.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1,16 @@
+setuptools
+pytz
+zope.component
+zope.configuration
+zope.exceptions
+zope.i18nmessageid
+zope.interface
+zope.location
+zope.proxy >= 3.4.2
+zope.schema
+
+[test]
+RestrictedPython
+
+[untrustedpython]
+RestrictedPython
\ No newline at end of file
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/requires.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/top_level.txt
===================================================================
--- van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/top_level.txt (rev 0)
+++ van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/top_level.txt 2009-05-26 13:14:01 UTC (rev 100399)
@@ -0,0 +1 @@
+zope
Property changes on: van.pydeb/trunk/van/pydeb/tests/zope.security.egg-info/top_level.txt
___________________________________________________________________
Added: svn:eol-style
+ native
More information about the Checkins
mailing list