zope.configuration-4.0.3/0000775000175000017500000000000012312363233015245 5ustar tseavertseaverzope.configuration-4.0.3/setup.cfg0000664000175000017500000000047312312363233017072 0ustar tseavertseaver[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [nosetests] cover-package = zope.configuration nocapture = 1 cover-erase = 1 ignore-files = (bad|victim|notyet).py with-doctest = 0 where = src [aliases] dev = develop easy_install zope.configuration[testing] docs = easy_install zope.configuration[docs] zope.configuration-4.0.3/buildout.cfg0000664000175000017500000000030212073042162017547 0ustar tseavertseaver[buildout] develop = . parts = test python [test] recipe = zc.recipe.testrunner eggs = zope.configuration [test] [python] recipe = zc.recipe.egg eggs = zope.configuration interpreter = python zope.configuration-4.0.3/PKG-INFO0000664000175000017500000001607512312363233016353 0ustar tseavertseaverMetadata-Version: 1.0 Name: zope.configuration Version: 4.0.3 Summary: Zope Configuration Markup Language (ZCML) Home-page: http://pypi.python.org/pypi/zope.configuration Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: zope.configuration README ========================= The zope configuration system provides an extensible system for supporting various kinds of configurations. It is based on the idea of configuration directives. Users of the configuration system provide configuration directives in some language that express configuration choices. The intent is that the language be pluggable. An XML language is provided by default. Please see http://docs.zope.org/zope.configuration/ for the documentation. zope.configuration Changelog ============================ 4.0.3 (2014-03-19) ------------------ - Added explicit support for Python 3.4. 4.0.2 (2012-12-31) ------------------ - Fleshed out PyPI Trove classifiers. - Removed spurious declaration of 'test' dependency on ``zope.testing``. 4.0.1 (2012-11-21) ------------------ - Added support for Python 3.3. - Removed the deprecated 'zope.configuration.stxdocs' script. and made the 'zope.configuration.tests.conditions' helper module (used in running Sphinx doctest snippets) Py3k compatible. https://bugs.launchpad.net/zope.configuration/+bug/1025390 4.0.0 (2012-05-16) ------------------ - 100% unit test coverage. - Automated build of Sphinx HTML docs and running doctest snippets via tox. - Dropped hard testing dependency on ``zope.testing``. - Added explicit support for PyPy. - Added explicit support for Python 3.2. - Dropped explicit support for Python 2.4 / 2.5. - Added support for continuous integration using ``tox`` and ``jenkins``. - Added ``Sphinx`` documentation. - Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). - Added ``setup.py dev`` alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). 3.8.1 (2012-05-05) ------------------ - Fixed Python 2.4 backwards incompat (itemgetter used with multiple args); Python 2.4 now works (at least if you use zope.schema == 3.8.1). This is the last release which will support Python 2.4 or 2.5. 3.8.0 (2011-12-06) ------------------ - Action structures changed from tuples to dictionaries to allow for action structure extensibility (merged chrism-dictactions branch). 3.7.4 (2011-04-03) ------------------ - Test fixes for Windows. 3.7.3 (2011-03-11) ------------------ - Correctly locate packages with a __path__ attribute but no __file__ attribute (such as namespace packages installed with setup.py install --single-version-externally-managed). - Allow "info" and "includepath" to be passed optionally to context.action. 3.7.2 (2010-04-30) ------------------ - Prefer the standard libraries doctest module over zope.testing.doctest. 3.7.1 (2010-01-05) ------------------ - Jython support: use ``__builtin__`` module import rather than assuming ``__builtins__`` is available. - Jython support: deal with the fact that the Jython SAX parser returns attribute sets that have an empty string indicating no namespace instead of ``None``. - Allow ``setup.py test`` to run at least a subset of the tests that would be run when using the zope testrunner: ``setup.py test`` runs 53 tests, while ``bin/test`` runs 156. 3.7.0 (2009-12-22) ------------------ - Adjust testing output to newer zope.schema. - Prefer zope.testing.doctest over doctestunit. 3.6.0 (2009-04-01) ------------------ - Removed dependency of `zope.deprecation` package. - Don't suppress deprecation warnings any more in 'zope.configuration' package level. This makes it more likely other packages will generate deprecation warnings now, which will allow us to remove more outdated ones. - Don't fail when zope.testing is not installed. - Added missing ``processFile`` method to ``IConfigurationContext``. It is already implemented in the mix-in class, ``zope.configuration.config.ConfigurationContext``, and used by implementations of ``include`` and ``exclude`` directives. 3.5.0 (2009-02-26) ------------------ - Added the ``exclude`` directive to standard directives. It was previously available via ``zc.configuration`` package and now it's merged into ``zope.configuration``. - Changed package's mailing list address to zope-dev at zope.org, change "cheeseshop" to "pypi" in the package's url. 3.4.1 (2008-12-11) ------------------ - Use built-in 'set' type, rather than importin the 'sets' module, which is deprecated in Python 2.6. - Added support to bootstrap on Jython. 3.4.0 (2007-10-02) ------------------ - Initial release as a standalone package. Before 3.4.0 ------------ This package was part of the Zope 3 distribution and did not have its own CHANGES.txt. For earlier changes please refer to either our subversion log or the CHANGES.txt of earlier Zope 3 releases. Keywords: zope configuration zcml 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: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.configuration-4.0.3/tox.ini0000664000175000017500000000215012312122003016542 0ustar tseavertseaver[tox] envlist = # Jython support pending 2.7 support, due 2012-07-15 or so. See: # http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html # py26,py27,py32,jython,pypy,coverage py26,py27,py32,py33,py34,pypy,coverage,docs [testenv] deps = zope.configuration[test] commands = python setup.py test -q [testenv:jython] commands = jython setup.py test -q [testenv:coverage] basepython = python2.6 commands = # The installed version messes up nose's test discovery / coverage reporting # So, we uninstall that from the environment, and then install the editable # version, before running nosetests. pip uninstall -y zope.configuration pip install -e . nosetests --with-xunit --with-xcoverage deps = zope.interface>=3.6.0 zope.event nose coverage nosexcover [testenv:docs] basepython = python2.6 commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest deps = zope.interface>=3.6.0 zope.event Sphinx repoze.sphinx.autointerface zope.configuration-4.0.3/.gitignore0000664000175000017500000000026112167130113017231 0ustar tseavertseaver*.pyc __pycache__ ./.installed.cfg ./bin ./develop-eggs ./eggs ./parts *.egg-info docs/_build .tox .coverage nosetests.xml src/coverage.xml .installed.cfg bin develop-eggs eggs zope.configuration-4.0.3/setup.py0000664000175000017500000001010712312363174016762 0ustar tseavertseaver############################################################################## # # Copyright (c) 2006 Zope Foundation 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. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() def _modname(path, base, name=''): if path == base: return name dirname, basename = os.path.split(path) return _modname(dirname, base, basename + '.' + name) def alltests(): import logging import pkg_resources import unittest class NullHandler(logging.Handler): level = 50 def emit(self, record): pass logging.getLogger().addHandler(NullHandler()) suite = unittest.TestSuite() base = pkg_resources.working_set.find( pkg_resources.Requirement.parse('zope.configuration')).location for dirpath, dirnames, filenames in os.walk(base): if os.path.basename(dirpath) == 'tests': for filename in filenames: if ( filename.endswith('.py') and filename.startswith('test') ): mod = __import__( _modname(dirpath, base, os.path.splitext(filename)[0]), {}, {}, ['*']) suite.addTest(mod.test_suite()) return suite TESTS_REQUIRE = [] setup(name='zope.configuration', version = '4.0.3', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description='Zope Configuration Markup Language (ZCML)', long_description=( read('README.rst') + '\n\n' + read('CHANGES.rst') ), keywords = "zope configuration zcml", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', "Programming Language :: Python :: 2", 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', "Programming Language :: Python :: 3", 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Framework :: Zope3'], url='http://pypi.python.org/pypi/zope.configuration', license='ZPL 2.1', packages=find_packages('src'), package_dir={'': 'src'}, namespace_packages=['zope'], extras_require={ 'docs': ['Sphinx', 'repoze.sphinx.autointerface'], 'test': [], 'testing': TESTS_REQUIRE + ['nose', 'coverage'], }, install_requires=['zope.i18nmessageid', 'zope.interface', 'zope.schema', 'setuptools', ], include_package_data=True, zip_safe=False, tests_require = TESTS_REQUIRE, test_suite='__main__.alltests', ) zope.configuration-4.0.3/bootstrap.py0000664000175000017500000001306612167130034017641 0ustar tseavertseaver############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os import shutil import sys import tempfile from optparse import OptionParser tmpeggs = tempfile.mkdtemp() usage = '''\ [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] Bootstraps a buildout-based project. Simply run this script in a directory containing a buildout.cfg, using the Python that you want bin/buildout to use. Note that by using --find-links to point to local resources, you can keep this script from going over the network. ''' parser = OptionParser(usage=usage) parser.add_option("-v", "--version", help="use a specific zc.buildout version") parser.add_option("-t", "--accept-buildout-test-releases", dest='accept_buildout_test_releases', action="store_true", default=False, help=("Normally, if you do not specify a --version, the " "bootstrap script and buildout gets the newest " "*final* versions of zc.buildout and its recipes and " "extensions for you. If you use this flag, " "bootstrap and buildout will get the newest releases " "even if they are alphas or betas.")) parser.add_option("-c", "--config-file", help=("Specify the path to the buildout configuration " "file to be used.")) parser.add_option("-f", "--find-links", help=("Specify a URL to search for buildout releases")) options, args = parser.parse_args() ###################################################################### # load/install setuptools to_reload = False try: import pkg_resources import setuptools except ImportError: ez = {} try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen # XXX use a more permanent ez_setup.py URL when available. exec(urlopen('https://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py' ).read(), ez) setup_args = dict(to_dir=tmpeggs, download_delay=0) ez['use_setuptools'](**setup_args) if to_reload: reload(pkg_resources) import pkg_resources # This does not (always?) update the default working set. We will # do it. for path in sys.path: if path not in pkg_resources.working_set.entries: pkg_resources.working_set.add_entry(path) ###################################################################### # Install buildout ws = pkg_resources.working_set cmd = [sys.executable, '-c', 'from setuptools.command.easy_install import main; main()', '-mZqNxd', tmpeggs] find_links = os.environ.get( 'bootstrap-testing-find-links', options.find_links or ('http://downloads.buildout.org/' if options.accept_buildout_test_releases else None) ) if find_links: cmd.extend(['-f', find_links]) setuptools_path = ws.find( pkg_resources.Requirement.parse('setuptools')).location requirement = 'zc.buildout' version = options.version if version is None and not options.accept_buildout_test_releases: # Figure out the most recent final version of zc.buildout. import setuptools.package_index _final_parts = '*final-', '*final' def _final_version(parsed_version): for part in parsed_version: if (part[:1] == '*') and (part not in _final_parts): return False return True index = setuptools.package_index.PackageIndex( search_path=[setuptools_path]) if find_links: index.add_find_links((find_links,)) req = pkg_resources.Requirement.parse(requirement) if index.obtain(req) is not None: best = [] bestv = None for dist in index[req.project_name]: distv = dist.parsed_version if _final_version(distv): if bestv is None or distv > bestv: best = [dist] bestv = distv elif distv == bestv: best.append(dist) if best: best.sort() version = best[-1].version if version: requirement = '=='.join((requirement, version)) cmd.append(requirement) import subprocess if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0: raise Exception( "Failed to execute command:\n%s", repr(cmd)[1:-1]) ###################################################################### # Import and run buildout ws.add_entry(tmpeggs) ws.require(requirement) import zc.buildout.buildout if not [a for a in args if '=' not in a]: args.append('bootstrap') # if -c was provided, we push it back into args for buildout' main function if options.config_file is not None: args[0:0] = ['-c', options.config_file] zc.buildout.buildout.main(args) shutil.rmtree(tmpeggs) zope.configuration-4.0.3/.travis.yml0000664000175000017500000000027512167130027017363 0ustar tseavertseaverlanguage: python python: - 2.6 - 2.7 - 3.2 - 3.3 - pypy install: - pip install . --use-mirrors script: - python setup.py test -q notifications: email: false zope.configuration-4.0.3/src/0000775000175000017500000000000012312363233016034 5ustar tseavertseaverzope.configuration-4.0.3/src/zope.configuration.egg-info/0000775000175000017500000000000012312363233023351 5ustar tseavertseaverzope.configuration-4.0.3/src/zope.configuration.egg-info/top_level.txt0000664000175000017500000000000512312363233026076 0ustar tseavertseaverzope zope.configuration-4.0.3/src/zope.configuration.egg-info/SOURCES.txt0000664000175000017500000001342512312363233025242 0ustar tseavertseaver.gitignore .travis.yml CHANGES.rst COPYRIGHT.txt LICENSE.txt MANIFEST.in README.rst bootstrap.py buildout.cfg setup.cfg setup.py tox.ini docs/Makefile docs/api.rst docs/conf.py docs/hacking.rst docs/index.rst docs/make.bat docs/narr.rst docs/_build/doctest/output.txt docs/_build/doctrees/api.doctree docs/_build/doctrees/environment.pickle docs/_build/doctrees/hacking.doctree docs/_build/doctrees/index.doctree docs/_build/doctrees/narr.doctree docs/_build/doctrees/api/config.doctree docs/_build/doctrees/api/docutils.doctree docs/_build/doctrees/api/exceptions.doctree docs/_build/doctrees/api/fields.doctree docs/_build/doctrees/api/interfaces.doctree docs/_build/doctrees/api/name.doctree docs/_build/doctrees/api/xmlconfig.doctree docs/_build/doctrees/api/zopeconfigure.doctree docs/_build/html/.buildinfo docs/_build/html/api.html docs/_build/html/genindex.html docs/_build/html/hacking.html docs/_build/html/index.html docs/_build/html/narr.html docs/_build/html/objects.inv docs/_build/html/py-modindex.html docs/_build/html/search.html docs/_build/html/searchindex.js docs/_build/html/_modules/index.html docs/_build/html/_modules/zope/configuration/config.html docs/_build/html/_modules/zope/configuration/docutils.html docs/_build/html/_modules/zope/configuration/exceptions.html docs/_build/html/_modules/zope/configuration/fields.html docs/_build/html/_modules/zope/configuration/interfaces.html docs/_build/html/_modules/zope/configuration/name.html docs/_build/html/_modules/zope/configuration/xmlconfig.html docs/_build/html/_modules/zope/configuration/zopeconfigure.html docs/_build/html/_sources/api.txt docs/_build/html/_sources/hacking.txt docs/_build/html/_sources/index.txt docs/_build/html/_sources/narr.txt docs/_build/html/_sources/api/config.txt docs/_build/html/_sources/api/docutils.txt docs/_build/html/_sources/api/exceptions.txt docs/_build/html/_sources/api/fields.txt docs/_build/html/_sources/api/interfaces.txt docs/_build/html/_sources/api/name.txt docs/_build/html/_sources/api/xmlconfig.txt docs/_build/html/_sources/api/zopeconfigure.txt docs/_build/html/_static/ajax-loader.gif docs/_build/html/_static/basic.css docs/_build/html/_static/comment-bright.png docs/_build/html/_static/comment-close.png docs/_build/html/_static/comment.png docs/_build/html/_static/default.css docs/_build/html/_static/doctools.js docs/_build/html/_static/down-pressed.png docs/_build/html/_static/down.png docs/_build/html/_static/file.png docs/_build/html/_static/jquery.js docs/_build/html/_static/minus.png docs/_build/html/_static/plus.png docs/_build/html/_static/pygments.css docs/_build/html/_static/searchtools.js docs/_build/html/_static/sidebar.js docs/_build/html/_static/underscore.js docs/_build/html/_static/up-pressed.png docs/_build/html/_static/up.png docs/_build/html/_static/websupport.js docs/_build/html/api/config.html docs/_build/html/api/docutils.html docs/_build/html/api/exceptions.html docs/_build/html/api/fields.html docs/_build/html/api/interfaces.html docs/_build/html/api/name.html docs/_build/html/api/xmlconfig.html docs/_build/html/api/zopeconfigure.html docs/api/config.rst docs/api/docutils.rst docs/api/exceptions.rst docs/api/fields.rst docs/api/interfaces.rst docs/api/name.rst docs/api/xmlconfig.rst docs/api/zopeconfigure.rst src/coverage.xml src/zope/__init__.py src/zope.configuration.egg-info/PKG-INFO src/zope.configuration.egg-info/SOURCES.txt src/zope.configuration.egg-info/dependency_links.txt src/zope.configuration.egg-info/namespace_packages.txt src/zope.configuration.egg-info/not-zip-safe src/zope.configuration.egg-info/requires.txt src/zope.configuration.egg-info/top_level.txt src/zope/configuration/__init__.py src/zope/configuration/_compat.py src/zope/configuration/config.py src/zope/configuration/docutils.py src/zope/configuration/exceptions.py src/zope/configuration/fields.py src/zope/configuration/interfaces.py src/zope/configuration/name.py src/zope/configuration/xmlconfig.py src/zope/configuration/zopeconfigure.py src/zope/configuration/tests/__init__.py src/zope/configuration/tests/bad.py src/zope/configuration/tests/conditions.py src/zope/configuration/tests/conditions.zcml src/zope/configuration/tests/directives.py src/zope/configuration/tests/nested.py src/zope/configuration/tests/notyet.py src/zope/configuration/tests/sample.zcml src/zope/configuration/tests/schema.zcml src/zope/configuration/tests/simple.py src/zope/configuration/tests/simple.zcml src/zope/configuration/tests/test___init__.py src/zope/configuration/tests/test_config.py src/zope/configuration/tests/test_docutils.py src/zope/configuration/tests/test_fields.py src/zope/configuration/tests/test_name.py src/zope/configuration/tests/test_xmlconfig.py src/zope/configuration/tests/test_zopeconfigure.py src/zope/configuration/tests/victim.py src/zope/configuration/tests/excludedemo/__init__.py src/zope/configuration/tests/excludedemo/configure.zcml src/zope/configuration/tests/excludedemo/spam.zcml src/zope/configuration/tests/excludedemo/sub/__init__.py src/zope/configuration/tests/excludedemo/sub/configure.zcml src/zope/configuration/tests/samplepackage/NamedForClass.py src/zope/configuration/tests/samplepackage/__init__.py src/zope/configuration/tests/samplepackage/bar.zcml src/zope/configuration/tests/samplepackage/bar1.zcml src/zope/configuration/tests/samplepackage/bar2.zcml src/zope/configuration/tests/samplepackage/bar21.zcml src/zope/configuration/tests/samplepackage/baro.zcml src/zope/configuration/tests/samplepackage/baro2.zcml src/zope/configuration/tests/samplepackage/baz1.zcml src/zope/configuration/tests/samplepackage/baz2.zcml src/zope/configuration/tests/samplepackage/baz3.zcml src/zope/configuration/tests/samplepackage/configure.zcml src/zope/configuration/tests/samplepackage/configure.zcml.in src/zope/configuration/tests/samplepackage/foo.py src/zope/configuration/tests/samplepackage/foo.zcml.inzope.configuration-4.0.3/src/zope.configuration.egg-info/PKG-INFO0000664000175000017500000001607512312363233024457 0ustar tseavertseaverMetadata-Version: 1.0 Name: zope.configuration Version: 4.0.3 Summary: Zope Configuration Markup Language (ZCML) Home-page: http://pypi.python.org/pypi/zope.configuration Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: zope.configuration README ========================= The zope configuration system provides an extensible system for supporting various kinds of configurations. It is based on the idea of configuration directives. Users of the configuration system provide configuration directives in some language that express configuration choices. The intent is that the language be pluggable. An XML language is provided by default. Please see http://docs.zope.org/zope.configuration/ for the documentation. zope.configuration Changelog ============================ 4.0.3 (2014-03-19) ------------------ - Added explicit support for Python 3.4. 4.0.2 (2012-12-31) ------------------ - Fleshed out PyPI Trove classifiers. - Removed spurious declaration of 'test' dependency on ``zope.testing``. 4.0.1 (2012-11-21) ------------------ - Added support for Python 3.3. - Removed the deprecated 'zope.configuration.stxdocs' script. and made the 'zope.configuration.tests.conditions' helper module (used in running Sphinx doctest snippets) Py3k compatible. https://bugs.launchpad.net/zope.configuration/+bug/1025390 4.0.0 (2012-05-16) ------------------ - 100% unit test coverage. - Automated build of Sphinx HTML docs and running doctest snippets via tox. - Dropped hard testing dependency on ``zope.testing``. - Added explicit support for PyPy. - Added explicit support for Python 3.2. - Dropped explicit support for Python 2.4 / 2.5. - Added support for continuous integration using ``tox`` and ``jenkins``. - Added ``Sphinx`` documentation. - Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). - Added ``setup.py dev`` alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). 3.8.1 (2012-05-05) ------------------ - Fixed Python 2.4 backwards incompat (itemgetter used with multiple args); Python 2.4 now works (at least if you use zope.schema == 3.8.1). This is the last release which will support Python 2.4 or 2.5. 3.8.0 (2011-12-06) ------------------ - Action structures changed from tuples to dictionaries to allow for action structure extensibility (merged chrism-dictactions branch). 3.7.4 (2011-04-03) ------------------ - Test fixes for Windows. 3.7.3 (2011-03-11) ------------------ - Correctly locate packages with a __path__ attribute but no __file__ attribute (such as namespace packages installed with setup.py install --single-version-externally-managed). - Allow "info" and "includepath" to be passed optionally to context.action. 3.7.2 (2010-04-30) ------------------ - Prefer the standard libraries doctest module over zope.testing.doctest. 3.7.1 (2010-01-05) ------------------ - Jython support: use ``__builtin__`` module import rather than assuming ``__builtins__`` is available. - Jython support: deal with the fact that the Jython SAX parser returns attribute sets that have an empty string indicating no namespace instead of ``None``. - Allow ``setup.py test`` to run at least a subset of the tests that would be run when using the zope testrunner: ``setup.py test`` runs 53 tests, while ``bin/test`` runs 156. 3.7.0 (2009-12-22) ------------------ - Adjust testing output to newer zope.schema. - Prefer zope.testing.doctest over doctestunit. 3.6.0 (2009-04-01) ------------------ - Removed dependency of `zope.deprecation` package. - Don't suppress deprecation warnings any more in 'zope.configuration' package level. This makes it more likely other packages will generate deprecation warnings now, which will allow us to remove more outdated ones. - Don't fail when zope.testing is not installed. - Added missing ``processFile`` method to ``IConfigurationContext``. It is already implemented in the mix-in class, ``zope.configuration.config.ConfigurationContext``, and used by implementations of ``include`` and ``exclude`` directives. 3.5.0 (2009-02-26) ------------------ - Added the ``exclude`` directive to standard directives. It was previously available via ``zc.configuration`` package and now it's merged into ``zope.configuration``. - Changed package's mailing list address to zope-dev at zope.org, change "cheeseshop" to "pypi" in the package's url. 3.4.1 (2008-12-11) ------------------ - Use built-in 'set' type, rather than importin the 'sets' module, which is deprecated in Python 2.6. - Added support to bootstrap on Jython. 3.4.0 (2007-10-02) ------------------ - Initial release as a standalone package. Before 3.4.0 ------------ This package was part of the Zope 3 distribution and did not have its own CHANGES.txt. For earlier changes please refer to either our subversion log or the CHANGES.txt of earlier Zope 3 releases. Keywords: zope configuration zcml 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: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.configuration-4.0.3/src/zope.configuration.egg-info/dependency_links.txt0000664000175000017500000000000112312363233027417 0ustar tseavertseaver zope.configuration-4.0.3/src/zope.configuration.egg-info/not-zip-safe0000664000175000017500000000000112073042570025601 0ustar tseavertseaver zope.configuration-4.0.3/src/zope.configuration.egg-info/namespace_packages.txt0000664000175000017500000000000512312363233027677 0ustar tseavertseaverzope zope.configuration-4.0.3/src/zope.configuration.egg-info/requires.txt0000664000175000017500000000020512312363233025746 0ustar tseavertseaverzope.i18nmessageid zope.interface zope.schema setuptools [test] [docs] Sphinx repoze.sphinx.autointerface [testing] nose coveragezope.configuration-4.0.3/src/coverage.xml0000664000175000017500000010672012073042765020367 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/0000775000175000017500000000000012312363233017011 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/__init__.py0000664000175000017500000000007012073042162021116 0ustar tseavertseaver__import__('pkg_resources').declare_namespace(__name__) zope.configuration-4.0.3/src/zope/configuration/0000775000175000017500000000000012312363233021660 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/configuration/name.py0000664000175000017500000000472612073042162023162 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation 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. # ############################################################################## """Provide configuration object name resolution """ import os from types import ModuleType def resolve(name, package='zopeproducts', _silly=('__doc__',), _globals={}): name = name.strip() if name.startswith('.'): name = package + name if name.endswith('.') or name.endswith('+'): name = name[:-1] repeat = True else: repeat = False names = name.split('.') last = names[-1] mod = '.'.join(names[:-1]) if not mod: return __import__(name, _globals, _globals, _silly) while 1: m = __import__(mod, _globals, _globals, _silly) try: a = getattr(m, last) except AttributeError: if not repeat: return __import__(name, _globals, _globals, _silly) else: if not repeat or (not isinstance(a, ModuleType)): return a mod += '.' + last def getNormalizedName(name, package): name = name.strip() if name.startswith('.'): name = package + name if name.endswith('.') or name.endswith('+'): name = name[:-1] repeat = True else: repeat = False name = name.split(".") while len(name) > 1 and name[-1] == name[-2]: name.pop() repeat = 1 name = ".".join(name) if repeat: name += "+" return name def path(file='', package='zopeproducts', _silly=('__doc__',), _globals={}): # XXX WTF? why not look for abspath before importing? try: package = __import__(package, _globals, _globals, _silly) except ImportError: norm = os.path.normpath(file) if file and os.path.abspath(norm) == norm: # The package didn't matter return norm raise path = os.path.dirname(package.__file__) if file: path = os.path.join(path, file) return path zope.configuration-4.0.3/src/zope/configuration/fields.py0000664000175000017500000001302412073042162023477 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Configuration-specific schema fields """ import os import re import warnings from zope.interface import implementer from zope.schema import Bool as schema_Bool from zope.schema import Field from zope.schema import InterfaceField from zope.schema import List from zope.schema import Text from zope.schema import TextLine from zope.schema import ValidationError from zope.schema.interfaces import IFromUnicode from zope.configuration.exceptions import ConfigurationError from zope.configuration.interfaces import InvalidToken from zope.configuration._compat import u PYIDENTIFIER_REGEX = u('\\A[a-zA-Z_]+[a-zA-Z0-9_]*\\Z') pyidentifierPattern = re.compile(PYIDENTIFIER_REGEX) @implementer(IFromUnicode) class PythonIdentifier(TextLine): """This field describes a python identifier, i.e. a variable name. """ def fromUnicode(self, u): return u.strip() def _validate(self, value): super(PythonIdentifier, self)._validate(value) if pyidentifierPattern.match(value) is None: raise ValidationError(value) @implementer(IFromUnicode) class GlobalObject(Field): """An object that can be accessed as a module global. """ def __init__(self, value_type=None, **kw): self.value_type = value_type super(GlobalObject, self).__init__(**kw) def _validate(self, value): super(GlobalObject, self)._validate(value) if self.value_type is not None: self.value_type.validate(value) def fromUnicode(self, u): name = str(u.strip()) # special case, mostly for interfaces if name == '*': return None try: value = self.context.resolve(name) except ConfigurationError as v: raise ValidationError(v) self.validate(value) return value @implementer(IFromUnicode) class GlobalInterface(GlobalObject): """An interface that can be accessed from a module. """ def __init__(self, **kw): super(GlobalInterface, self).__init__(InterfaceField(), **kw) @implementer(IFromUnicode) class Tokens(List): """A list that can be read from a space-separated string. """ def fromUnicode(self, u): u = u.strip() if u: vt = self.value_type.bind(self.context) values = [] for s in u.split(): try: v = vt.fromUnicode(s) except ValidationError as v: raise InvalidToken("%s in %s" % (v, u)) else: values.append(v) else: values = [] self.validate(values) return values @implementer(IFromUnicode) class Path(Text): """A file path name, which may be input as a relative path Input paths are converted to absolute paths and normalized. """ def fromUnicode(self, u): u = u.strip() if os.path.isabs(u): return os.path.normpath(u) return self.context.path(u) @implementer(IFromUnicode) class Bool(schema_Bool): """A boolean value Values may be input (in upper or lower case) as any of: yes, no, y, n, true, false, t, or f. """ def fromUnicode(self, u): u = u.lower() if u in ('1', 'true', 'yes', 't', 'y'): return True if u in ('0', 'false', 'no', 'f', 'n'): return False raise ValidationError @implementer(IFromUnicode) class MessageID(Text): """Text string that should be translated. When a string is converted to a message ID, it is also recorded in the context. """ __factories = {} def fromUnicode(self, u): context = self.context domain = getattr(context, 'i18n_domain', '') if not domain: domain = 'untranslated' warnings.warn( "You did not specify an i18n translation domain for the "\ "'%s' field in %s" % (self.getName(), context.info.file ) ) v = super(MessageID, self).fromUnicode(u) # Check whether there is an explicit message is specified default = None if v.startswith('[]'): v = v[2:].lstrip() elif v.startswith('['): end = v.find(']') default = v[end+2:] v = v[1:end] # Convert to a message id, importing the factory, if necessary factory = self.__factories.get(domain) if factory is None: import zope.i18nmessageid factory = zope.i18nmessageid.MessageFactory(domain) self.__factories[domain] = factory msgid = factory(v, default) # Record the string we got for the domain i18n_strings = context.i18n_strings strings = i18n_strings.get(domain) if strings is None: strings = i18n_strings[domain] = {} locations = strings.setdefault(msgid, []) locations.append((context.info.file, context.info.line)) return msgid zope.configuration-4.0.3/src/zope/configuration/xmlconfig.py0000664000175000017500000004410512073042162024223 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002, 2003 Zope Foundation 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. # ############################################################################## """Support for the XML configuration file format Note, for a detailed description of the way that conflicting configuration actions are resolved, see the detailed example in test_includeOverrides in tests/test_xmlconfig.py """ __docformat__ = 'restructuredtext' import errno from glob import glob import logging import os import sys from xml.sax import make_parser from xml.sax.xmlreader import InputSource from xml.sax.handler import ContentHandler, feature_namespaces from xml.sax import SAXParseException from zope.interface import Interface from zope.schema import NativeStringLine from zope.configuration.config import ConfigurationMachine from zope.configuration.config import defineGroupingDirective from zope.configuration.config import defineSimpleDirective from zope.configuration.config import GroupingContextDecorator from zope.configuration.config import GroupingStackItem from zope.configuration.config import resolveConflicts from zope.configuration.exceptions import ConfigurationError from zope.configuration.fields import GlobalObject from zope.configuration.zopeconfigure import IZopeConfigure from zope.configuration.zopeconfigure import ZopeConfigure from zope.configuration._compat import StringIO from zope.configuration._compat import reraise from zope.configuration._compat import u logger = logging.getLogger("config") ZCML_NAMESPACE = "http://namespaces.zope.org/zcml" ZCML_CONDITION = (ZCML_NAMESPACE, u("condition")) class ZopeXMLConfigurationError(ConfigurationError): """Zope XML Configuration error These errors are wrappers for other errors. They include configuration info and the wrapped error type and value. """ def __init__(self, info, etype, evalue): self.info, self.etype, self.evalue = info, etype, evalue def __str__(self): # Only use the repr of the info. This is because we expect to # get a parse info and we only want the location information. return "%s\n %s: %s" % ( repr(self.info), self.etype.__name__, self.evalue) class ZopeSAXParseException(ConfigurationError): """Sax Parser errors, reformatted in an emacs friendly way """ def __init__(self, v): self._v = v def __str__(self): v = self._v s = tuple(str(v).split(':')) if len(s) == 4: return 'File "%s", line %s.%s, %s' % s else: return str(v) class ParserInfo(object): """Information about a directive based on parser data This includes the directive location, as well as text data contained in the directive. """ text = u('') def __init__(self, file, line, column): self.file, self.line, self.column = file, line, column self.eline, self.ecolumn = line, column def end(self, line, column): self.eline, self.ecolumn = line, column def __repr__(self): if (self.line, self.column) == (self.eline, self.ecolumn): return 'File "%s", line %s.%s' % ( self.file, self.line, self.column) return 'File "%s", line %s.%s-%s.%s' % ( self.file, self.line, self.column, self.eline, self.ecolumn) def __str__(self): if (self.line, self.column) == (self.eline, self.ecolumn): return 'File "%s", line %s.%s' % ( self.file, self.line, self.column) file = self.file if file == 'tests//sample.zcml': # special case for testing file = os.path.join(os.path.dirname(__file__), 'tests', 'sample.zcml') try: with open(file) as f: lines = f.readlines()[self.line-1:self.eline] except IOError: src = " Could not read source." else: ecolumn = self.ecolumn if lines[-1][ecolumn:ecolumn+2] == '', ecolumn) if l >= 0: lines[-1] = lines[-1][:l+1] else: #pragma NO COVER lines[-1] = lines[-1][:ecolumn+1] column = self.column if lines[0][:column].strip(): #pragma NO COVER # Remove text before start if it's noy whitespace lines[0] = lines[0][self.column:] pad = u(' ') blank = u('') try: src = blank.join([pad + l for l in lines]) except UnicodeDecodeError: #pragma NO COVER # XXX: # I hope so most internation zcml will use UTF-8 as encoding # otherwise this code must be made more clever src = blank.join([pad + l.decode('utf-8') for l in lines]) # unicode won't be printable, at least on my console src = src.encode('ascii','replace') return "%s\n%s" % (repr(self), src) def characters(self, characters): self.text += characters class ConfigurationHandler(ContentHandler): """Interface to the xml parser Translate parser events into calls into the configuration system. """ locator = None def __init__(self, context, testing=False): self.context = context self.testing = testing self.ignore_depth = 0 def setDocumentLocator(self, locator): self.locator = locator def characters(self, text): self.context.getInfo().characters(text) def startElementNS(self, name, qname, attrs): if self.ignore_depth: self.ignore_depth += 1 return data = {} for (ns, aname), value in attrs.items(): # NB: even though on CPython, 'ns' will be ``None`` always, # do not change the below to "if ns is None" because Jython's # sax parser generates attrs that have empty strings for # the namepace instead of ``None``. if not ns: aname = str(aname) data[aname] = value if (ns, aname) == ZCML_CONDITION: # need to process the expression to determine if we # use this element and it's descendents use = self.evaluateCondition(value) if not use: self.ignore_depth = 1 return info = ParserInfo( self.locator.getSystemId(), self.locator.getLineNumber(), self.locator.getColumnNumber(), ) try: self.context.begin(name, data, info) except (KeyboardInterrupt, SystemExit): #pragma NO COVER raise except: if self.testing: raise reraise(ZopeXMLConfigurationError(info, sys.exc_info()[0], sys.exc_info()[1]), None, sys.exc_info()[2]) self.context.setInfo(info) def evaluateCondition(self, expression): """Evaluate a ZCML condition. ``expression`` is a string of the form "verb arguments". Currently the supported verbs are ``have``, ``not-have``, ``installed`` and ``not-installed``. """ arguments = expression.split(None) verb = arguments.pop(0) if verb in ('have', 'not-have'): if not arguments: raise ValueError("Feature name missing: %r" % expression) if len(arguments) > 1: raise ValueError("Only one feature allowed: %r" % expression) if verb == 'have': return self.context.hasFeature(arguments[0]) elif verb == 'not-have': return not self.context.hasFeature(arguments[0]) elif verb in ('installed', 'not-installed'): if not arguments: raise ValueError("Package name missing: %r" % expression) if len(arguments) > 1: raise ValueError("Only one package allowed: %r" % expression) try: __import__(arguments[0]) installed = True except ImportError: installed = False if verb == 'installed': return installed elif verb == 'not-installed': return not installed else: raise ValueError("Invalid ZCML condition: %r" % expression) def endElementNS(self, name, qname): # If ignore_depth is set, this element will be ignored, even # if this this decrements ignore_depth to 0. if self.ignore_depth: self.ignore_depth -= 1 return info = self.context.getInfo() info.end( self.locator.getLineNumber(), self.locator.getColumnNumber(), ) try: self.context.end() except (KeyboardInterrupt, SystemExit): #pragma NO COVER raise except: if self.testing: raise reraise(ZopeXMLConfigurationError(info, sys.exc_info()[0], sys.exc_info()[1]), None, sys.exc_info()[2]) def processxmlfile(file, context, testing=False): """Process a configuration file See examples in tests/text_xmlconfig.py """ src = InputSource(getattr(file, 'name', '')) src.setByteStream(file) parser = make_parser() parser.setContentHandler(ConfigurationHandler(context, testing=testing)) parser.setFeature(feature_namespaces, True) try: parser.parse(src) except SAXParseException: reraise(ZopeSAXParseException(sys.exc_info()[1]), None, sys.exc_info()[2]) def openInOrPlain(filename): """Open a file, falling back to filename.in. If the requested file does not exist and filename.in does, fall back to filename.in. If opening the original filename fails for any other reason, allow the failure to propogate. """ try: return open(filename) except IOError as e: code, msg = e.args if code == errno.ENOENT: fn = filename + ".in" if os.path.exists(fn): return open(fn) raise class IInclude(Interface): """The ``include``, ``includeOverrides`` and ``exclude`` directives These directives allows you to include or preserve including of another ZCML file in the configuration. This enables you to write configuration files in each package and then link them together. """ file = NativeStringLine( title=u("Configuration file name"), description=u("The name of a configuration file to be included/" "excluded, relative to the directive containing the " "including configuration file."), required=False, ) files = NativeStringLine( title=u("Configuration file name pattern"), description=u(""" The names of multiple configuration files to be included/excluded, expressed as a file-name pattern, relative to the directive containing the including or excluding configuration file. The pattern can include: - ``*`` matches 0 or more characters - ``?`` matches a single character - ``[]`` matches any character in seq - ``[!]`` matches any character not in seq The file names are included in sorted order, where sorting is without regard to case. """), required=False, ) package = GlobalObject( title=u("Include or exclude package"), description=u(""" Include or exclude the named file (or configure.zcml) from the directory of this package. """), required=False, ) def include(_context, file=None, package=None, files=None): """Include a zcml file See examples in tests/text_xmlconfig.py """ if files: if file: raise ValueError("Must specify only one of file or files") elif not file: file = 'configure.zcml' # This is a tad tricky. We want to behave as a grouping directive. context = GroupingContextDecorator(_context) if package is not None: context.package = package context.basepath = None if files: paths = glob(context.path(files)) paths = sorted(zip([path.lower() for path in paths], paths)) paths = [path for (l, path) in paths] else: paths = [context.path(file)] for path in paths: if context.processFile(path): with openInOrPlain(path) as f: logger.debug("include %s" % f.name) context.basepath = os.path.dirname(path) context.includepath = _context.includepath + (f.name, ) _context.stack.append(GroupingStackItem(context)) processxmlfile(f, context) assert _context.stack[-1].context is context _context.stack.pop() def exclude(_context, file=None, package=None, files=None): """Exclude a zcml file This directive should be used before any ZML that includes configuration you want to exclude. """ if files: if file: raise ValueError("Must specify only one of file or files") elif not file: file = 'configure.zcml' context = GroupingContextDecorator(_context) if package is not None: context.package = package context.basepath = None if files: paths = glob(context.path(files)) paths = sorted(zip([path.lower() for path in paths], paths)) paths = [path for (l, path) in paths] else: paths = [context.path(file)] for path in paths: # processFile returns a boolean indicating if the file has been # processed or not, it *also* marks the file as having been processed, # here the side effect is used to keep the given file from being # processed in the future context.processFile(path) def includeOverrides(_context, file=None, package=None, files=None): """Include zcml file containing overrides The actions in the included file are added to the context as if they were in the including file directly. See the detailed example in test_includeOverrides in tests/text_xmlconfig.py """ # We need to remember how many actions we had before nactions = len(_context.actions) # We'll give the new actions this include path includepath = _context.includepath # Now we'll include the file. We'll munge the actions after include(_context, file, package, files) # Now we'll grab the new actions, resolve conflicts, # and munge the includepath: newactions = [] for action in resolveConflicts(_context.actions[nactions:]): action['includepath'] = includepath newactions.append(action) _context.actions[nactions:] = newactions def registerCommonDirectives(context): # We have to use the direct definition functions to define # a directive for all namespaces. defineSimpleDirective( context, "include", IInclude, include, namespace="*") defineSimpleDirective( context, "exclude", IInclude, exclude, namespace="*") defineSimpleDirective( context, "includeOverrides", IInclude, includeOverrides, namespace="*") defineGroupingDirective( context, name="configure", namespace="*", schema=IZopeConfigure, handler=ZopeConfigure, ) def file(name, package=None, context=None, execute=True): """Execute a zcml file """ if context is None: context = ConfigurationMachine() registerCommonDirectives(context) context.package = package include(context, name, package) if execute: context.execute_actions() return context def string(s, context=None, name="", execute=True): """Execute a zcml string """ if context is None: context = ConfigurationMachine() registerCommonDirectives(context) f = StringIO(s) f.name = name processxmlfile(f, context) if execute: context.execute_actions() return context ############################################################################## # Backward compatability, mainly for tests _context = None def _clearContext(): global _context _context = ConfigurationMachine() registerCommonDirectives(_context) def _getContext(): global _context if _context is None: _clearContext() try: from zope.testing.cleanup import addCleanUp except ImportError: #pragma NO COVER pass else: #pragma NO COVER addCleanUp(_clearContext) del addCleanUp return _context class XMLConfig(object): """Provide high-level handling of configuration files. See examples in tests/text_xmlconfig.py """ def __init__(self, file_name, module=None): context = _getContext() include(context, file_name, module) self.context = context def __call__(self): self.context.execute_actions() def xmlconfig(file, testing=False): context = _getContext() processxmlfile(file, context, testing=testing) context.execute_actions(testing=testing) def testxmlconfig(file): """xmlconfig that doesn't raise configuration errors This is useful for testing, as it doesn't mask exception types. """ context = _getContext() processxmlfile(file, context, testing=True) context.execute_actions(testing=True) zope.configuration-4.0.3/src/zope/configuration/_compat.py0000664000175000017500000000566712073042162023671 0ustar tseavertseaver############################################################################## # # Copyright (c) 2012 Zope Foundation 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 PY3 = sys.version_info[0] >= 3 if PY3: #pragma NO COVER import builtins from io import StringIO string_types = str, text_type = str def b(s): return s.encode("latin-1") def u(s): return s # borrowed from 'six' print_ = getattr(builtins, "print") # borrowed from 'six' def reraise(tp, value, tb=None): if value is None: value = tp if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value else: #pragma NO COVER import __builtin__ as builtins from StringIO import StringIO text_type = unicode string_types = basestring, def b(s): return s def u(s): return unicode(s, "unicode_escape") # borrowed from 'six' def print_(*args, **kwargs): """The new-style print function.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): if not isinstance(data, basestring): data = str(data) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") if kwargs: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: if isinstance(arg, unicode): want_unicode = True break if want_unicode: newline = unicode("\n") space = unicode(" ") else: newline = "\n" space = " " if sep is None: sep = space if end is None: end = newline for i, arg in enumerate(args): if i: write(sep) write(arg) write(end) # borrowed from 'six' exec("""\ def reraise(tp, value, tb=None): raise tp, value, tb """) zope.configuration-4.0.3/src/zope/configuration/__init__.py0000664000175000017500000000151312073042162023770 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation 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. # ############################################################################## """Zope configuration support Software that wants to provide new config directives calls zope.configuration.meta.register. """ def namespace(suffix): return 'http://namespaces.zope.org/'+suffix zope.configuration-4.0.3/src/zope/configuration/config.py0000664000175000017500000010404312073042162023500 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Configuration processor """ from keyword import iskeyword import operator import os.path import sys from zope.interface.adapter import AdapterRegistry from zope.interface import Interface from zope.interface import implementer from zope.interface import providedBy from zope.schema import TextLine from zope.schema import URI from zope.schema import ValidationError from zope.configuration.exceptions import ConfigurationError from zope.configuration.interfaces import IConfigurationContext from zope.configuration.interfaces import IGroupingContext from zope.configuration.fields import GlobalInterface from zope.configuration.fields import GlobalObject from zope.configuration._compat import builtins from zope.configuration._compat import reraise from zope.configuration._compat import string_types from zope.configuration._compat import text_type from zope.configuration._compat import u zopens = 'http://namespaces.zope.org/zope' metans = 'http://namespaces.zope.org/meta' testns = 'http://namespaces.zope.org/test' _import_chickens = {}, {}, ("*",) # dead chickens needed by __import__ class ConfigurationContext(object): """Mix-in that implements IConfigurationContext Subclasses provide a ``package`` attribute and a ``basepath`` attribute. If the base path is not None, relative paths are converted to absolute paths using the the base path. If the package is not none, relative imports are performed relative to the package. In general, the basepath and package attributes should be consistent. When a package is provided, the base path should be set to the path of the package directory. Subclasses also provide an ``actions`` attribute, which is a list of actions, an ``includepath`` attribute, and an ``info`` attribute. The include path is appended to each action and is used when resolving conflicts among actions. Normally, only the a ConfigurationMachine provides the actions attribute. Decorators simply use the actions of the context they decorate. The ``includepath`` attribute is a tuple of names. Each name is typically the name of an included configuration file. The ``info`` attribute contains descriptive information helpful when reporting errors. If not set, it defaults to an empty string. The actions attribute is a sequence of dictionaries where each dictionary has the following keys: - ``discriminator``, a value that identifies the action. Two actions that have the same (non None) discriminator conflict. - ``callable``, an object that is called to execute the action, - ``args``, positional arguments for the action - ``kw``, keyword arguments for the action - ``includepath``, a tuple of include file names (defaults to ()) - ``info``, an object that has descriptive information about the action (defaults to '') """ def __init__(self): super(ConfigurationContext, self).__init__() self._seen_files = set() self._features = set() def resolve(self, dottedname): """Resolve a dotted name to an object. """ name = dottedname.strip() if not name: raise ValueError("The given name is blank") if name == '.': return self.package names = name.split('.') if not names[-1]: raise ValueError( "Trailing dots are no longer supported in dotted names") if len(names) == 1: # Check for built-in objects marker = object() obj = getattr(builtins, names[0], marker) if obj is not marker: return obj if not names[0]: # Got a relative name. Convert it to abs using package info if self.package is None: raise ConfigurationError( "Can't use leading dots in dotted names, " "no package has been set.") pnames = self.package.__name__.split(".") pnames.append('') while names and not names[0]: names.pop(0) try: pnames.pop() except IndexError: raise ConfigurationError("Invalid global name", name) names[0:0] = pnames # Now we should have an absolute dotted name # Split off object name: oname, mname = names[-1], '.'.join(names[:-1]) # Import the module if not mname: # Just got a single name. Must me a module mname = oname oname = '' try: mod = __import__(mname, *_import_chickens) except ImportError as v: if sys.exc_info()[2].tb_next is not None: # ImportError was caused deeper raise raise ConfigurationError( "ImportError: Couldn't import %s, %s" % (mname, v)) if not oname: # see not mname case above return mod try: obj = getattr(mod, oname) return obj except AttributeError: # No such name, maybe it's a module that we still need to import try: return __import__(mname+'.'+oname, *_import_chickens) except ImportError: if sys.exc_info()[2].tb_next is not None: # ImportError was caused deeper raise raise ConfigurationError( "ImportError: Module %s has no global %s" % (mname, oname)) def path(self, filename): """ Compute package-relative paths. """ filename = os.path.normpath(filename) if os.path.isabs(filename): return filename # Got a relative path, combine with base path. # If we have no basepath, compute the base path from the package # path. basepath = getattr(self, 'basepath', '') if not basepath: if self.package is None: basepath = os.getcwd() else: if hasattr(self.package, '__path__'): basepath = self.package.__path__[0] else: basepath = os.path.dirname(self.package.__file__) basepath = os.path.abspath(os.path.normpath(basepath)) self.basepath = basepath return os.path.normpath(os.path.join(basepath, filename)) def checkDuplicate(self, filename): """Check for duplicate imports of the same file. Raises an exception if this file had been processed before. This is better than an unlimited number of conflict errors. """ path = self.path(filename) if path in self._seen_files: raise ConfigurationError('%r included more than once' % path) self._seen_files.add(path) def processFile(self, filename): """Check whether a file needs to be processed. Return True if processing is needed and False otherwise. If the file needs to be processed, it will be marked as processed, assuming that the caller will procces the file if it needs to be procssed. """ #' <-- bow to font-lock path = self.path(filename) if path in self._seen_files: return False self._seen_files.add(path) return True def action(self, discriminator, callable=None, args=(), kw=None, order=0, includepath=None, info=None, **extra): """Add an action with the given discriminator, callable and arguments. For testing purposes, the callable and arguments may be omitted. In that case, a default noop callable is used. The discriminator must be given, but it can be None, to indicate that the action never conflicts. """ if kw is None: kw = {} action = extra if info is None: info = getattr(self, 'info', '') if includepath is None: includepath = getattr(self, 'includepath', ()) action.update( dict( discriminator=discriminator, callable=callable, args=args, kw=kw, includepath=includepath, info=info, order=order, ) ) self.actions.append(action) def hasFeature(self, feature): """Check whether a named feature has been provided. Initially no features are provided """ return feature in self._features def provideFeature(self, feature): """Declare thata named feature has been provided. See :meth:`hasFeature` for examples. """ self._features.add(feature) class ConfigurationAdapterRegistry(object): """Simple adapter registry that manages directives as adapters """ def __init__(self): super(ConfigurationAdapterRegistry, self).__init__() self._registry = {} # Stores tuples of form: # (namespace, name), schema, usedIn, info, parent self._docRegistry = [] def register(self, interface, name, factory): r = self._registry.get(name) if r is None: r = AdapterRegistry() self._registry[name] = r r.register([interface], Interface, '', factory) def document(self, name, schema, usedIn, handler, info, parent=None): if isinstance(name, string_types): name = ('', name) self._docRegistry.append((name, schema, usedIn, handler, info, parent)) def factory(self, context, name): r = self._registry.get(name) if r is None: # Try namespace-independent name ns, n = name r = self._registry.get(n) if r is None: raise ConfigurationError("Unknown directive", ns, n) f = r.lookup1(providedBy(context), Interface) if f is None: raise ConfigurationError( "The directive %s cannot be used in this context" % (name, )) return f @implementer(IConfigurationContext) class ConfigurationMachine(ConfigurationAdapterRegistry, ConfigurationContext): """Configuration machine """ package = None basepath = None includepath = () info = '' def __init__(self): super(ConfigurationMachine, self).__init__() self.actions = [] self.stack = [RootStackItem(self)] self.i18n_strings = {} _bootstrap(self) def begin(self, __name, __data=None, __info=None, **kw): if __data: if kw: raise TypeError("Can't provide a mapping object and keyword " "arguments") else: __data = kw self.stack.append(self.stack[-1].contained(__name, __data, __info)) def end(self): self.stack.pop().finish() def __call__(self, __name, __info=None, **__kw): self.begin(__name, __kw, __info) self.end() def getInfo(self): return self.stack[-1].context.info def setInfo(self, info): self.stack[-1].context.info = info def execute_actions(self, clear=True, testing=False): """Execute the configuration actions. This calls the action callables after resolving conflicts. """ try: for action in resolveConflicts(self.actions): callable = action['callable'] if callable is None: continue args = action['args'] kw = action['kw'] info = action['info'] try: callable(*args, **kw) except (KeyboardInterrupt, SystemExit): #pragma NO COVER raise except: if testing: raise t, v, tb = sys.exc_info() try: reraise(ConfigurationExecutionError(t, v, info), None, tb) finally: del t, v, tb finally: if clear: del self.actions[:] class ConfigurationExecutionError(ConfigurationError): """An error occurred during execution of a configuration action """ def __init__(self, etype, evalue, info): self.etype, self.evalue, self.info = etype, evalue, info def __str__(self): #pragma NO COVER return "%s: %s\n in:\n %s" % (self.etype, self.evalue, self.info) ############################################################################## # Stack items class IStackItem(Interface): """Configuration machine stack items Stack items are created when a directive is being processed. A stack item is created for each directive use. """ def contained(name, data, info): """Begin processing a contained directive The data are a dictionary of attribute names mapped to unicode strings. The info argument is an object that can be converted to a string and that contains information about the directive. The begin method returns the next item to be placed on the stack. """ def finish(): """Finish processing a directive """ @implementer(IStackItem) class SimpleStackItem(object): """Simple stack item A simple stack item can't have anything added after it. It can only be removed. It is used for simple directives and subdirectives, which can't contain other directives. It also defers any computation until the end of the directive has been reached. """ #XXX why this *argdata hack instead of schema, data? def __init__(self, context, handler, info, *argdata): newcontext = GroupingContextDecorator(context) newcontext.info = info self.context = newcontext self.handler = handler self.argdata = argdata def contained(self, name, data, info): raise ConfigurationError("Invalid directive %s" % str(name)) def finish(self): # We're going to use the context that was passed to us, which wasn't # created for the directive. We want to set it's info to the one # passed to us while we make the call, so we'll save the old one # and restore it. context = self.context args = toargs(context, *self.argdata) actions = self.handler(context, **args) if actions: # we allow the handler to return nothing for action in actions: if not isinstance(action, dict): action = expand_action(*action) # b/c context.action(**action) @implementer(IStackItem) class RootStackItem(object): def __init__(self, context): self.context = context def contained(self, name, data, info): """Handle a contained directive We have to compute a new stack item by getting a named adapter for the current context object. """ factory = self.context.factory(self.context, name) if factory is None: raise ConfigurationError("Invalid directive", name) adapter = factory(self.context, data, info) return adapter def finish(self): pass @implementer(IStackItem) class GroupingStackItem(RootStackItem): """Stack item for a grouping directive A grouping stack item is in the stack when a grouping directive is being processed. Grouping directives group other directives. Often, they just manage common data, but they may also take actions, either before or after contained directives are executed. A grouping stack item is created with a grouping directive definition, a configuration context, and directive data. """ def __init__(self, context): super(GroupingStackItem, self).__init__(context) def __callBefore(self): actions = self.context.before() if actions: for action in actions: if not isinstance(action, dict): action = expand_action(*action) self.context.action(**action) self.__callBefore = noop def contained(self, name, data, info): self.__callBefore() return RootStackItem.contained(self, name, data, info) def finish(self): self.__callBefore() actions = self.context.after() if actions: for action in actions: if not isinstance(action, dict): action = expand_action(*action) self.context.action(**action) def noop(): pass @implementer(IStackItem) class ComplexStackItem(object): """Complex stack item A complex stack item is in the stack when a complex directive is being processed. It only allows subdirectives to be used. A complex stack item is created with a complex directive definition (IComplexDirectiveContext), a configuration context, and directive data. """ def __init__(self, meta, context, data, info): newcontext = GroupingContextDecorator(context) newcontext.info = info self.context = newcontext self.meta = meta # Call the handler contructor args = toargs(newcontext, meta.schema, data) self.handler = self.meta.handler(newcontext, **args) def contained(self, name, data, info): """Handle a subdirective """ # Look up the subdirective meta data on our meta object ns, name = name schema = self.meta.get(name) if schema is None: raise ConfigurationError("Invalid directive", name) schema = schema[0] # strip off info handler = getattr(self.handler, name) return SimpleStackItem(self.context, handler, info, schema, data) def finish(self): # when we're done, we call the handler, which might return more actions # Need to save and restore old info # XXX why not just use callable()? try: actions = self.handler() except AttributeError as v: if v.args[0] == '__call__': return # noncallable raise except TypeError: return # non callable if actions: # we allow the handler to return nothing for action in actions: if not isinstance(action, dict): action = expand_action(*action) self.context.action(**action) ############################################################################## # Helper classes @implementer(IConfigurationContext, IGroupingContext) class GroupingContextDecorator(ConfigurationContext): """Helper mix-in class for building grouping directives See the discussion (and test) in GroupingStackItem. """ def __init__(self, context, **kw): self.context = context for name, v in kw.items(): setattr(self, name, v) def __getattr__(self, name, getattr=getattr, setattr=setattr): v = getattr(self.context, name) # cache result in self setattr(self, name, v) return v def before(self): pass def after(self): pass ############################################################################## # Directive-definition class DirectiveSchema(GlobalInterface): """A field that contains a global variable value that must be a schema """ class IDirectivesInfo(Interface): """Schema for the ``directives`` directive """ namespace = URI( title=u("Namespace"), description=u("The namespace in which directives' names " "will be defined"), ) class IDirectivesContext(IDirectivesInfo, IConfigurationContext): pass @implementer(IDirectivesContext) class DirectivesHandler(GroupingContextDecorator): """Handler for the directives directive This is just a grouping directive that adds a namespace attribute to the normal directive context. """ class IDirectiveInfo(Interface): """Information common to all directive definitions have """ name = TextLine( title = u("Directive name"), description = u("The name of the directive being defined"), ) schema = DirectiveSchema( title = u("Directive handler"), description = u("The dotted name of the directive handler"), ) class IFullInfo(IDirectiveInfo): """Information that all top-level directives (not subdirectives) have """ handler = GlobalObject( title = u("Directive handler"), description = u("The dotted name of the directive handler"), ) usedIn = GlobalInterface( title = u("The directive types the directive can be used in"), description = u("The interface of the directives that can contain " "the directive" ), default = IConfigurationContext, ) class IStandaloneDirectiveInfo(IDirectivesInfo, IFullInfo): """Info for full directives defined outside a directives directives """ def defineSimpleDirective(context, name, schema, handler, namespace='', usedIn=IConfigurationContext): """Define a simple directive Define and register a factory that invokes the simple directive and returns a new stack item, which is always the same simple stack item. If the namespace is '*', the directive is registered for all namespaces. """ namespace = namespace or context.namespace if namespace != '*': name = namespace, name def factory(context, data, info): return SimpleStackItem(context, handler, info, schema, data) factory.schema = schema context.register(usedIn, name, factory) context.document(name, schema, usedIn, handler, context.info) def defineGroupingDirective(context, name, schema, handler, namespace='', usedIn=IConfigurationContext): """Define a grouping directive Define and register a factory that sets up a grouping directive. If the namespace is '*', the directive is registered for all namespaces. """ namespace = namespace or context.namespace if namespace != '*': name = namespace, name def factory(context, data, info): args = toargs(context, schema, data) newcontext = handler(context, **args) newcontext.info = info return GroupingStackItem(newcontext) factory.schema = schema context.register(usedIn, name, factory) context.document(name, schema, usedIn, handler, context.info) class IComplexDirectiveContext(IFullInfo, IConfigurationContext): pass @implementer(IComplexDirectiveContext) class ComplexDirectiveDefinition(GroupingContextDecorator, dict): """Handler for defining complex directives See the description and tests for ComplexStackItem. """ def before(self): def factory(context, data, info): return ComplexStackItem(self, context, data, info) factory.schema = self.schema self.register(self.usedIn, (self.namespace, self.name), factory) self.document((self.namespace, self.name), self.schema, self.usedIn, self.handler, self.info) def subdirective(context, name, schema): context.document((context.namespace, name), schema, context.usedIn, getattr(context.handler, name, context.handler), context.info, context.context) context.context[name] = schema, context.info ############################################################################## # Features class IProvidesDirectiveInfo(Interface): """Information for a directive""" feature = TextLine( title = u("Feature name"), description = u("""The name of the feature being provided You can test available features with zcml:condition="have featurename". """), ) def provides(context, feature): """Declare that a feature is provided in context. """ if len(feature.split()) > 1: raise ValueError("Only one feature name allowed") context.provideFeature(feature) ############################################################################## # Argument conversion def toargs(context, schema, data): """Marshal data to an argument dictionary using a schema Names that are python keywords have an underscore added as a suffix in the schema and in the argument list, but are used without the underscore in the data. The fields in the schema must all implement IFromUnicode. All of the items in the data must have corresponding fields in the schema unless the schema has a true tagged value named 'keyword_arguments'. """ data = dict(data) args = {} for name, field in schema.namesAndDescriptions(True): field = field.bind(context) n = name if n.endswith('_') and iskeyword(n[:-1]): n = n[:-1] s = data.get(n, data) if s is not data: s = text_type(s) del data[n] try: args[str(name)] = field.fromUnicode(s) except ValidationError as v: reraise(ConfigurationError("Invalid value for", n, str(v)), None, sys.exc_info()[2]) elif field.required: # if the default is valid, we can use that: default = field.default try: field.validate(default) except ValidationError: raise ConfigurationError("Missing parameter:", n) args[str(name)] = default if data: # we had data left over try: keyword_arguments = schema.getTaggedValue('keyword_arguments') except KeyError: keyword_arguments = False if not keyword_arguments: raise ConfigurationError("Unrecognized parameters:", *data) for name in data: args[str(name)] = data[name] return args ############################################################################## # Conflict resolution def expand_action(discriminator, callable=None, args=(), kw=None, includepath=(), info=None, order=0, **extra): if kw is None: kw = {} action = extra action.update( dict( discriminator=discriminator, callable=callable, args=args, kw=kw, includepath=includepath, info=info, order=order, ) ) return action def resolveConflicts(actions): """Resolve conflicting actions Given an actions list, identify and try to resolve conflicting actions. Actions conflict if they have the same non-None discriminator. Conflicting actions can be resolved if the include path of one of the actions is a prefix of the includepaths of the other conflicting actions and is unequal to the include paths in the other conflicting actions. """ # organize actions by discriminators unique = {} output = [] for i, action in enumerate(actions): if not isinstance(action, dict): # old-style tuple action action = expand_action(*action) # "order" is an integer grouping. Actions in a lower order will be # executed before actions in a higher order. Within an order, # actions are executed sequentially based on original action ordering # ("i"). order = action['order'] or 0 discriminator = action['discriminator'] # "ainfo" is a tuple of (order, i, action) where "order" is a # user-supplied grouping, "i" is an integer expressing the relative # position of this action in the action list being resolved, and # "action" is an action dictionary. The purpose of an ainfo is to # associate an "order" and an "i" with a particular action; "order" # and "i" exist for sorting purposes after conflict resolution. ainfo = (order, i, action) if discriminator is None: # The discriminator is None, so this action can never conflict. # We can add it directly to the result. output.append(ainfo) continue L = unique.setdefault(discriminator, []) L.append(ainfo) # Check for conflicts conflicts = {} for discriminator, ainfos in unique.items(): # We use (includepath, order, i) as a sort key because we need to # sort the actions by the paths so that the shortest path with a # given prefix comes first. The "first" action is the one with the # shortest include path. We break sorting ties using "order", then # "i". def bypath(ainfo): path, order, i = ainfo[2]['includepath'], ainfo[0], ainfo[1] return path, order, i ainfos.sort(key=bypath) ainfo, rest = ainfos[0], ainfos[1:] output.append(ainfo) _, _, action = ainfo basepath, baseinfo, discriminator = (action['includepath'], action['info'], action['discriminator']) for _, _, action in rest: includepath = action['includepath'] # Test whether path is a prefix of opath if (includepath[:len(basepath)] != basepath # not a prefix or includepath == basepath): L = conflicts.setdefault(discriminator, [baseinfo]) L.append(action['info']) if conflicts: raise ConfigurationConflictError(conflicts) # Sort conflict-resolved actions by (order, i) and return them. return [x[2] for x in sorted(output, key=operator.itemgetter(0, 1))] class ConfigurationConflictError(ConfigurationError): def __init__(self, conflicts): self._conflicts = conflicts def __str__(self): #pragma NO COVER r = ["Conflicting configuration actions"] items = self._conflicts.items() items.sort() for discriminator, infos in items: r.append(" For: %s" % (discriminator, )) for info in infos: for line in text_type(info).rstrip().split(u('\n')): r.append(u(" ") + line) return "\n".join(r) ############################################################################## # Bootstap code def _bootstrap(context): # Set enough machinery to register other directives # Define the directive (simple directive) directive by calling it's # handler directly info = 'Manually registered in zope/configuration/config.py' context.info = info defineSimpleDirective( context, namespace=metans, name='directive', schema=IStandaloneDirectiveInfo, handler=defineSimpleDirective) context.info = '' # OK, now that we have that, we can use the machine to define the # other directives. This isn't the easiest way to proceed, but it lets # us eat our own dogfood. :) # Standalone groupingDirective context((metans, 'directive'), info, name='groupingDirective', namespace=metans, handler="zope.configuration.config.defineGroupingDirective", schema="zope.configuration.config.IStandaloneDirectiveInfo" ) # Now we can use the grouping directive to define the directives directive context((metans, 'groupingDirective'), info, name='directives', namespace=metans, handler="zope.configuration.config.DirectivesHandler", schema="zope.configuration.config.IDirectivesInfo" ) # directive and groupingDirective inside directives context((metans, 'directive'), info, name='directive', namespace=metans, usedIn="zope.configuration.config.IDirectivesContext", handler="zope.configuration.config.defineSimpleDirective", schema="zope.configuration.config.IFullInfo" ) context((metans, 'directive'), info, name='groupingDirective', namespace=metans, usedIn="zope.configuration.config.IDirectivesContext", handler="zope.configuration.config.defineGroupingDirective", schema="zope.configuration.config.IFullInfo" ) # Setup complex directive directive, both standalone, and in # directives directive context((metans, 'groupingDirective'), info, name='complexDirective', namespace=metans, handler="zope.configuration.config.ComplexDirectiveDefinition", schema="zope.configuration.config.IStandaloneDirectiveInfo" ) context((metans, 'groupingDirective'), info, name='complexDirective', namespace=metans, usedIn="zope.configuration.config.IDirectivesContext", handler="zope.configuration.config.ComplexDirectiveDefinition", schema="zope.configuration.config.IFullInfo" ) # Finally, setup subdirective directive context((metans, 'directive'), info, name='subdirective', namespace=metans, usedIn="zope.configuration.config.IComplexDirectiveContext", handler="zope.configuration.config.subdirective", schema="zope.configuration.config.IDirectiveInfo" ) # meta:provides context((metans, 'directive'), info, name='provides', namespace=metans, handler="zope.configuration.config.provides", schema="zope.configuration.config.IProvidesDirectiveInfo" ) zope.configuration-4.0.3/src/zope/configuration/docutils.py0000664000175000017500000000466412073042162024071 0ustar tseavertseaver############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## """Helper Utility to wrap a text to a set width of characters """ __docformat__ = 'restructuredtext' import re para_sep = re.compile('\n{2,}') whitespace = re.compile('[ \t\n\r]+') def wrap(text, width=78, indent=0): """Makes sure that we keep a line length of a certain width. """ paras = para_sep.split(text.strip()) new_paras = [] for par in paras: words= filter(None, whitespace.split(par)) lines = [] line = [] length = indent for word in words: if length + len(word) <= width: line.append(word) length += len(word) + 1 else: lines.append(' '*indent + ' '.join(line)) line = [word] length = len(word) + 1 + indent lines.append(' '*indent + ' '.join(line)) new_paras.append('\n'.join(lines)) return '\n\n'.join(new_paras) + '\n\n' def makeDocStructures(context): """Creates two structures that provide a friendly format for documentation. 'namespaces' is a dictionary that maps namespaces to a directives dictionary with the key being the name of the directive and the value is a tuple: (schema, handler, info). 'subdirs' maps a (namespace, name) pair to a list of subdirectives that have the form (namespace, name, schema, info). """ namespaces = {} subdirs = {} registry = context._docRegistry for (namespace, name), schema, usedIn, handler, info, parent in registry: if not parent: ns_entry = namespaces.setdefault(namespace, {}) ns_entry[name] = (schema, handler, info) else: sd_entry = subdirs.setdefault((parent.namespace, parent.name), []) sd_entry.append((namespace, name, schema, handler, info)) return namespaces, subdirs zope.configuration-4.0.3/src/zope/configuration/interfaces.py0000664000175000017500000001072612073042162024362 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation 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. # ############################################################################## """Zope Configuration (ZCML) interfaces """ from zope.interface import Interface from zope.schema import BytesLine from zope.schema.interfaces import ValidationError from zope.configuration._compat import u class InvalidToken(ValidationError): """Invaid token in list.""" class IConfigurationContext(Interface): """Configuration Context The configuration context manages information about the state of the configuration system, such as the package containing the configuration file. More importantly, it provides methods for importing objects and opening files relative to the package. """ package = BytesLine( title=u("The current package name"), description=u("""\ This is the name of the package containing the configuration file being executed. If the configuration file was not included by package, then this is None. """), required=False, ) def resolve(dottedname): """Resolve a dotted name to an object A dotted name is constructed by concatenating a dotted module name with a global name within the module using a dot. For example, the object named "spam" in the foo.bar module has a dotted name of foo.bar.spam. If the current package is a prefix of a dotted name, then the package name can be relaced with a leading dot, So, for example, if the configuration file is in the foo package, then the dotted name foo.bar.spam can be shortened to .bar.spam. If the current package is multiple levels deep, multiple leading dots can be used to refer to higher-level modules. For example, if the current package is x.y.z, the dotted object name ..foo refers to x.y.foo. """ def path(filename): """Compute a full file name for the given file If the filename is relative to the package, then the returned name will include the package path, otherwise, the original file name is returned. """ def checkDuplicate(filename): """Check for duplicate imports of the same file. Raises an exception if this file had been processed before. This is better than an unlimited number of conflict errors. """ def processFile(filename): """Check whether a file needs to be processed. Return True if processing is needed and False otherwise. If the file needs to be processed, it will be marked as processed, assuming that the caller will procces the file if it needs to be procssed. """ def action(discriminator, callable, args=(), kw={}, order=0, includepath=None, info=None): """Record a configuration action The job of most directives is to compute actions for later processing. The action method is used to record those actions. The discriminator is used to to find actions that conflict. Actions conflict if they have the same discriminator. The exception to this is the special case of the discriminator with the value None. An actions with a discriminator of None never conflicts with other actions. This is possible to add an order argument to crudely control the order of execution. 'info' is optional source line information, 'includepath' is None (the default) or a tuple of include paths for this action. """ def provideFeature(name): """Record that a named feature is available in this context.""" def hasFeature(name): """Check whether a named feature is available in this context.""" class IGroupingContext(Interface): def before(): """Do something before processing nested directives """ def after(): """Do something after processing nested directives """ zope.configuration-4.0.3/src/zope/configuration/tests/0000775000175000017500000000000012312363233023022 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/configuration/tests/simple.zcml0000664000175000017500000000156312073042162025206 0ustar tseavertseaver Register a file with the file registry Blah blah blah :) Describes how to implement a simple directive Shows the ZCML directives needed to register a simple directive. Also show some usage examples, zope.configuration-4.0.3/src/zope/configuration/tests/sample.zcml0000664000175000017500000000044312073042162025172 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/0000775000175000017500000000000012312363233025617 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/bar21.zcml0000664000175000017500000000017012073042162027412 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/bar.zcml0000664000175000017500000000013412073042162027247 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/NamedForClass.py0000664000175000017500000000014612073042162030652 0ustar tseavertseaver# Test the "repeat" feature of zope.configuration.name.resolve. class NamedForClass(object): pass zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/__init__.py0000664000175000017500000000007512073042162027731 0ustar tseavertseaver# # This file is necessary to make this directory a package. zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/foo.py0000664000175000017500000000245012073042162026754 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Sample module used for testing """ from zope.interface import Interface from zope import schema data = [] class S1(Interface): x = schema.BytesLine() y = schema.Int() class stuff(object): def __init__(self, args, info, basepath, package, includepath): (self.args, self.info, self.basepath, self.package, self.includepath ) = args, info, basepath, package, includepath def handler(_context, **kw): args = sorted(kw.items()) args = tuple(args) discriminator = args args = (stuff(args, _context.info, _context.basepath, _context.package, _context.includepath), ) _context.action(discriminator, data.append, args) zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/baz3.zcml0000664000175000017500000000023712073042162027346 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/bar2.zcml0000664000175000017500000000023112073042162027327 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/bar1.zcml0000664000175000017500000000020412073042162027326 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/baro.zcml0000664000175000017500000000014512073042162027430 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/configure.zcml.in0000664000175000017500000000010112073042162031063 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/configure.zcml0000664000175000017500000000067312073042162030474 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/baz2.zcml0000664000175000017500000000023712073042162027345 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/baz1.zcml0000664000175000017500000000063412073042162027345 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/baro2.zcml0000664000175000017500000000014412073042162027511 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/samplepackage/foo.zcml.in0000664000175000017500000000067212073042162027702 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/__init__.py0000664000175000017500000000007512073042162025134 0ustar tseavertseaver# # This file is necessary to make this directory a package. zope.configuration-4.0.3/src/zope/configuration/tests/test_docutils.py0000664000175000017500000001120312073042162026255 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Tests for for zope.configuration.docutils """ import unittest class Test_wrap(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.docutils import wrap return wrap(*args, **kw) def test_empty(self): self.assertEqual(self._callFUT(''), '\n\n') def test_only_whitespace(self): self.assertEqual(self._callFUT(' \t\n\r'), '\n\n') def test_single_paragraphs(self): self.assertEqual( self._callFUT('abcde fghij klmno pqrst uvwxy', 10, 3), ' abcde\n fghij\n klmno\n pqrst\n uvwxy\n\n') def test_multiple_paragraphs(self): self.assertEqual( self._callFUT('abcde fghij klmno\n\npqrst uvwxy', 10, 3), ' abcde\n fghij\n klmno\n\n pqrst\n uvwxy\n\n') class Test_makeDocStructures(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.docutils import makeDocStructures return makeDocStructures(*args, **kw) def _makeContext(self): class _Context(object): def __init__(self): self._docRegistry = [] return _Context() def test_empty(self): context = self._makeContext() namespaces, subdirs = self._callFUT(context) self.assertEqual(len(namespaces), 0) self.assertEqual(len(subdirs), 0) def test_wo_parents(self): from zope.interface import Interface class ISchema(Interface): pass class IUsedIn(Interface): pass NS = 'http://namespace.example.com/main' NS2 = 'http://namespace.example.com/other' def _one(): pass def _two(): pass def _three(): pass context = self._makeContext() context._docRegistry.append( ((NS, 'one'), ISchema, IUsedIn, _one, 'ONE', None)) context._docRegistry.append( ((NS2, 'two'), ISchema, IUsedIn, _two, 'TWO', None)) context._docRegistry.append( ((NS, 'three'), ISchema, IUsedIn, _three, 'THREE', None)) namespaces, subdirs = self._callFUT(context) self.assertEqual(len(namespaces), 2) self.assertEqual(namespaces[NS], {'one': (ISchema, _one, 'ONE'), 'three': (ISchema, _three, 'THREE')}) self.assertEqual(namespaces[NS2], {'two': (ISchema, _two, 'TWO')}) self.assertEqual(len(subdirs), 0) def test_w_parents(self): from zope.interface import Interface class ISchema(Interface): pass class IUsedIn(Interface): pass PNS = 'http://namespace.example.com/parent' NS = 'http://namespace.example.com/main' NS2 = 'http://namespace.example.com/other' def _one(): pass def _two(): pass def _three(): pass class Parent(object): namespace = PNS name = 'parent' parent1 = Parent() parent2 = Parent() parent2.name = 'parent2' context = self._makeContext() context._docRegistry.append( ((NS, 'one'), ISchema, IUsedIn, _one, 'ONE', parent1)) context._docRegistry.append( ((NS2, 'two'), ISchema, IUsedIn, _two, 'TWO', parent2)) context._docRegistry.append( ((NS, 'three'), ISchema, IUsedIn, _three, 'THREE', parent1)) namespaces, subdirs = self._callFUT(context) self.assertEqual(len(namespaces), 0) self.assertEqual(len(subdirs), 2) self.assertEqual(subdirs[(PNS, 'parent')], [(NS, 'one', ISchema, _one, 'ONE'), (NS, 'three', ISchema, _three, 'THREE')]) self.assertEqual(subdirs[(PNS, 'parent2')], [(NS2, 'two', ISchema, _two, 'TWO')]) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(Test_wrap), unittest.makeSuite(Test_makeDocStructures), )) zope.configuration-4.0.3/src/zope/configuration/tests/test_zopeconfigure.py0000664000175000017500000000264512073042162027320 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Test zope.configuration.xmlconfig. """ import unittest class ZopeConfigureTests(unittest.TestCase): def _getTargetClass(self): from zope.configuration.xmlconfig import ZopeConfigure return ZopeConfigure def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor_wo_package(self): zc = self._makeOne(Context()) self.assertEqual(zc.basepath, None) def test_ctor_w_package(self): import os import zope.configuration.tests as zct zc = self._makeOne(Context(), package=zct) self.assertEqual(zc.basepath, os.path.dirname(zct.__file__)) class Context(object): basepath = None def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ZopeConfigureTests), )) zope.configuration-4.0.3/src/zope/configuration/tests/directives.py0000664000175000017500000000473212073042162025542 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation 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. # ############################################################################## """Test directives """ from zope.interface import Interface from zope.interface import implementer from zope.schema import BytesLine from zope.schema import Text from zope.configuration.config import GroupingContextDecorator from zope.configuration.interfaces import IConfigurationContext from zope.configuration.fields import GlobalObject from zope.configuration._compat import u class F(object): def __repr__(self): return 'f' def __call__(self, *a, **k): pass f = F() class ISimple(Interface): a = Text() b = Text(required=False) c = BytesLine() def simple(context, a=None, c=None, b=u("xxx")): return [(('simple', a, b, c), f, (a, b, c))] def newsimple(context, a, c, b=u("xxx")): context.action(('newsimple', a, b, c), f, (a, b, c)) class IPackaged(Interface): package = GlobalObject() class IPackagedContext(IPackaged, IConfigurationContext): pass @implementer(IPackagedContext) class Packaged(GroupingContextDecorator): pass class IFactory(Interface): factory = GlobalObject() def factory(context, factory): context.action(('factory', 1,2), factory) class Complex(object): def __init__(self, context, a, c, b=u("xxx")): self.a, self.b, self.c = a, b, c context.action("Complex.__init__") def factory(self, context, factory): return [(('Complex.factory', 1,2), factory, (self.a, ))] def factory2(self, context, factory): return [(('Complex.factory', 1,2), factory, (self.a, ))] def __call__(self): return [(('Complex', 1,2), f, (self.b, self.c))] class Ik(Interface): for_ = BytesLine() class_ = BytesLine() x = BytesLine() def k(context, for_, class_, x): context.action(('k', for_), f, (for_, class_, x)) def kkw(context, for_, class_, x, **kw): context.action(('k', for_), f, (for_, class_, x, kw)) zope.configuration-4.0.3/src/zope/configuration/tests/conditions.py0000664000175000017500000000230312073042162025542 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """ Enable "Making specific directives condition" section of narrative docs. """ from zope.interface import Interface from zope.schema import Id from zope.configuration._compat import u class IRegister(Interface): """Trivial sample registry.""" id = Id( title=u("Identifier"), description=u("Some identifier that can be checked."), required=True, ) registry = [] def register(context, id): context.action(discriminator=('Register', id), callable=registry.append, args=(id,) ) zope.configuration-4.0.3/src/zope/configuration/tests/notyet.py0000664000175000017500000000004612073042162024715 0ustar tseavertseaver# We don't get imported automagically zope.configuration-4.0.3/src/zope/configuration/tests/test_fields.py0000664000175000017500000002611512073042162025705 0ustar tseavertseaver############################################################################## # # Copyright (c) 20!2 Zope Foundation 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. # ############################################################################## """Test zope.configuration.fields. """ import unittest class _ConformsToIFromUnicode(object): def test_class_conforms_to_IFromUnicode(self): from zope.interface.verify import verifyClass from zope.schema.interfaces import IFromUnicode verifyClass(IFromUnicode, self._getTargetClass()) def test_instance_conforms_to_IFromUnicode(self): from zope.interface.verify import verifyObject from zope.schema.interfaces import IFromUnicode verifyObject(IFromUnicode, self._makeOne()) class PythonIdentifierTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import PythonIdentifier return PythonIdentifier def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_fromUnicode_empty(self): pi = self._makeOne() self.assertEqual(pi.fromUnicode(''), '') def test_fromUnicode_normal(self): pi = self._makeOne() self.assertEqual(pi.fromUnicode('normal'), 'normal') def test_fromUnicode_strips_ws(self): pi = self._makeOne() self.assertEqual(pi.fromUnicode(' '), '') self.assertEqual(pi.fromUnicode(' normal '), 'normal') def test__validate_miss(self): from zope.schema import ValidationError from zope.configuration._compat import u pi = self._makeOne() self.assertRaises(ValidationError, pi._validate, u('not-an-identifier')) def test__validate_hit(self): from zope.configuration._compat import u pi = self._makeOne() pi._validate(u('is_an_identifier')) class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import GlobalObject return GlobalObject def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test__validate_wo_value_type(self): from zope.configuration._compat import u from zope.configuration._compat import b go = self._makeOne(value_type=None) for value in [0, 0.0, (), [], set(), frozenset(), u(''), b('')]: go._validate(value) #noraise def test__validate_w_value_type(self): from zope.schema import Text from zope.schema.interfaces import WrongType from zope.configuration._compat import u from zope.configuration._compat import b go = self._makeOne(value_type=Text()) go.validate(u('')) for value in [0, 0.0, (), [], set(), frozenset(), b('')]: self.assertRaises(WrongType, go._validate, value) def test_fromUnicode_w_star_and_extra_ws(self): go = self._makeOne() self.assertEqual(go.fromUnicode(' * '), None) def test_fromUnicode_w_resolve_fails(self): from zope.schema import ValidationError from zope.configuration.config import ConfigurationError class Context(object): def resolve(self, name): self._resolved = name raise ConfigurationError() go = self._makeOne() context = Context() bound = go.bind(context) self.assertRaises(ValidationError, bound.fromUnicode, 'tried') self.assertEqual(context._resolved, 'tried') def test_fromUnicode_w_resolve_success(self): _target = object() class Context(object): def resolve(self, name): self._resolved = name return _target go = self._makeOne() context = Context() bound = go.bind(context) found = bound.fromUnicode('tried') self.assertTrue(found is _target) self.assertEqual(context._resolved, 'tried') def test_fromUnicode_w_resolve_but_validation_fails(self): from zope.schema import Text from zope.schema import ValidationError _target = object() class Context(object): def resolve(self, name): self._resolved = name return _target go = self._makeOne(value_type=Text()) context = Context() bound = go.bind(context) self.assertRaises(ValidationError, bound.fromUnicode, 'tried') self.assertEqual(context._resolved, 'tried') class GlobalInterfaceTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import GlobalInterface return GlobalInterface def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor(self): from zope.schema import InterfaceField gi = self._makeOne() self.assertTrue(isinstance(gi.value_type, InterfaceField)) class TokensTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import Tokens return Tokens def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_fromUnicode_empty(self): tok = self._makeOne() self.assertEqual(tok.fromUnicode(''), []) def test_fromUnicode_strips_ws(self): from zope.schema import Text from zope.configuration._compat import u tok = self._makeOne(value_type=Text()) context = object() self.assertEqual(tok.fromUnicode(u(' one two three ')), [u('one'), u('two'), u('three')]) def test_fromUnicode_invalid(self): from zope.schema import Int from zope.configuration.interfaces import InvalidToken from zope.configuration._compat import u tok = self._makeOne(value_type=Int(min=0)) context = object() self.assertRaises(InvalidToken, tok.fromUnicode, u(' 1 -1 3 ')) class PathTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import Path return Path def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_fromUnicode_absolute(self): import os path = self._makeOne() self.assertEqual(path.fromUnicode('/'), os.path.normpath('/')) def test_fromUnicode_relative(self): class Context(object): def path(self, value): self._pathed = value return '/hard/coded' context = Context() path = self._makeOne() bound = path.bind(context) self.assertEqual(bound.fromUnicode('relative/path'), '/hard/coded') self.assertEqual(context._pathed, 'relative/path') class BoolTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import Bool return Bool def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_fromUnicode_w_true_values(self): values = ['1', 'true', 'yes', 't', 'y'] values += [x.upper() for x in values] bo = self._makeOne() for value in values: self.assertEqual(bo.fromUnicode(value), True) def test_fromUnicode_w_false_values(self): values = ['0', 'false', 'no', 'f', 'n'] values += [x.upper() for x in values] bo = self._makeOne() for value in values: self.assertEqual(bo.fromUnicode(value), False) def test_fromUnicode_w_invalid(self): from zope.schema import ValidationError bo = self._makeOne() self.assertRaises(ValidationError, bo.fromUnicode, 'notvalid') class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): def _getTargetClass(self): from zope.configuration.fields import MessageID return MessageID def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def _makeContext(self, domain='testing_domain'): class Info(object): file = 'test_file' line = 42 class Context(object): i18n_domain = domain def __init__(self): self.i18n_strings = {} self.info = Info() return Context() def test_wo_domain(self): import warnings from zope.configuration._compat import u mid = self._makeOne() context = self._makeContext(None) bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: msgid = bound.fromUnicode(u('testing')) self.assertEqual(len(log), 1) self.assertTrue(str(log[0].message).startswith( 'You did not specify an i18n translation domain')) self.assertEqual(msgid, 'testing') self.assertEqual(msgid.default, None) self.assertEqual(msgid.domain, 'untranslated') self.assertEqual(context.i18n_strings, {'untranslated': {'testing': [('test_file', 42)]}}) def test_w_empty_id(self): import warnings from zope.configuration._compat import u mid = self._makeOne() context = self._makeContext() bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: msgid = bound.fromUnicode(u('[] testing')) self.assertEqual(len(log), 0) self.assertEqual(msgid, 'testing') self.assertEqual(msgid.default, None) self.assertEqual(msgid.domain, 'testing_domain') self.assertEqual(context.i18n_strings, {'testing_domain': {'testing': [('test_file', 42)]}}) def test_w_id_and_default(self): import warnings from zope.configuration._compat import u mid = self._makeOne() context = self._makeContext() bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: msgid = bound.fromUnicode(u('[testing] default')) self.assertEqual(len(log), 0) self.assertEqual(msgid, 'testing') self.assertEqual(msgid.default, 'default') self.assertEqual(msgid.domain, 'testing_domain') self.assertEqual(context.i18n_strings, {'testing_domain': {'testing': [('test_file', 42)]}}) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(PythonIdentifierTests), unittest.makeSuite(GlobalObjectTests), unittest.makeSuite(GlobalInterfaceTests), unittest.makeSuite(TokensTests), unittest.makeSuite(PathTests), unittest.makeSuite(BoolTests), unittest.makeSuite(MessageIDTests), )) zope.configuration-4.0.3/src/zope/configuration/tests/victim.py0000664000175000017500000000001312073042162024660 0ustar tseavertseaverimport bad zope.configuration-4.0.3/src/zope/configuration/tests/test_config.py0000664000175000017500000021115412073042162025703 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Test configuration machinery. """ import unittest class _Catchable(object): # Mixin for classes which need to make assertions about the exception # instance. def assertRaises(self, excClass, callableObj, *args, **kwargs): # Morph stdlib version to return the raised exception try: callableObj(*args, **kwargs) except excClass as exc: return exc if hasattr(excClass,'__name__'): excName = excClass.__name__ else: excName = str(excClass) raise self.failureException("%s not raised" % excName) class ConfigurationContextTests(_Catchable, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import ConfigurationContext return ConfigurationContext def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_resolve_blank(self): c = self._makeOne() self.assertRaises(ValueError, c.resolve, '') self.assertRaises(ValueError, c.resolve, ' ') def test_resolve_dot(self): c = self._makeOne() package = c.package = object() self.assertTrue(c.resolve('.') is package) def test_resolve_trailing_dot_in_resolve(self): #Dotted names are no longer allowed to end in dots c = self._makeOne() self.assertRaises(ValueError, c.resolve, 'zope.') def test_resolve_builtin(self): c = self._makeOne() self.assertTrue(c.resolve('str') is str) def test_resolve_single_non_builtin(self): import os c = self._makeOne() self.assertTrue(c.resolve('os') is os) def test_resolve_relative_miss_no_package(self): from zope.configuration.exceptions import ConfigurationError c = self._makeOne() c.package = None self.assertRaises(ConfigurationError, c.resolve, '.nonesuch') def test_resolve_relative_miss_w_package_too_many_dots(self): class FauxPackage(object): pass from zope.configuration.exceptions import ConfigurationError c = self._makeOne() package = c.package = FauxPackage() package.__name__ = 'one.dot' self.assertRaises(ConfigurationError, c.resolve, '....nonesuch') def test_resolve_bad_dotted_last_import(self): # Import error caused by a bad last component in the dotted name. from zope.configuration.exceptions import ConfigurationError c = self._makeOne() exc = self.assertRaises(ConfigurationError, c.resolve, 'zope.configuration.tests.nosuch') self.assertTrue('ImportError' in str(exc)) def test_resolve_bad_dotted_import(self): # Import error caused by a totally wrong dotted name. from zope.configuration.exceptions import ConfigurationError c = self._makeOne() exc = self.assertRaises(ConfigurationError, c.resolve, 'zope.configuration.nosuch.noreally') self.assertTrue('ImportError' in str(exc)) def test_resolve_bad_sub_last_import(self): #Import error caused by a bad sub import inside the referenced #dotted name. Here we keep the standard traceback. import sys c = self._makeOne() self.assertRaises(ImportError, c.resolve, 'zope.configuration.tests.victim') #Cleanup: for name in ('zope.configuration.tests.victim', 'zope.configuration.tests.bad'): if name in sys.modules: del sys.modules[name] def test_resolve_bad_sub_import(self): #Import error caused by a bad sub import inside part of the referenced #dotted name. Here we keep the standard traceback. import sys c = self._makeOne() self.assertRaises(ImportError, c.resolve, 'zope.configuration.tests.victim.nosuch') #Cleanup: for name in ('zope.configuration.tests.victim', 'zope.configuration.tests.bad'): if name in sys.modules: del sys.modules[name] def test_path_w_absolute_filename(self): import os c = self._makeOne() self.assertEqual(c.path('/path/to/somewhere'), os.path.normpath('/path/to/somewhere')) def test_path_w_relative_filename_w_basepath(self): import os c = self._makeOne() c.basepath = '/path/to' self.assertEqual(c.path('somewhere'), os.path.normpath('/path/to/somewhere')) def test_path_w_relative_filename_wo_basepath_wo_package(self): import os c = self._makeOne() c.package = None self.assertEqual(c.path('somewhere'), os.path.join(os.getcwd(), 'somewhere')) def test_path_wo_basepath_w_package_having_file(self): #Path must always return an absolute path. import os class stub: __file__ = os.path.join('relative', 'path') c = self._makeOne() c.package = stub() self.assertTrue(os.path.isabs(c.path('y/z'))) def test_path_wo_basepath_w_package_having_no_file_but_path(self): #Determine package path using __path__ if __file__ isn't available. # (i.e. namespace package installed with #--single-version-externally-managed) import os class stub: __path__ = [os.path.join('relative', 'path')] c = self._makeOne() c.package = stub() self.assertTrue(os.path.isabs(c.path('y/z'))) def test_checkDuplicate_miss(self): import os c = self._makeOne() c.checkDuplicate('/path') # doesn't raise self.assertEqual(list(c._seen_files), [os.path.normpath('/path')]) def test_checkDuplicate_hit(self): import os from zope.configuration.exceptions import ConfigurationError c = self._makeOne() c.checkDuplicate('/path') self.assertRaises(ConfigurationError, c.checkDuplicate, '/path') self.assertEqual(list(c._seen_files), [os.path.normpath('/path')]) def test_processFile_miss(self): import os c = self._makeOne() self.assertEqual(c.processFile('/path'), True) self.assertEqual(list(c._seen_files), [os.path.normpath('/path')]) def test_processFile_hit(self): import os c = self._makeOne() c.processFile('/path') self.assertEqual(c.processFile('/path'), False) self.assertEqual(list(c._seen_files), [os.path.normpath('/path')]) def test_action_defaults_no_info_no_includepath(self): DISCRIMINATOR = ('a', ('b',), 0) c = self._makeOne() c.actions = [] # normally provided by subclass c.action(DISCRIMINATOR) self.assertEqual(len(c.actions), 1) info = c.actions[0] self.assertEqual(info['discriminator'], DISCRIMINATOR) self.assertEqual(info['callable'], None) self.assertEqual(info['args'], ()) self.assertEqual(info['kw'], {}) self.assertEqual(info['includepath'], ()) self.assertEqual(info['info'], '') self.assertEqual(info['order'], 0) def test_action_defaults_w_info_w_includepath(self): DISCRIMINATOR = ('a', ('b',), 0) c = self._makeOne() c.actions = [] # normally provided by subclass c.info = 'INFO' # normally provided by subclass c.includepath = ('a', 'b') # normally provided by subclass c.action(DISCRIMINATOR) self.assertEqual(len(c.actions), 1) info = c.actions[0] self.assertEqual(info['discriminator'], DISCRIMINATOR) self.assertEqual(info['callable'], None) self.assertEqual(info['args'], ()) self.assertEqual(info['kw'], {}) self.assertEqual(info['order'], 0) self.assertEqual(info['includepath'], ('a', 'b')) self.assertEqual(info['info'], 'INFO') def test_action_explicit_no_extra(self): DISCRIMINATOR = ('a', ('b',), 0) ARGS = (12, 'z') KW = {'one': 1} INCLUDE_PATH = ('p', 'q/r') INFO = 'INFO' def _callable(): pass c = self._makeOne() c.actions = [] # normally provided by subclass c.action(DISCRIMINATOR, _callable, ARGS, KW, 42, INCLUDE_PATH, INFO, ) self.assertEqual(len(c.actions), 1) info = c.actions[0] self.assertEqual(info['discriminator'], DISCRIMINATOR) self.assertEqual(info['callable'], _callable) self.assertEqual(info['args'], ARGS) self.assertEqual(info['kw'], KW) self.assertEqual(info['order'], 42) self.assertEqual(info['includepath'], INCLUDE_PATH) self.assertEqual(info['info'], INFO) def test_action_explicit_w_extra(self): DISCRIMINATOR = ('a', ('b',), 0) ARGS = (12, 'z') KW = {'one': 1} INCLUDE_PATH = ('p', 'q/r') INFO = 'INFO' def _callable(): pass c = self._makeOne() c.actions = [] # normally provided by subclass c.action(DISCRIMINATOR, _callable, ARGS, KW, 42, INCLUDE_PATH, INFO, foo='bar', baz=17, ) self.assertEqual(len(c.actions), 1) info = c.actions[0] self.assertEqual(info['discriminator'], DISCRIMINATOR) self.assertEqual(info['callable'], _callable) self.assertEqual(info['args'], ARGS) self.assertEqual(info['kw'], KW) self.assertEqual(info['order'], 42) self.assertEqual(info['includepath'], INCLUDE_PATH) self.assertEqual(info['info'], INFO) self.assertEqual(info['foo'], 'bar') self.assertEqual(info['baz'], 17) def test_hasFeature_miss(self): c = self._makeOne() self.assertFalse(c.hasFeature('nonesuch')) def test_hasFeature_hit(self): c = self._makeOne() c._features.add('a.feature') self.assertTrue(c.hasFeature('a.feature')) def test_provideFeature(self): c = self._makeOne() c.provideFeature('a.feature') self.assertTrue(c.hasFeature('a.feature')) class ConfigurationAdapterRegistryTests(unittest.TestCase): def _getTargetClass(self): from zope.configuration.config import ConfigurationAdapterRegistry return ConfigurationAdapterRegistry def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor(self): reg = self._makeOne() self.assertEqual(len(reg._registry), 0) self.assertEqual(len(reg._docRegistry), 0) def test_register(self): from zope.interface import Interface class IFoo(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' def _factory(): pass reg = self._makeOne() reg.register(IFoo, (NS, NAME), _factory) self.assertEqual(len(reg._registry), 1) areg = reg._registry[(NS, NAME)] self.assertTrue(areg.lookup1(IFoo, Interface) is _factory) self.assertEqual(len(reg._docRegistry), 0) def test_register_replacement(self): from zope.interface import Interface class IFoo(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' def _factory(): pass def _rival(): pass reg = self._makeOne() reg.register(IFoo, (NS, NAME), _factory) reg.register(IFoo, (NS, NAME), _rival) self.assertEqual(len(reg._registry), 1) areg = reg._registry[(NS, NAME)] self.assertTrue(areg.lookup1(IFoo, Interface) is _rival) self.assertEqual(len(reg._docRegistry), 0) def test_register_new_name(self): from zope.interface import Interface class IFoo(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' NAME2 = 'other' def _factory(): pass def _rival(): pass reg = self._makeOne() reg.register(IFoo, (NS, NAME), _factory) reg.register(IFoo, (NS, NAME2), _rival) self.assertEqual(len(reg._registry), 2) areg = reg._registry[(NS, NAME)] self.assertTrue(areg.lookup1(IFoo, Interface) is _factory) areg = reg._registry[(NS, NAME2)] self.assertTrue(areg.lookup1(IFoo, Interface) is _rival) self.assertEqual(len(reg._docRegistry), 0) def test_document_non_string_name(self): from zope.interface import Interface class ISchema(Interface): pass class IUsedIn(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' HANDLER = object() INFO = 'INFO' PARENT = object() reg = self._makeOne() reg.document((NS, NAME), ISchema, IUsedIn, HANDLER, INFO, PARENT) self.assertEqual(len(reg._registry), 0) self.assertEqual(len(reg._docRegistry), 1) name, schema, used_in, handler, info, parent = reg._docRegistry[0] self.assertEqual(name, (NS, NAME)) self.assertEqual(schema, ISchema) self.assertEqual(used_in, IUsedIn) self.assertEqual(info, INFO) self.assertEqual(parent, PARENT) def test_document_w_string_name(self): from zope.interface import Interface class ISchema(Interface): pass class IUsedIn(Interface): pass NAME = 'testing' HANDLER = object() INFO = 'INFO' PARENT = object() reg = self._makeOne() reg.document(NAME, ISchema, IUsedIn, HANDLER, INFO, PARENT) self.assertEqual(len(reg._registry), 0) self.assertEqual(len(reg._docRegistry), 1) name, schema, used_in, handler, info, parent = reg._docRegistry[0] self.assertEqual(name, ('', NAME)) self.assertEqual(schema, ISchema) self.assertEqual(used_in, IUsedIn) self.assertEqual(info, INFO) self.assertEqual(parent, PARENT) def test_factory_miss(self): from zope.configuration.exceptions import ConfigurationError NS = 'http://namespace.example.com/' NAME = 'testing' context = object() reg = self._makeOne() self.assertRaises(ConfigurationError, reg.factory, context, (NS, NAME)) def test_factory_hit_on_fqn(self): from zope.interface import Interface from zope.interface import implementer class IFoo(Interface): pass @implementer(IFoo) class Context(object): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = Context() def _factory(): pass reg = self._makeOne() reg.register(IFoo, (NS, NAME), _factory) self.assertEqual(reg.factory(context, (NS, NAME)), _factory) def test_factory_miss_on_fqn_hit_on_bare_name(self): from zope.interface import Interface from zope.interface import implementer class IFoo(Interface): pass @implementer(IFoo) class Context(object): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = Context() def _factory(): pass reg = self._makeOne() reg.register(IFoo, NAME, _factory) self.assertEqual(reg.factory(context, (NS, NAME)), _factory) def test_factory_hit_on_fqn_lookup_fails(self): from zope.interface import Interface from zope.configuration.exceptions import ConfigurationError class IFoo(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = object() # doesn't provide IFoo def _factory(): pass reg = self._makeOne() reg.register(IFoo, (NS, NAME), _factory) self.assertRaises(ConfigurationError, reg.factory, context, (NS, NAME)) class _ConformsToIConfigurationContext(object): def test_class_conforms_to_IConfigurationContext(self): from zope.interface.verify import verifyClass from zope.configuration.interfaces import IConfigurationContext verifyClass(IConfigurationContext, self._getTargetClass()) def test_instance_conforms_to_IConfigurationContext(self): from zope.interface.verify import verifyObject from zope.configuration.interfaces import IConfigurationContext verifyObject(IConfigurationContext, self._makeOne()) class ConfigurationMachineTests(_Catchable, _ConformsToIConfigurationContext, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import ConfigurationMachine return ConfigurationMachine def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor(self): from zope.configuration.config import RootStackItem from zope.configuration.config import metans cm = self._makeOne() self.assertEqual(cm.package, None) self.assertEqual(cm.basepath, None) self.assertEqual(cm.includepath, ()) self.assertEqual(cm.info, '') self.assertEqual(len(cm.actions), 0) self.assertEqual(len(cm.stack), 1) root = cm.stack[0] self.assertTrue(isinstance(root, RootStackItem)) self.assertTrue(root.context is cm) self.assertEqual(len(cm.i18n_strings), 0) # Check bootstrapped meta:*. self.assertTrue((metans, 'directive') in cm._registry) self.assertTrue((metans, 'directives') in cm._registry) self.assertTrue((metans, 'complexDirective') in cm._registry) self.assertTrue((metans, 'groupingDirective') in cm._registry) self.assertTrue((metans, 'provides') in cm._registry) self.assertTrue((metans, 'subdirective') in cm._registry) def test_begin_w___data_and_kw(self): from zope.configuration.config import IConfigurationContext NS = 'http://namespace.example.com/' NAME = 'testing' def _factory(context, data, info): pass cm = self._makeOne() cm.register(IConfigurationContext, (NS, NAME), _factory) self.assertRaises(TypeError, cm.begin, (NS, NAME), {'foo': 'bar'}, baz='bam') def test_begin_w___data_no_kw(self): from zope.interface import Interface from zope.configuration.config import IConfigurationContext from zope.configuration.config import RootStackItem class ISchema(Interface): pass class IUsedIn(Interface): pass def _handler(*args, **kw): pass NS = 'http://namespace.example.com/' NAME = 'testing' _called_with = [] item = object() def _factory(context, data, info): _called_with.append((context, data, info)) return item cm = self._makeOne() cm.register(IConfigurationContext, (NS, NAME), _factory) cm.begin((NS, NAME), {'name': 'testing', 'schema': ISchema, 'usedIn': IUsedIn, 'handler': _handler, }, 'INFO') self.assertEqual(len(cm.stack), 2) root = cm.stack[0] self.assertTrue(isinstance(root, RootStackItem)) nested = cm.stack[1] self.assertTrue(nested is item) self.assertEqual(_called_with, [(cm, {'name': 'testing', 'schema': ISchema, 'usedIn': IUsedIn, 'handler': _handler, }, 'INFO')]) def test_begin_wo___data_w_kw(self): from zope.interface import Interface from zope.configuration.config import IConfigurationContext from zope.configuration.config import RootStackItem class ISchema(Interface): pass class IUsedIn(Interface): pass def _handler(*args, **kw): pass NS = 'http://namespace.example.com/' NAME = 'testing' _called_with = [] item = object() def _factory(context, data, info): _called_with.append((context, data, info)) return item cm = self._makeOne() cm.register(IConfigurationContext, (NS, NAME), _factory) cm.begin((NS, NAME), None, 'INFO', name='testing', schema=ISchema, usedIn=IUsedIn, handler=_handler, ) self.assertEqual(len(cm.stack), 2) root = cm.stack[0] self.assertTrue(isinstance(root, RootStackItem)) nested = cm.stack[1] self.assertTrue(nested is item) self.assertEqual(_called_with, [(cm, {'name': 'testing', 'schema': ISchema, 'usedIn': IUsedIn, 'handler': _handler, }, 'INFO')]) def test_end(self): from zope.configuration.config import RootStackItem class FauxItem(object): _finished = False def finish(self): self._finished = True cm = self._makeOne() item = FauxItem() cm.stack.append(item) cm.end() self.assertEqual(len(cm.stack), 1) root = cm.stack[0] self.assertTrue(isinstance(root, RootStackItem)) self.assertTrue(item._finished) def test___call__(self): from zope.interface import Interface from zope.configuration.config import IConfigurationContext from zope.configuration.config import RootStackItem class ISchema(Interface): pass class IUsedIn(Interface): pass class FauxItem(object): _finished = False def finish(self): self._finished = True def _handler(*args, **kw): pass NS = 'http://namespace.example.com/' NAME = 'testing' _called_with = [] item = FauxItem() def _factory(context, data, info): _called_with.append((context, data, info)) return item cm = self._makeOne() cm.register(IConfigurationContext, (NS, NAME), _factory) cm((NS, NAME), 'INFO', name='testing', schema=ISchema, usedIn=IUsedIn, handler=_handler, ) self.assertEqual(len(cm.stack), 1) root = cm.stack[0] self.assertTrue(isinstance(root, RootStackItem)) self.assertEqual(_called_with, [(cm, {'name': 'testing', 'schema': ISchema, 'usedIn': IUsedIn, 'handler': _handler, }, 'INFO')]) self.assertTrue(item._finished) def test_getInfo_only_root_default(self): cm = self._makeOne() self.assertEqual(cm.getInfo(), '') def test_getInfo_only_root(self): cm = self._makeOne() cm.info = 'INFO' self.assertEqual(cm.getInfo(), 'INFO') def test_getInfo_w_item(self): class FauxItem(object): info = 'FAUX' def __init__(self): self.context = self cm = self._makeOne() cm.stack.append(FauxItem()) self.assertEqual(cm.getInfo(), 'FAUX') def test_setInfo_only_root(self): cm = self._makeOne() cm.setInfo('INFO') self.assertEqual(cm.info, 'INFO') def test_setInfo_w_item(self): class FauxItem(object): info = 'FAUX' def __init__(self): self.context = self cm = self._makeOne() item = FauxItem() cm.stack.append(item) cm.setInfo('UPDATED') self.assertEqual(item.info, 'UPDATED') def test_execute_actions_empty(self): cm = self._makeOne() cm.execute_actions() # noop def test_execute_actions_wo_errors(self): _called_with = {} def _a1(*args, **kw): _called_with.setdefault('_a1', []).append((args, kw)) def _a2(*args, **kw): _called_with.setdefault('_a2', []).append((args, kw)) cm = self._makeOne() cm.action(None, None) # will be skipped cm.action(None, _a1, ('a', 0), {'foo': 'bar'}, 4) cm.action(None, _a2, ('a', 1), {'foo': 'baz'}, 3) cm.action(None, _a1, ('b', 2), {'foo': 'qux'}, 2) cm.execute_actions() self.assertEqual(_called_with['_a1'], [(('b', 2), {'foo': 'qux'}), (('a', 0), {'foo': 'bar'}), ]) self.assertEqual(_called_with['_a2'], [(('a', 1), {'foo': 'baz'}), ]) def test_execute_actions_w_errors_w_testing(self): def _err(*args, **kw): raise ValueError('XXX') cm = self._makeOne() cm.action(None, _err) exc = self.assertRaises(ValueError, cm.execute_actions, testing=True) self.assertEqual(str(exc), 'XXX') def test_execute_actions_w_errors_wo_testing(self): from zope.configuration.config import ConfigurationExecutionError def _err(*args, **kw): raise ValueError('XXX') cm = self._makeOne() cm.info = 'INFO' cm.action(None, _err) exc = self.assertRaises(ConfigurationExecutionError, cm.execute_actions) self.assertTrue(exc.etype is ValueError) self.assertEqual(str(exc.evalue), "XXX") self.assertEqual(exc.info, "INFO") def test_keyword_handling(self): # This is really an integraiton test. from zope.configuration.config import metans from zope.configuration.tests.directives import f from zope.configuration._compat import b from zope.configuration._compat import u machine = self._makeOne() ns = "http://www.zope.org/testing" #Register some test directives, starting with a grouping directive # that sets a package: machine((metans, "groupingDirective"), name="package", namespace=ns, schema="zope.configuration.tests.directives.IPackaged", handler="zope.configuration.tests.directives.Packaged", ) # set the package: machine.begin((ns, "package"), package="zope.configuration.tests.directives", ) #Which makes it easier to define the other directives: machine((metans, "directive"), namespace=ns, name="k", schema=".Ik", handler=".k") machine((ns, "k"), "yee ha", **{"for": u("f"), "class": u("c"), "x": u("x")}) self.assertEqual(len(machine.actions), 1) self.assertEqual(machine.actions[0], {'args': (b('f'), b('c'), b('x')), 'callable': f, 'discriminator': ('k', b('f')), 'includepath': (), 'info': 'yee ha', 'kw': {}, 'order': 0, }) class _ConformsToIStackItem(object): def test_class_conforms_to_IStackItem(self): from zope.interface.verify import verifyClass from zope.configuration.config import IStackItem verifyClass(IStackItem, self._getTargetClass()) def test_instance_conforms_to_IStackItem(self): from zope.interface.verify import verifyObject from zope.configuration.config import IStackItem verifyObject(IStackItem, self._makeOne()) class SimpleStackItemTests(_ConformsToIStackItem, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import SimpleStackItem return SimpleStackItem def _makeOne(self, context=None, handler=None, info=None, schema=None, data=None): from zope.interface import Interface if context is None: context = FauxContext() if handler is None: def handler(): pass if info is None: info = 'INFO' if schema is None: schema = Interface if data is None: data = {} return self._getTargetClass()(context, handler, info, schema, data) def test_ctor(self): from zope.interface import Interface from zope.configuration.config import GroupingContextDecorator class ISchema(Interface): pass context = FauxContext() def _handler(): pass _data = {} ssi = self._makeOne(context, _handler, 'INFO', ISchema, _data) self.assertTrue(isinstance(ssi.context, GroupingContextDecorator)) self.assertTrue(ssi.context.context is context) self.assertEqual(ssi.context.info, 'INFO') self.assertEqual(ssi.handler, _handler) self.assertEqual(ssi.argdata, (ISchema, _data)) def test_contained_raises(self): from zope.configuration.exceptions import ConfigurationError ssi = self._makeOne() self.assertRaises(ConfigurationError, ssi.contained, ('ns', 'name'), {}, '') def test_finish_handler_returns_no_actions(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): name = Text(required=True) context = FauxContext() def _handler(context, **kw): return () _data = {'name': 'NAME'} ssi = self._makeOne(context, _handler, 'INFO', ISchema, _data) ssi.finish() # noraise self.assertEqual(context.actions, []) def test_finish_handler_returns_oldstyle_actions(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): name = Text(required=True) context = FauxContext() def _action(context, **kw): pass def _handler(context, **kw): return [(None, _action)] _data = {'name': 'NAME'} ssi = self._makeOne(context, _handler, 'INFO', ISchema, _data) ssi.finish() self.assertEqual(context.actions, [{'discriminator': None, 'callable': _action, 'args': (), 'kw': {}, 'includepath': (), 'info': 'INFO', 'order': 0, }]) def test_finish_handler_returns_newstyle_actions(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): name = Text(required=True) context = FauxContext() def _action(context, **kw): pass def _handler(context, **kw): return [{'discriminator': None, 'callable': _action}] _data = {'name': 'NAME'} ssi = self._makeOne(context, _handler, 'INFO', ISchema, _data) ssi.finish() self.assertEqual(context.actions, [{'discriminator': None, 'callable': _action, 'args': (), 'kw': {}, 'includepath': (), 'info': 'INFO', 'order': 0, }]) class RootStackItemTests(_ConformsToIStackItem, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import RootStackItem return RootStackItem def _makeOne(self, context=None): if context is None: context = object() return self._getTargetClass()(context) def test_contained_context_factory_fails(self): from zope.configuration.exceptions import ConfigurationError class _Context(object): def factory(self, context, name): pass rsi = self._makeOne(_Context()) self.assertRaises(ConfigurationError, rsi.contained, ('ns', 'name'), {}, '') def test_contained_context_factory_normal(self): _called_with = [] _adapter = object() def _factory(context, data, info): _called_with.append((context, data, info)) return _adapter class _Context(object): def factory(self, context, name): return _factory context = _Context() rsi = self._makeOne(context) adapter = rsi.contained(('ns', 'name'), {'a': 'b'}, 'INFO') self.assertTrue(adapter is _adapter) self.assertEqual(_called_with, [(context, {'a': 'b'}, 'INFO')]) def test_finish(self): rsi = self._makeOne() rsi.finish() #noraise class GroupingStackItemTests(_ConformsToIStackItem, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import GroupingStackItem return GroupingStackItem def _makeOne(self, context=None): if context is None: context = object() return self._getTargetClass()(context) def test_contained_context_before_returns_oldstyle_actions(self): _called_with = [] _adapter = object() def _factory(context, data, info): _called_with.append((context, data, info)) return _adapter def _action(*args, **kw): pass class _Context(FauxContext): def factory(self, context, name): return _factory def before(self): return [(None, _action)] def after(self): return () context = _Context() rsi = self._makeOne(context) adapter = rsi.contained(('ns', 'name'), {'a': 'b'}, 'INFO') self.assertTrue(adapter is _adapter) self.assertEqual(_called_with, [(context, {'a': 'b'}, 'INFO')]) self.assertEqual(len(context.actions), 1) self.assertEqual(context.actions[0], {'discriminator': None, 'callable': _action, 'args': (), 'kw': {}, 'includepath': (), 'info': None, 'order': 0, }) rsi.finish() # doesn't re-do the 'before' dance self.assertEqual(len(context.actions), 1) def test_contained_context_before_returns_newstyle_actions(self): _called_with = [] _adapter = object() def _factory(context, data, info): _called_with.append((context, data, info)) return _adapter def _before(*args, **kw): pass def _after(*args, **kw): pass class _Context(FauxContext): def factory(self, context, name): return _factory def before(self): return [{'discriminator': None, 'callable': _before}] def after(self): return [{'discriminator': None, 'callable': _after}] context = _Context() rsi = self._makeOne(context) adapter = rsi.contained(('ns', 'name'), {'a': 'b'}, 'INFO') self.assertTrue(adapter is _adapter) self.assertEqual(_called_with, [(context, {'a': 'b'}, 'INFO')]) self.assertEqual(len(context.actions), 1) self.assertEqual(context.actions[0], # no GSI to add extras {'discriminator': None, 'callable': _before, }) rsi.finish() # doesn't re-do the 'before' dance self.assertEqual(len(context.actions), 2) self.assertEqual(context.actions[1], {'discriminator': None, 'callable': _after, }) def test_finish_calls_before_if_not_already_called(self): def _before(*args, **kw): pass def _after(*args, **kw): pass class _Context(FauxContext): def before(self): return [(None, _before)] def after(self): return [(None, _after)] context = _Context() rsi = self._makeOne(context) adapter = rsi.finish() self.assertEqual(len(context.actions), 2) self.assertEqual(context.actions[0], # no GSI to add extras {'discriminator': None, 'callable': _before, 'args': (), 'kw': {}, 'includepath': (), 'info': None, 'order': 0, }) self.assertEqual(context.actions[1], {'discriminator': None, 'callable': _after, 'args': (), 'kw': {}, 'includepath': (), 'info': None, 'order': 0, }) class ComplexStackItemTests(_ConformsToIStackItem, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import ComplexStackItem return ComplexStackItem def _makeOne(self, meta=None, context=None, data=None, info=None): if meta is None: meta = self._makeMeta() if context is None: context = object() if data is None: data = {'name': 'NAME'} if info is None: info = 'INFO' return self._getTargetClass()(meta, context, data, info) def _makeMeta(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): name = Text() class FauxMeta(dict): schema = ISchema _handler_args = None _handler = object() def handler(self, newcontext, **kw): self._handler_kwargs = kw return self._handler return FauxMeta() def test_ctor(self): from zope.configuration.config import GroupingContextDecorator meta = self._makeMeta() context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') self.assertTrue(isinstance(csi.context, GroupingContextDecorator)) self.assertTrue(csi.context.context is context) self.assertEqual(csi.context.info, 'INFO') self.assertEqual(csi.handler, meta._handler) self.assertEqual(meta._handler_kwargs, _data) def test_contained_miss(self): from zope.configuration.exceptions import ConfigurationError NS = 'http://namespace.example.com/' NAME = 'testing' csi = self._makeOne() self.assertRaises(ConfigurationError, csi.contained, (NS, NAME), {}, 'INFO') def test_contained_hit(self): from zope.interface import Interface from zope.configuration.config import GroupingContextDecorator from zope.configuration.config import SimpleStackItem NS = 'http://namespace.example.com/' NAME = 'testing' class ISubSchema(Interface): pass class WithName(object): def testing(self, *args): pass meta = self._makeMeta() wn = meta._handler = WithName() meta[NAME] = (ISubSchema, 'SUBINFO') context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') ssi = csi.contained((NS, NAME), {}, 'SUBINFO') self.assertTrue(isinstance(ssi, SimpleStackItem)) self.assertTrue(isinstance(ssi.context, GroupingContextDecorator)) self.assertTrue(ssi.context.context is csi.context) self.assertEqual(ssi.context.info, 'SUBINFO') self.assertEqual(ssi.handler, wn.testing) self.assertEqual(ssi.argdata, (ISubSchema, {})) def test_finish_handler_is_noncallable(self): meta = self._makeMeta() context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') csi.finish() #noraise self.assertEqual(len(context.actions), 0) def test_finish_handler_raises_AE_for___call__(self): def _handler(): raise AttributeError('__call__') meta = self._makeMeta() meta._handler = _handler context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') csi.finish() #noraise self.assertEqual(len(context.actions), 0) def test_finish_handler_raises_AE_for_other(self): def _handler(): raise AttributeError('other') meta = self._makeMeta() meta._handler = _handler context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') self.assertRaises(AttributeError, csi.finish) def test_finish_handler_returns_oldstyle_actions(self): def _action(): pass def _handler(): return [(None, _action)] meta = self._makeMeta() meta._handler = _handler context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') csi.finish() self.assertEqual(len(context.actions), 1) self.assertEqual(context.actions[0], {'discriminator': None, 'callable': _action, 'args': (), 'kw': {}, 'includepath': (), 'info': 'INFO', 'order': 0, }) def test_finish_handler_returns_newstyle_actions(self): def _action(): pass def _handler(): return [{'discriminator': None, 'callable': _action}] meta = self._makeMeta() meta._handler = _handler context = FauxContext() _data = {'name': 'NAME'} csi = self._makeOne(meta, context, _data, 'INFO') csi.finish() self.assertEqual(len(context.actions), 1) self.assertEqual(context.actions[0], {'discriminator': None, 'callable': _action, 'args': (), 'kw': {}, 'includepath': (), 'info': 'INFO', 'order': 0, }) class _ConformsToIGroupingContext(object): def test_class_conforms_to_IGroupingContext(self): from zope.interface.verify import verifyClass from zope.configuration.interfaces import IGroupingContext verifyClass(IGroupingContext, self._getTargetClass()) def test_instance_conforms_to_IGroupingContext(self): from zope.interface.verify import verifyObject from zope.configuration.interfaces import IGroupingContext verifyObject(IGroupingContext, self._makeOne()) class GroupingContextDecoratorTests(_ConformsToIConfigurationContext, _ConformsToIGroupingContext, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import GroupingContextDecorator return GroupingContextDecorator def _makeOne(self, context=None, **kw): if context is None: context = FauxContext() context.package = None #appease IConfigurationContext instance = self._getTargetClass()(context, **kw) return instance def test_ctor_no_kwargs(self): context = FauxContext() gcd = self._makeOne(context) self.assertTrue(gcd.context is context) def test_ctor_w_kwargs(self): context = FauxContext() gcd = self._makeOne(context, foo='bar', baz=42) self.assertTrue(gcd.context is context) self.assertEqual(gcd.foo, 'bar') self.assertEqual(gcd.baz, 42) def test_getattr_fetches_from_context_and_caches(self): context = FauxContext() gcd = self._makeOne(context) context.foo = 'bar' self.assertEqual(gcd.foo, 'bar') self.assertTrue('foo' in gcd.__dict__) def test_before(self): gcd = self._makeOne() gcd.before() #noraise def test_after(self): gcd = self._makeOne() gcd.after() #noraise class _ConformsToIDirectivesContext(object): def test_class_conforms_to_IDirectivesContext(self): from zope.interface.verify import verifyClass from zope.configuration.config import IDirectivesContext verifyClass(IDirectivesContext, self._getTargetClass()) def test_instance_conforms_to_IDirectivesContext(self): from zope.interface.verify import verifyObject from zope.configuration.config import IDirectivesContext verifyObject(IDirectivesContext, self._makeOne()) class DirectivesHandlerTests(_ConformsToIDirectivesContext, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import DirectivesHandler return DirectivesHandler def _makeOne(self, context=None): if context is None: context = FauxContext() context.package = None #appease IConfigurationContext context.namespace = None #appease IDirectivesInfo instance = self._getTargetClass()(context) return instance class Test_defineSimpleDirective(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import defineSimpleDirective return defineSimpleDirective(*args, **kw) def _makeContext(self): class _Context(FauxContext): def __init__(self): self._registered = [] self._documented = [] def register(self, usedIn, name, factory): self._registered.append((usedIn, name, factory)) def document(self, name, schema, usedIn, handler, info): self._documented.append((name, schema, usedIn, handler, info)) return _Context() def test_defaults(self): from zope.interface import Interface from zope.configuration.interfaces import IConfigurationContext as ICC class ISchema(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = self._makeContext() context.namespace = NS context.info = 'INFO' def _handler(): pass self._callFUT(context, NAME, ISchema, _handler) self.assertEqual(len(context._registered), 1) usedIn, name, factory = context._registered[0] self.assertEqual(usedIn, ICC) self.assertEqual(name, (NS, NAME)) sub = object() ssi = factory(sub, {'a': 1}, 'SUBINFO') self.assertTrue(ssi.context.context is sub) self.assertEqual(ssi.context.info, 'SUBINFO') self.assertEqual(ssi.handler, _handler) self.assertEqual(len(context._documented), 1) self.assertEqual(context._documented[0], ((NS, NAME), ISchema, ICC, _handler, 'INFO')) def test_explicit_w_star_namespace(self): from zope.interface import Interface class ISchema(Interface): pass class IUsedIn(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = self._makeContext() context.namespace = NS context.info = 'INFO' def _handler(): pass self._callFUT(context, NAME, ISchema, _handler, namespace='*', usedIn=IUsedIn) self.assertEqual(len(context._registered), 1) usedIn, name, factory = context._registered[0] self.assertEqual(usedIn, IUsedIn) self.assertEqual(name, NAME) sub = object() ssi = factory(sub, {'a': 1}, 'SUBINFO') self.assertTrue(ssi.context.context is sub) self.assertEqual(ssi.context.info, 'SUBINFO') self.assertEqual(ssi.handler, _handler) self.assertEqual(len(context._documented), 1) self.assertEqual(context._documented[0], (NAME, ISchema, IUsedIn, _handler, 'INFO')) class Test_defineGroupingDirective(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import defineGroupingDirective return defineGroupingDirective(*args, **kw) def _makeContext(self): class _Context(FauxContext): def __init__(self): self._registered = [] self._documented = [] def register(self, usedIn, name, factory): self._registered.append((usedIn, name, factory)) def document(self, name, schema, usedIn, handler, info): self._documented.append((name, schema, usedIn, handler, info)) return _Context() def test_defaults(self): from zope.interface import Interface from zope.schema import Text from zope.configuration.interfaces import IConfigurationContext as ICC class ISchema(Interface): arg = Text() NS = 'http://namespace.example.com/' NAME = 'testing' context = self._makeContext() context.namespace = NS context.info = 'INFO' newcontext = FauxContext() _called_with = [] def _handler(context, **kw): _called_with.append((context, kw)) return newcontext self._callFUT(context, NAME, ISchema, _handler) self.assertEqual(len(context._registered), 1) usedIn, name, factory = context._registered[0] self.assertEqual(usedIn, ICC) self.assertEqual(name, (NS, NAME)) sub = object() gsi = factory(sub, {'arg': 'val'}, 'SUBINFO') self.assertTrue(gsi.context is newcontext) self.assertEqual(newcontext.info, 'SUBINFO') self.assertEqual(_called_with, [(sub, {'arg': 'val'})]) self.assertEqual(len(context._documented), 1) self.assertEqual(context._documented[0], ((NS, NAME), ISchema, ICC, _handler, 'INFO')) def test_explicit_w_star_namespace(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): arg = Text() class IUsedIn(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' context = self._makeContext() context.namespace = NS context.info = 'INFO' newcontext = FauxContext() _called_with = [] def _handler(context, **kw): _called_with.append((context, kw)) return newcontext self._callFUT(context, NAME, ISchema, _handler, namespace='*', usedIn=IUsedIn) self.assertEqual(len(context._registered), 1) usedIn, name, factory = context._registered[0] self.assertEqual(usedIn, IUsedIn) self.assertEqual(name, NAME) sub = object() gsi = factory(sub, {'arg': 'val'}, 'SUBINFO') self.assertTrue(gsi.context is newcontext) self.assertEqual(newcontext.info, 'SUBINFO') self.assertEqual(_called_with, [(sub, {'arg': 'val'})]) self.assertEqual(len(context._documented), 1) self.assertEqual(context._documented[0], (NAME, ISchema, IUsedIn, _handler, 'INFO')) class _ConformsToIComplexDirectiveContext(object): def test_class_conforms_to_IComplexDirectiveContext(self): from zope.interface.verify import verifyClass from zope.configuration.config import IComplexDirectiveContext verifyClass(IComplexDirectiveContext, self._getTargetClass()) def test_instance_conforms_to_IComplexDirectiveContext(self): from zope.interface.verify import verifyObject from zope.configuration.config import IComplexDirectiveContext verifyObject(IComplexDirectiveContext, self._makeOne()) class ComplexDirectiveDefinitionTests(_ConformsToIComplexDirectiveContext, unittest.TestCase, ): def _getTargetClass(self): from zope.configuration.config import ComplexDirectiveDefinition return ComplexDirectiveDefinition def _makeOne(self, context=None): if context is None: context = self._makeContext() instance = self._getTargetClass()(context) return instance def _makeContext(self, package=None, namespace=None, name=None, schema=None, handler=None, usedIn=None): context = FauxContext() context.package = package context.namespace = namespace context.name = name context.schema = schema context.handler = handler context.usedIn = usedIn return context def test_before(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): arg = Text() class IUsedIn(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' _handled = [] _csi_handler = object() def _handler(context, **kw): _handled.append((context, kw)) return _csi_handler context = self._makeContext(namespace=NS, name=NAME, schema=ISchema, handler=_handler, usedIn=IUsedIn) context.info = 'INFO' _registered = [] def _register(*args): _registered.append(args) context.register = _register _documented = [] def _document(*args): _documented.append(args) context.document = _document cdd = self._makeOne(context) cdd.before() self.assertEqual(len(_registered), 1) usedIn, fqn, factory = _registered[0] self.assertEqual(usedIn, IUsedIn) self.assertEqual(fqn, (NS, NAME)) sub = FauxContext() csi = factory(sub, {'arg': 'val'}, 'SUBINFO') self.assertEqual(csi.meta, cdd) self.assertEqual(csi.context.context, sub) self.assertEqual(csi.context.info, 'SUBINFO') self.assertEqual(csi.handler, _csi_handler) self.assertEqual(_handled, [(csi.context, {'arg': 'val'})]) self.assertEqual(_documented, [((NS, NAME), ISchema, IUsedIn, _handler, 'INFO')]) class Test_subdirective(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import subdirective return subdirective(*args, **kw) def _makeContext(self, package=None, namespace=None, name=None, schema=None, handler=None, usedIn=None): class _Context(object): def __init__(self): self.context = {} self._documented = [] def document(self, *args): self._documented.append(args) context = _Context() context.package = package context.namespace = namespace context.name = name context.schema = schema context.handler = handler context.usedIn = usedIn return context def test_wo_handler_attribute(self): from zope.interface import Interface from zope.schema import Text class ISubSchema(Interface): arg = Text() class ISchema(Interface): pass class IUsedIn(Interface): pass NS = 'http://namespace.example.com/' NAME = 'testing' SUBNAME = 'sub' _handler = object() context = self._makeContext(None, NS, NAME, ISchema, _handler, IUsedIn) context.info = 'INFO' self._callFUT(context, SUBNAME, ISubSchema) self.assertEqual(len(context._documented), 1) fqn, schema, usedIn, handler, info, ctx = context._documented[0] self.assertEqual(fqn, (NS, SUBNAME)) self.assertEqual(schema, ISubSchema) self.assertEqual(usedIn, IUsedIn) self.assertEqual(handler, _handler) self.assertEqual(info, 'INFO') self.assertEqual(ctx, context.context) self.assertEqual(context.context[SUBNAME], (ISubSchema, 'INFO')) def test_w_handler_attribute(self): from zope.interface import Interface from zope.schema import Text class ISubSchema(Interface): arg = Text() class ISchema(Interface): pass class IUsedIn(Interface): pass class Handler(object): sub = object() NS = 'http://namespace.example.com/' NAME = 'testing' SUBNAME = 'sub' handler = Handler() context = self._makeContext(None, NS, NAME, ISchema, handler, IUsedIn) context.info = 'INFO' self._callFUT(context, SUBNAME, ISubSchema) self.assertEqual(len(context._documented), 1) fqn, schema, usedIn, handler, info, ctx = context._documented[0] self.assertEqual(fqn, (NS, SUBNAME)) self.assertEqual(schema, ISubSchema) self.assertEqual(usedIn, IUsedIn) self.assertEqual(handler, Handler.sub) self.assertEqual(info, 'INFO') self.assertEqual(ctx, context.context) self.assertEqual(context.context[SUBNAME], (ISubSchema, 'INFO')) class Test_provides(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import provides return provides(*args, **kw) def test_w_multiple(self): context = FauxContext() self.assertRaises(ValueError, self._callFUT, context, 'one two') def test_w_single(self): _provided = [] def _provideFeature(feature): _provided.append(feature) context = FauxContext() context.provideFeature = _provideFeature self._callFUT(context, 'one') self.assertEqual(_provided, ['one']) class Test_toargs(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import toargs return toargs(*args, **kw) def test_w_empty_schema_no_data(self): from zope.interface import Interface class ISchema(Interface): pass context = FauxContext() self.assertEqual(self._callFUT(context, ISchema, {}), {}) def test_w_empty_schema_w_data_no_kwargs_allowed(self): from zope.configuration.exceptions import ConfigurationError from zope.interface import Interface class ISchema(Interface): pass context = FauxContext() exc = self.assertRaises(ConfigurationError, self._callFUT, context, ISchema, {'a': 'b'}) self.assertEqual(exc.args, ('Unrecognized parameters:', 'a')) def test_w_empty_schema_w_data_w_kwargs_allowed(self): from zope.interface import Interface class ISchema(Interface): pass ISchema.setTaggedValue('keyword_arguments', True) context = FauxContext() self.assertEqual(self._callFUT(context, ISchema, {'a': 'b'}), {'a': 'b'}) def test_w_keyword_sub(self): from zope.interface import Interface from zope.schema import Text class ISchema(Interface): for_ = Text() context = FauxContext() self.assertEqual(self._callFUT(context, ISchema, {'for': 'foo'}), {'for_': 'foo'}) def test_w_field_missing_no_default(self): from zope.interface import Interface from zope.schema import Text from zope.configuration.exceptions import ConfigurationError class ISchema(Interface): no_default = Text() context = FauxContext() exc = self.assertRaises(ConfigurationError, self._callFUT, context, ISchema, {}) self.assertEqual(exc.args, ('Missing parameter:', 'no_default')) def test_w_field_missing_but_default(self): from zope.interface import Interface from zope.schema import Text from zope.configuration._compat import u class ISchema(Interface): w_default = Text(default=u('default')) context = FauxContext() self.assertEqual(self._callFUT(context, ISchema, {}), {'w_default': 'default'}) def test_w_invalid_value(self): from zope.interface import Interface from zope.schema import Int from zope.configuration.exceptions import ConfigurationError class ISchema(Interface): count = Int(min=0) context = FauxContext() exc = self.assertRaises(ConfigurationError, self._callFUT, context, ISchema, {'count': '-1'}) self.assertEqual(exc.args, ('Invalid value for', 'count', '(-1, 0)')) class Test_expand_action(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import expand_action return expand_action(*args, **kw) def test_defaults(self): self.assertEqual(self._callFUT(('a', 1, None)), {'discriminator': ('a', 1, None), 'callable': None, 'args': (), 'kw': {}, 'includepath': (), 'info': None, 'order': 0, }) def test_explicit_no_extra(self): def _callable(): pass self.assertEqual(self._callFUT(('a', 1, None), _callable, ('b', 2), {'c': None}, ('p', 'q/r'), 'INFO', 42, ), {'discriminator': ('a', 1, None), 'callable': _callable, 'args': ('b', 2), 'kw': {'c': None}, 'includepath': ('p', 'q/r'), 'info': 'INFO', 'order': 42, }) def test_explicit_w_extra(self): def _callable(): pass self.assertEqual(self._callFUT(('a', 1, None), _callable, ('b', 2), {'c': None}, ('p', 'q/r'), 'INFO', 42, foo='bar', baz=None, ), {'discriminator': ('a', 1, None), 'callable': _callable, 'args': ('b', 2), 'kw': {'c': None}, 'includepath': ('p', 'q/r'), 'info': 'INFO', 'order': 42, 'foo': 'bar', 'baz': None, }) class Test_resolveConflicts(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.config import resolveConflicts return resolveConflicts(*args, **kw) def test_empty(self): self.assertEqual(self._callFUT(()), []) def test_expands_oldstyle_actions(self): def _callable(): pass self.assertEqual(self._callFUT([(None, _callable)]), [{'discriminator': None, 'callable': _callable, 'args': (), 'kw': {}, 'includepath': (), 'info': None, 'order': 0, }]) def test_wo_discriminator_clash(self): from zope.configuration.config import expand_action def _a(): pass def _b(): pass def _c(): pass def _d(): pass actions = [expand_action(('a', 1), _a, order=3), expand_action(('b', 2), _b, order=1), expand_action(('c', 3), _c, order=2), expand_action(('d', 4), _d, order=1), ] self.assertEqual([x['callable'] for x in self._callFUT(actions)], [_b, _d, _c, _a]) def test_w_resolvable_discriminator_clash(self): from zope.configuration.config import expand_action def _a(): pass def _b(): pass actions = [expand_action(('a', 1), _a, includepath=('a',)), expand_action(('a', 1), _b, includepath=('a', 'b')), ] self.assertEqual([x['callable'] for x in self._callFUT(actions)], [_a]) def test_w_non_resolvable_discriminator_clash_different_paths(self): from zope.configuration.config import ConfigurationConflictError from zope.configuration.config import expand_action def _a(): pass def _b(): pass actions = [expand_action(('a', 1), _a, includepath=('b','c'), info='X'), expand_action(('a', 1), _b, includepath=('a',), info='Y'), ] exc = self.assertRaises(ConfigurationConflictError, self._callFUT, actions) self.assertEqual(exc._conflicts, {('a', 1): ['Y', 'X']}) def test_w_non_resolvable_discriminator_clash_same_path(self): from zope.configuration.config import ConfigurationConflictError from zope.configuration.config import expand_action def _a(): pass def _b(): pass actions = [expand_action(('a', 1), _a, includepath=('a',), info='X'), expand_action(('a', 1), _b, includepath=('a',), info='Y'), ] exc = self.assertRaises(ConfigurationConflictError, self._callFUT, actions) self.assertEqual(exc._conflicts, {('a', 1): ['X', 'Y']}) def test_wo_discriminators_final_sorting_order(self): from zope.configuration.config import expand_action def _a(): pass def _b(): pass def _c(): pass def _d(): pass actions = [expand_action(None, _a, order=3), expand_action(None, _b, order=1), expand_action(None, _c, order=2), expand_action(None, _d, order=1), ] self.assertEqual([x['callable'] for x in self._callFUT(actions)], [_b, _d, _c, _a]) class FauxContext(object): def __init__(self): self.actions = [] def action(self, **kw): self.actions.append(kw) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ConfigurationContextTests), unittest.makeSuite(ConfigurationAdapterRegistryTests), unittest.makeSuite(ConfigurationMachineTests), unittest.makeSuite(SimpleStackItemTests), unittest.makeSuite(RootStackItemTests), unittest.makeSuite(GroupingStackItemTests), unittest.makeSuite(ComplexStackItemTests), unittest.makeSuite(GroupingContextDecoratorTests), unittest.makeSuite(DirectivesHandlerTests), unittest.makeSuite(Test_defineSimpleDirective), unittest.makeSuite(Test_defineGroupingDirective), unittest.makeSuite(ComplexDirectiveDefinitionTests), unittest.makeSuite(Test_subdirective), unittest.makeSuite(Test_provides), unittest.makeSuite(Test_toargs), unittest.makeSuite(Test_expand_action), unittest.makeSuite(Test_resolveConflicts), )) zope.configuration-4.0.3/src/zope/configuration/tests/test_name.py0000664000175000017500000001120212073042162025346 0ustar tseavertseaver############################################################################## # # Copyright (c) 20!2 Zope Foundation 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. # ############################################################################## """Test zope.configuration.name """ import unittest class Test_resolve(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.name import resolve return resolve(*args, **kw) def test_top_level_module(self): import os self.assertTrue(self._callFUT('os') is os) def test_nested_module(self): import os.path self.assertTrue(self._callFUT('os.path') is os.path) def test_function_in_module(self): import os.path self.assertTrue(self._callFUT('os.path.join') is os.path.join) def test_importable_but_not_attr_of_parent(self): import sys import zope.configuration.tests as zct self.assertFalse('notyet' in zct.__dict__) mod = self._callFUT('zope.configuration.tests.notyet') self.assertTrue(mod is zct.notyet) del zct.notyet del sys.modules['zope.configuration.tests.notyet'] def test_function_in_module_relative(self): import os.path self.assertTrue(self._callFUT('.join', 'os.path') is os.path.join) def test_class_in_module(self): from zope.configuration.tests.directives import Complex self.assertTrue( self._callFUT('zope.configuration.tests.directives.Complex') is Complex) def test_class_w_same_name_as_module(self): from zope.configuration.tests.samplepackage.NamedForClass \ import NamedForClass self.assertTrue( self._callFUT( 'zope.configuration.tests.samplepackage.NamedForClass+') is NamedForClass) self.assertTrue( self._callFUT( 'zope.configuration.tests.samplepackage.NamedForClass.') is NamedForClass) class Test_getNormalizedName(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.name import getNormalizedName return getNormalizedName(*args, **kw) def test_no_dots(self): self.assertEqual(self._callFUT('os', None), 'os') def test_one_dot(self): self.assertEqual(self._callFUT('os.path', None), 'os.path') def test_two_dots(self): self.assertEqual(self._callFUT('os.path.join', None), 'os.path.join') def test_relative(self): self.assertEqual(self._callFUT('.join', 'os.path'), 'os.path.join') def test_repeat_plus(self): self.assertEqual( self._callFUT('zope.configuration.tests.NamedForClass+', None), 'zope.configuration.tests.NamedForClass+') def test_repeat_dot(self): self.assertEqual( self._callFUT('zope.configuration.tests.NamedForClass.', None), 'zope.configuration.tests.NamedForClass+') def test_repeat_inferred(self): self.assertEqual( self._callFUT( 'zope.configuration.tests.NamedForClass.NamedForClass', None), 'zope.configuration.tests.NamedForClass+') class Test_path(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.name import path return path(*args, **kw) def test_absolute(self): import os absolute_path = os.path.abspath('/absolute') self.assertEqual(self._callFUT(absolute_path), os.path.normpath(absolute_path)) def test_relative_bogus_package(self): self.assertRaises(ImportError, self._callFUT, '', 'no.such.package.exists') def test_relative_empty(self): import os self.assertEqual(self._callFUT('', 'zope.configuration.tests'), os.path.dirname(__file__)) def test_relative_w_file(self): import os self.assertEqual( self._callFUT('configure.zcml', 'zope.configuration.tests'), os.path.join(os.path.dirname(__file__), 'configure.zcml')) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(Test_resolve), unittest.makeSuite(Test_resolve), unittest.makeSuite(Test_path), )) zope.configuration-4.0.3/src/zope/configuration/tests/simple.py0000664000175000017500000000324712073042162024672 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """ Utilities for the 'simple directive' section in the narrative docs. """ from zope.interface import Interface from zope.schema import Text from zope.configuration.fields import Path from zope.configuration._compat import u class IRegisterFile(Interface): path = Path( title=u("File path"), description=u("This is the path name of the file to be registered."), ) title = Text( title=u("Short summary of the file"), description=u("This will be used in file listings"), required = False ) class FileInfo(object): def __init__(self, path, title, description, info): (self.path, self.title, self.description, self.info ) = path, title, description, info file_registry = [] def registerFile(context, path, title=u("")): info = context.info description = info.text.strip() context.action(discriminator=('RegisterFile', path), callable=file_registry.append, args=(FileInfo(path, title, description, info),) ) zope.configuration-4.0.3/src/zope/configuration/tests/test_xmlconfig.py0000664000175000017500000014063612073042162026432 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """Test zope.configuration.xmlconfig. """ import unittest from zope.configuration._compat import u NS = u('ns') FOO = u('foo') XXX = u('xxx') SPLAT = u('splat') SPLATV = u('splatv') A = u('a') AVALUE = u('avalue') B = u('b') BVALUE = u('bvalue') class _Catchable(object): # Mixin for classes which need to make assertions about the exception # instance. def assertRaises(self, excClass, callableObj, *args, **kwargs): # Morph stdlib version to return the raised exception try: callableObj(*args, **kwargs) except excClass as exc: return exc if hasattr(excClass,'__name__'): excName = excClass.__name__ else: excName = str(excClass) raise self.failureException("%s not raised" % excName) class ZopeXMLConfigurationErrorTests(unittest.TestCase): def _getTargetClass(self): from zope.configuration.xmlconfig import ZopeXMLConfigurationError return ZopeXMLConfigurationError def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test___str___uses_repr_of_info(self): zxce = self._makeOne('info', Exception, 'value') self.assertEqual(str(zxce), "'info'\n Exception: value") class ZopeSAXParseExceptionTests(unittest.TestCase): def _getTargetClass(self): from zope.configuration.xmlconfig import ZopeSAXParseException return ZopeSAXParseException def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test___str___not_a_sax_error(self): zxce = self._makeOne(Exception('Not a SAX error')) self.assertEqual(str(zxce), "Not a SAX error") def test___str___w_a_sax_error(self): zxce = self._makeOne(Exception('filename.xml:24:32:WAAA')) self.assertEqual(str(zxce), 'File "filename.xml", line 24.32, WAAA') class ParserInfoTests(unittest.TestCase): _tempdir = None def tearDown(self): if self._tempdir is not None: import shutil shutil.rmtree(self._tempdir) def _getTargetClass(self): from zope.configuration.xmlconfig import ParserInfo return ParserInfo def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test___repr___w_eline_ecolumn_match_line_column(self): pi = self._makeOne('filename.xml', 24, 32) pi.end(24, 32) self.assertEqual(repr(pi), 'File "filename.xml", line 24.32') def test___repr___w_eline_ecolumn_dont_match_line_column(self): pi = self._makeOne('filename.xml', 24, 32) pi.end(33, 21) self.assertEqual(repr(pi), 'File "filename.xml", line 24.32-33.21') def test___str___w_eline_ecolumn_match_line_column(self): pi = self._makeOne('filename.xml', 24, 32) pi.end(24, 32) self.assertEqual(str(pi), 'File "filename.xml", line 24.32') def test___str___w_eline_ecolumn_dont_match_line_column_bad_file(self): pi = self._makeOne('/path/to/nonesuch.xml', 24, 32) pi.end(33, 21) self.assertEqual(str(pi), 'File "/path/to/nonesuch.xml", line 24.32-33.21\n' ' Could not read source.') def test___str___w_good_file(self): pi = self._makeOne('tests//sample.zcml', 3, 2) pi.end(3, 57) self.assertEqual( str(pi), 'File "tests//sample.zcml", line 3.2-3.57\n' ' ') class ConfigurationHandlerTests(_Catchable, unittest.TestCase): def _getTargetClass(self): from zope.configuration.xmlconfig import ConfigurationHandler return ConfigurationHandler def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor_defaults(self): context = FauxContext() handler = self._makeOne(context) self.assertTrue(handler.context is context) self.assertFalse(handler.testing) self.assertEqual(handler.ignore_depth, 0) def test_ctor_explicit(self): context = FauxContext() handler = self._makeOne(context, True) self.assertTrue(handler.context is context) self.assertTrue(handler.testing) self.assertEqual(handler.ignore_depth, 0) self.assertTrue(handler.locator is None) def test_setDocumentLocator(self): context = FauxContext() locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context, True) handler.setDocumentLocator(locator) self.assertTrue(handler.locator is locator) def test_startElementNS_w_zcml_condition_failing(self): from zope.configuration.xmlconfig import ZCML_CONDITION context = FauxContext() handler = self._makeOne(context, True) # No locator set: we won't need it, due to a failed condition. handler.startElementNS((NS, FOO), FOO, {ZCML_CONDITION: 'have nonesuch', (None, A): AVALUE, (None, B): BVALUE, }) self.assertEqual(handler.ignore_depth, 1) def test_startElementNS_w_ignore_depth_already_set(self): context = FauxContext() handler = self._makeOne(context, True) handler.ignore_depth = 1 # No locator set: we won't need it, as an ancestor had a # failed condition. handler.startElementNS((NS, FOO), FOO, {(XXX, SPLAT): SPLATV, (None, A): AVALUE, (None, B): BVALUE, }) self.assertEqual(handler.ignore_depth, 2) def test_startElementNS_context_begin_raises_wo_testing(self): from zope.configuration.xmlconfig import ZopeXMLConfigurationError class ErrorContext(FauxContext): def begin(self, *args): raise AttributeError("xxx") context = ErrorContext() locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context) handler.setDocumentLocator(locator) exc = self.assertRaises(ZopeXMLConfigurationError, handler.startElementNS, (NS, FOO), FOO, {(XXX, SPLAT): SPLATV, (None, A): AVALUE, (None, B): BVALUE, }) self.assertEqual(exc.info.file, 'tests//sample.zcml') self.assertEqual(exc.info.line, 1) self.assertEqual(exc.info.column, 1) def test_startElementNS_context_begin_raises_w_testing(self): class ErrorContext(FauxContext): def begin(self, *args): raise AttributeError("xxx") context = ErrorContext() locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context, True) handler.setDocumentLocator(locator) self.assertRaises(AttributeError, handler.startElementNS, (NS, FOO), FOO, {(XXX, SPLAT): SPLATV, (None, A): AVALUE, (None, B): BVALUE, }) def test_startElementNS_normal(self): # Integration test of startElementNS / endElementNS pair. context = FauxContext() locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context) handler.setDocumentLocator(locator) handler.startElementNS((NS, FOO), FOO, {(XXX, SPLAT): SPLATV, (None, A): AVALUE, (None, B): BVALUE, }) self.assertEqual(context.info.file, 'tests//sample.zcml') self.assertEqual(context.info.line, 1) self.assertEqual(context.info.column, 1) self.assertEqual(context.begin_args, ((NS, FOO), {'a': AVALUE, 'b': BVALUE})) self.assertFalse(context._end_called) def test_endElementNS_w_ignore_depth_already_set(self): context = FauxContext() handler = self._makeOne(context, True) handler.ignore_depth = 1 # No locator set: we won't need it, as we had a # failed condition. handler.endElementNS((NS, FOO), FOO) self.assertEqual(handler.ignore_depth, 0) def test_endElementNS_context_end_raises_wo_testing(self): from zope.configuration.xmlconfig import ZopeXMLConfigurationError class ErrorContext(FauxContext): def end(self): raise AttributeError("xxx") class Info(object): _line = _col = None def end(self, line, col): self._line, self._col = line, col context = ErrorContext() info = Info() context.setInfo(info) locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context) handler.setDocumentLocator(locator) locator.line, locator.column = 7, 16 exc = self.assertRaises(ZopeXMLConfigurationError, handler.endElementNS, (NS, FOO), FOO) self.assertTrue(exc.info is context.info) self.assertEqual(exc.info._line, 7) self.assertEqual(exc.info._col, 16) def test_endElementNS_context_end_raises_w_testing(self): class ErrorContext(FauxContext): def end(self): raise AttributeError("xxx") class Info(object): _line = _col = None def end(self, line, col): self._line, self._col = line, col context = ErrorContext() info = Info() context.setInfo(info) locator = FauxLocator('tests//sample.zcml', 1, 1) handler = self._makeOne(context, True) handler.setDocumentLocator(locator) locator.line, locator.column = 7, 16 self.assertRaises(AttributeError, handler.endElementNS, (NS, FOO), FOO) self.assertEqual(context.info._line, 7) self.assertEqual(context.info._col, 16) def test_evaluateCondition_w_have_no_args(self): context = FauxContext() handler = self._makeOne(context) exc = self.assertRaises(ValueError, handler.evaluateCondition, 'have') self.assertEqual(str(exc.args[0]), "Feature name missing: 'have'") def test_evaluateCondition_w_not_have_too_many_args(self): context = FauxContext() handler = self._makeOne(context) exc = self.assertRaises(ValueError, handler.evaluateCondition, 'not-have a b') self.assertEqual(str(exc.args[0]), "Only one feature allowed: 'not-have a b'") def test_evaluateCondition_w_have_miss(self): context = FauxContext() handler = self._makeOne(context) self.assertFalse(handler.evaluateCondition('have feature')) def test_evaluateCondition_w_have_hit(self): context = FauxContext() context._features = ('feature',) handler = self._makeOne(context) self.assertTrue(handler.evaluateCondition('have feature')) def test_evaluateCondition_w_not_have_miss(self): context = FauxContext() context._features = ('feature',) handler = self._makeOne(context) self.assertFalse(handler.evaluateCondition('not-have feature')) def test_evaluateCondition_w_not_have_hit(self): context = FauxContext() handler = self._makeOne(context) self.assertTrue(handler.evaluateCondition('not-have feature')) def test_evaluateCondition_w_installed_no_args(self): context = FauxContext() handler = self._makeOne(context) exc = self.assertRaises(ValueError, handler.evaluateCondition, 'installed') self.assertEqual(str(exc.args[0]), "Package name missing: 'installed'") def test_evaluateCondition_w_not_installed_too_many_args(self): context = FauxContext() handler = self._makeOne(context) exc = self.assertRaises(ValueError, handler.evaluateCondition, 'not-installed a b') self.assertEqual(str(exc.args[0]), "Only one package allowed: 'not-installed a b'") def test_evaluateCondition_w_installed_miss(self): context = FauxContext() handler = self._makeOne(context) self.assertFalse(handler.evaluateCondition('installed nonsuch.package')) def test_evaluateCondition_w_installed_hit(self): context = FauxContext() handler = self._makeOne(context) self.assertTrue(handler.evaluateCondition('installed os')) def test_evaluateCondition_w_not_installed_miss(self): context = FauxContext() handler = self._makeOne(context) self.assertFalse(handler.evaluateCondition('not-installed os')) def test_evaluateCondition_w_not_installed_hit(self): context = FauxContext() handler = self._makeOne(context) self.assertTrue( handler.evaluateCondition('not-installed nonsuch.package')) def test_evaluateCondition_w_unknown_verb(self): context = FauxContext() handler = self._makeOne(context) exc = self.assertRaises(ValueError, handler.evaluateCondition, 'nonesuch') self.assertEqual(str(exc.args[0]), "Invalid ZCML condition: 'nonesuch'") def test_endElementNS_normal(self): class Info(object): _line = _col = None def end(self, line, col): self._line, self._col = line, col context = FauxContext() info = Info() context.setInfo(info) locator = FauxLocator('tests//sample.zcml', 7, 16) handler = self._makeOne(context, True) handler.setDocumentLocator(locator) handler.endElementNS((NS, FOO), FOO) self.assertEqual(context.info._line, 7) self.assertEqual(context.info._col, 16) self.assertTrue(context._end_called) class Test_processxmlfile(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import processxmlfile return processxmlfile(*args, **kw) def test_w_empty_xml(self): from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration.xmlconfig import ZopeSAXParseException from zope.configuration._compat import StringIO context = ConfigurationMachine() registerCommonDirectives(context) exc = self.assertRaises(ZopeSAXParseException, self._callFUT, StringIO(), context) self.assertEqual(str(exc._v), ':1:0: no element found') def test_w_valid_xml_fp(self): # Integration test, really from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo file = open(path("samplepackage", "configure.zcml")) context = ConfigurationMachine() registerCommonDirectives(context) self._callFUT(file, context) self.assertEqual(foo.data, []) context.execute_actions() data = foo.data.pop() self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertEqual(clean_info_path(repr(data.info)), 'File "tests/samplepackage/configure.zcml", line 12.2-12.29') self.assertEqual(clean_info_path(str(data.info)), 'File "tests/samplepackage/configure.zcml", line 12.2-12.29\n' + ' ') self.assertEqual(data.package, None) self.assertEqual(data.basepath, None) class Test_openInOrPlain(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import openInOrPlain return openInOrPlain(*args, **kw) def _makeFilename(self, fn): import os from zope.configuration.tests.samplepackage import __file__ return os.path.join(os.path.dirname(__file__), fn) def test_file_present(self): import os with self._callFUT(self._makeFilename('configure.zcml')) as fp: self.assertEqual(os.path.basename(fp.name), 'configure.zcml') def test_file_missing_but_dot_in_present(self): import os with self._callFUT(self._makeFilename('foo.zcml')) as fp: self.assertEqual(os.path.basename(fp.name), 'foo.zcml.in') def test_file_missing_and_dot_in_not_present(self): import errno exc = self.assertRaises( IOError, self._callFUT, self._makeFilename('nonesuch.zcml')) self.assertEqual(exc.errno, errno.ENOENT) class Test_include(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import include return include(*args, **kw) def test_both_file_and_files_passed(self): context = FauxContext() exc = self.assertRaises(ValueError, self._callFUT, context, 'tests//sample.zcml', files=['tests/*.zcml']) self.assertEqual(str(exc), "Must specify only one of file or files") def test_neither_file_nor_files_passed_already_seen(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration.tests import samplepackage context = ConfigurationMachine() registerCommonDirectives(context) context.package = samplepackage fqn = _packageFile(samplepackage, 'configure.zcml') context._seen_files.add(fqn) logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): self._callFUT(context) #skips self.assertEqual(len(logger.debugs), 0) self.assertEqual(len(context.actions), 0) def test_neither_file_nor_files_passed(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo context = ConfigurationMachine() registerCommonDirectives(context) before_stack = context.stack[:] context.package = samplepackage fqn = _packageFile(samplepackage, 'configure.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): self._callFUT(context) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['callable'], foo.data.append) self.assertEqual(action['includepath'], (fqn,)) self.assertEqual(context.stack, before_stack) self.assertEqual(len(context._seen_files), 1) self.assertTrue(fqn in context._seen_files) def test_w_file_passed(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration import tests from zope.configuration.tests import simple context = ConfigurationMachine() registerCommonDirectives(context) before_stack = context.stack[:] context.package = tests fqn = _packageFile(tests, 'simple.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): self._callFUT(context, 'simple.zcml') self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(context.actions), 3) action = context.actions[0] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqn,)) self.assertEqual(action['args'][0].path, _packageFile(tests, 'simple.py')) action = context.actions[1] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqn,)) self.assertEqual(action['args'][0].path, _packageFile(tests, 'simple.zcml')) action = context.actions[2] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqn,)) self.assertEqual(action['args'][0].path, _packageFile(tests, '__init__.py')) self.assertEqual(context.stack, before_stack) self.assertEqual(len(context._seen_files), 1) self.assertTrue(fqn in context._seen_files) def test_w_files_passed_and_package(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo context = ConfigurationMachine() registerCommonDirectives(context) before_stack = context.stack[:] fqn1 = _packageFile(samplepackage, 'baz1.zcml') fqn2 = _packageFile(samplepackage, 'baz2.zcml') fqn3 = _packageFile(samplepackage, 'baz3.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): self._callFUT(context, package=samplepackage, files='baz*.zcml') self.assertEqual(len(logger.debugs), 3) self.assertEqual(logger.debugs[0], ('include %s' % fqn1, (), {})) self.assertEqual(logger.debugs[1], ('include %s' % fqn2, (), {})) self.assertEqual(logger.debugs[2], ('include %s' % fqn3, (), {})) self.assertEqual(len(context.actions), 2) action = context.actions[0] self.assertEqual(action['callable'], foo.data.append) self.assertEqual(action['includepath'], (fqn2,)) self.assertTrue(isinstance(action['args'][0], foo.stuff)) self.assertEqual(action['args'][0].args, (('x', b('foo')), ('y', 2))) action = context.actions[1] self.assertEqual(action['callable'], foo.data.append) self.assertEqual(action['includepath'], (fqn3,)) self.assertTrue(isinstance(action['args'][0], foo.stuff)) self.assertEqual(action['args'][0].args, (('x', b('foo')), ('y', 3))) self.assertEqual(context.stack, before_stack) self.assertEqual(len(context._seen_files), 3) self.assertTrue(fqn1 in context._seen_files) self.assertTrue(fqn2 in context._seen_files) self.assertTrue(fqn3 in context._seen_files) class Test_exclude(_Catchable, unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import exclude return exclude(*args, **kw) def test_both_file_and_files_passed(self): context = FauxContext() exc = self.assertRaises(ValueError, self._callFUT, context, 'tests//sample.zcml', files=['tests/*.zcml']) self.assertEqual(str(exc), "Must specify only one of file or files") def test_neither_file_nor_files_passed(self): from zope.configuration.config import ConfigurationMachine from zope.configuration.tests import samplepackage context = ConfigurationMachine() context.package = samplepackage fqn = _packageFile(samplepackage, 'configure.zcml') self._callFUT(context) self.assertEqual(len(context.actions), 0) self.assertEqual(len(context._seen_files), 1) self.assertTrue(fqn in context._seen_files) def test_w_file_passed(self): from zope.configuration.config import ConfigurationMachine from zope.configuration import tests context = ConfigurationMachine() context.package = tests fqn = _packageFile(tests, 'simple.zcml') self._callFUT(context, 'simple.zcml') self.assertEqual(len(context.actions), 0) self.assertEqual(len(context._seen_files), 1) self.assertTrue(fqn in context._seen_files) def test_w_files_passed_and_package(self): from zope.configuration.config import ConfigurationMachine from zope.configuration.tests import samplepackage context = ConfigurationMachine() fqn1 = _packageFile(samplepackage, 'baz1.zcml') fqn2 = _packageFile(samplepackage, 'baz2.zcml') fqn3 = _packageFile(samplepackage, 'baz3.zcml') self._callFUT(context, package=samplepackage, files='baz*.zcml') self.assertEqual(len(context.actions), 0) self.assertEqual(len(context._seen_files), 3) self.assertTrue(fqn1 in context._seen_files) self.assertTrue(fqn2 in context._seen_files) self.assertTrue(fqn3 in context._seen_files) def test_w_subpackage(self): from zope.configuration.config import ConfigurationMachine from zope.configuration.tests import excludedemo from zope.configuration.tests.excludedemo import sub context = ConfigurationMachine() fqne_spam = _packageFile(excludedemo, 'spam.zcml') fqne_config = _packageFile(excludedemo, 'configure.zcml') fqns_config = _packageFile(sub, 'configure.zcml') self._callFUT(context, package=sub) self.assertEqual(len(context.actions), 0) self.assertEqual(len(context._seen_files), 1) self.assertFalse(fqne_spam in context._seen_files) self.assertFalse(fqne_config in context._seen_files) self.assertTrue(fqns_config in context._seen_files) class Test_includeOverrides(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import includeOverrides return includeOverrides(*args, **kw) def test_actions_have_parents_includepath(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration import tests from zope.configuration.tests import simple context = ConfigurationMachine() fqp = _packageFile(tests, 'configure.zcml') registerCommonDirectives(context) before_stack = context.stack[:] context.package = tests # dummy action, path from "previous" include context.includepath = (fqp,) def _callable(): pass context.actions.append({'discriminator': None, 'callable': _callable, }) fqn = _packageFile(tests, 'simple.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): self._callFUT(context, 'simple.zcml') self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(context.actions), 4) action = context.actions[0] self.assertEqual(action['discriminator'], None) self.assertEqual(action['callable'], _callable) action = context.actions[1] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqp,)) self.assertEqual(action['args'][0].path, _packageFile(tests, 'simple.py')) action = context.actions[2] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqp,)) self.assertEqual(action['args'][0].path, _packageFile(tests, 'simple.zcml')) action = context.actions[3] self.assertEqual(action['callable'], simple.file_registry.append) self.assertEqual(action['includepath'], (fqp,)) self.assertEqual(action['args'][0].path, _packageFile(tests, '__init__.py')) self.assertEqual(context.stack, before_stack) self.assertEqual(len(context._seen_files), 1) self.assertTrue(fqn in context._seen_files) class Test_file(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import file return file(*args, **kw) def test_wo_execute_wo_context_wo_package(self): from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo file_name = path("samplepackage", "configure.zcml") logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): context = self._callFUT(file_name, execute=False) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % file_name, (), {})) self.assertEqual(len(foo.data), 0) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_wo_execute_wo_context_w_package(self): from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo file_name = path("samplepackage", "configure.zcml") logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): context = self._callFUT('configure.zcml', package=samplepackage, execute=False) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % file_name, (), {})) self.assertEqual(len(foo.data), 0) self.assertTrue(context.package is samplepackage) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_wo_execute_w_context(self): from zope.configuration import xmlconfig from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo context = ConfigurationMachine() context.package = samplepackage registerCommonDirectives(context) file_name = path("samplepackage", "configure.zcml") logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): ret = self._callFUT('configure.zcml', context=context, execute=False) self.assertTrue(ret is context) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % file_name, (), {})) self.assertEqual(len(foo.data), 0) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_w_execute(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo file_name = path("samplepackage", "configure.zcml") logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): context = self._callFUT(file_name) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % file_name, (), {})) data = foo.data.pop() self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file.endswith( os.path.normpath('tests/samplepackage/configure.zcml'))) self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) self.assertEqual(data.package, None) self.assertTrue(data.basepath.endswith( os.path.normpath('tests/samplepackage'))) class Test_string(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import string return string(*args, **kw) def test_wo_execute_wo_context(self): from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo file_name = path("samplepackage", "configure.zcml") with open(file_name) as f: xml = f.read() context = self._callFUT(xml, execute=False) self.assertEqual(len(foo.data), 0) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_wo_execute_w_context(self): from zope.configuration.config import ConfigurationMachine from zope.configuration.xmlconfig import registerCommonDirectives from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo context = ConfigurationMachine() registerCommonDirectives(context) file_name = path("samplepackage", "configure.zcml") with open(file_name) as f: xml = f.read() ret = self._callFUT(xml, context=context, execute=False) self.assertTrue(ret is context) self.assertEqual(len(foo.data), 0) self.assertEqual(len(context.actions), 1) action = context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_w_execute(self): from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo file_name = path("samplepackage", "configure.zcml") with open(file_name) as f: xml = f.read() context = self._callFUT(xml) data = foo.data.pop() self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file, '') self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) self.assertEqual(data.package, None) self.assertEqual(data.basepath, None) class XMLConfigTests(unittest.TestCase): def setUp(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def tearDown(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def _getTargetClass(self): from zope.configuration.xmlconfig import XMLConfig return XMLConfig def _makeOne(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_ctor_w_global_context_missing(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo here = os.path.dirname(__file__) path = os.path.join(here, "samplepackage", "configure.zcml") logger = LoggerStub() xmlconfig._context = None with _Monkey(xmlconfig, logger=logger): xc = self._makeOne(path) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % path, (), {})) self.assertEqual(len(foo.data), 0) # no execut_actions self.assertEqual(len(xc.context.actions), 1) action = xc.context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_ctor(self): from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo fqn = _packageFile(samplepackage, 'configure.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): xc = self._makeOne(fqn) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(foo.data), 0) # no execut_actions self.assertEqual(len(xc.context.actions), 1) action = xc.context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test_ctor_w_module(self): from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests.samplepackage import foo from zope.configuration.tests import samplepackage fqn = _packageFile(samplepackage, 'configure.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): xc = self._makeOne("configure.zcml", samplepackage) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(foo.data), 0) # no execut_actions self.assertEqual(len(xc.context.actions), 1) action = xc.context.actions[0] self.assertEqual(action['discriminator'], (('x', b('blah')), ('y', 0))) self.assertEqual(action['callable'], foo.data.append) def test___call__(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo fqn = _packageFile(samplepackage, 'configure.zcml') logger = LoggerStub() with _Monkey(xmlconfig, logger=logger): xc = self._makeOne(fqn) self.assertEqual(len(logger.debugs), 1) self.assertEqual(logger.debugs[0], ('include %s' % fqn, (), {})) self.assertEqual(len(foo.data), 0) xc() # call to process the actions self.assertEqual(len(foo.data), 1) data = foo.data.pop(0) self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file.endswith( os.path.normpath('tests/samplepackage/configure.zcml'))) self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) class Test_xmlconfig(unittest.TestCase): def setUp(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def tearDown(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import xmlconfig return xmlconfig(*args, **kw) def test_wo_testing_passed(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo def _assertTestingFalse(func): def _wrapper(*args, **kw): assert(not kw['testing']) return func(*args, **kw) return _wrapper fqn = _packageFile(samplepackage, 'configure.zcml') context = xmlconfig._getContext() context.execute_actions = _assertTestingFalse(context.execute_actions) with _Monkey(xmlconfig, processxmlfile=_assertTestingFalse( xmlconfig.processxmlfile)): self._callFUT(open(fqn), False) self.assertEqual(len(foo.data), 1) data = foo.data.pop(0) self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file.endswith( os.path.normpath('tests/samplepackage/configure.zcml'))) self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) def test_w_testing_passed(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo def _assertTestingTrue(func): def _wrapper(*args, **kw): assert(kw['testing']) return func(*args, **kw) return _wrapper fqn = _packageFile(samplepackage, 'configure.zcml') context = xmlconfig._getContext() context.execute_actions = _assertTestingTrue(context.execute_actions) with _Monkey(xmlconfig, processxmlfile=_assertTestingTrue( xmlconfig.processxmlfile)): self._callFUT(open(fqn), True) self.assertEqual(len(foo.data), 1) data = foo.data.pop(0) self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file.endswith( os.path.normpath('tests/samplepackage/configure.zcml'))) self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) class Test_testxmlconfig(unittest.TestCase): def setUp(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def tearDown(self): from zope.configuration.xmlconfig import _clearContext from zope.configuration.tests.samplepackage.foo import data _clearContext() del data[:] def _callFUT(self, *args, **kw): from zope.configuration.xmlconfig import testxmlconfig return testxmlconfig(*args, **kw) def test_w_testing_passed(self): import os from zope.configuration import xmlconfig from zope.configuration._compat import b from zope.configuration.tests import samplepackage from zope.configuration.tests.samplepackage import foo def _assertTestingTrue(func): def _wrapper(*args, **kw): assert(kw['testing']) return func(*args, **kw) return _wrapper fqn = _packageFile(samplepackage, 'configure.zcml') context = xmlconfig._getContext() context.execute_actions = _assertTestingTrue(context.execute_actions) with _Monkey(xmlconfig, processxmlfile=_assertTestingTrue( xmlconfig.processxmlfile)): self._callFUT(open(fqn)) self.assertEqual(len(foo.data), 1) data = foo.data.pop(0) self.assertEqual(data.args, (('x', b('blah')), ('y', 0))) self.assertTrue(data.info.file.endswith( os.path.normpath('tests/samplepackage/configure.zcml'))) self.assertEqual(data.info.line, 12) self.assertEqual(data.info.column, 2) self.assertEqual(data.info.eline, 12) self.assertEqual(data.info.ecolumn, 29) class FauxLocator(object): def __init__(self, file, line, column): self.file, self.line, self.column = file, line, column def getSystemId(self): return self.file def getLineNumber(self): return self.line def getColumnNumber(self): return self.column class FauxContext(object): includepath = () _features = () _end_called = False def setInfo(self, info): self.info = info def getInfo(self): return self.info def begin(self, name, data, info): self.begin_args = name, data self.info = info def end(self): self._end_called = 1 def hasFeature(self, feature): return feature in self._features def path(*p): import os return os.path.join(os.path.dirname(__file__), *p) def clean_info_path(s): import os part1 = s[:6] part2 = s[6:s.find('"', 6)] part2 = part2[part2.rfind("tests"):] part2 = part2.replace(os.sep, '/') part3 = s[s.find('"', 6):].rstrip() return part1+part2+part3 def clean_path(s): import os s = s[s.rfind("tests"):] s = s.replace(os.sep, '/') return s def clean_actions(actions): return [ {'discriminator': action['discriminator'], 'info': clean_info_path(repr(action['info'])), 'includepath': [clean_path(p) for p in action['includepath']], } for action in actions ] def clean_text_w_paths(error): r = [] for line in unicode(error).split("\n"): line = line.rstrip() if not line: continue l = line.find('File "') if l >= 0: line = line[:l] + clean_info_path(line[l:]) r.append(line) return '\n'.join(r) def _packageFile(package, filename): import os return os.path.join(os.path.dirname(package.__file__), filename) class _Monkey(object): def __init__(self, module, **replacements): self.module = module self.orig = {} self.replacements = replacements def __enter__(self): for k, v in self.replacements.items(): orig = getattr(self.module, k, self) if orig is not self: self.orig[k] = orig setattr(self.module, k, v) def __exit__(self, *exc_info): for k, v in self.replacements.items(): if k in self.orig: setattr(self.module, k, self.orig[k]) else: #pragma NO COVERSGE delattr(self.module, k) class LoggerStub(object): def __init__(self): self.errors = [] self.warnings = [] self.infos = [] self.debugs = [] def error(self, msg, *args, **kwargs): self.errors.append((msg, args, kwargs)) def warning(self, msg, *args, **kwargs): self.warnings.append((msg, args, kwargs)) def info(self, msg, *args, **kwargs): self.infos.append((msg, args, kwargs)) def debug(self, msg, *args, **kwargs): self.debugs.append((msg, args, kwargs)) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ZopeXMLConfigurationErrorTests), unittest.makeSuite(ZopeSAXParseExceptionTests), unittest.makeSuite(ParserInfoTests), unittest.makeSuite(ConfigurationHandlerTests), unittest.makeSuite(Test_processxmlfile), unittest.makeSuite(Test_openInOrPlain), unittest.makeSuite(Test_include), unittest.makeSuite(Test_exclude), unittest.makeSuite(Test_includeOverrides), unittest.makeSuite(Test_file), unittest.makeSuite(Test_string), unittest.makeSuite(XMLConfigTests), unittest.makeSuite(Test_xmlconfig), unittest.makeSuite(Test_testxmlconfig), )) zope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/0000775000175000017500000000000012312363233025320 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/__init__.py0000664000175000017500000000000212073042162027420 0ustar tseavertseaver# zope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/spam.zcml0000664000175000017500000000001612073042162027143 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/sub/0000775000175000017500000000000012312363233026111 5ustar tseavertseaverzope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/sub/__init__.py0000664000175000017500000000000212073042162030211 0ustar tseavertseaver# zope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/sub/configure.zcml0000664000175000017500000000001612073042162030755 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/excludedemo/configure.zcml0000664000175000017500000000012312073042162030163 0ustar tseavertseaver zope.configuration-4.0.3/src/zope/configuration/tests/conditions.zcml0000664000175000017500000000376412073042162026073 0ustar tseavertseaver This registers a directive which creates registrations we can test. ZCML directives inside here should be included. This registration should be included. ZCML directives inside here should be ignored. This registration should be ignored. zope.configuration-4.0.3/src/zope/configuration/tests/bad.py0000664000175000017500000000011512073042162024116 0ustar tseavertseaver# I'm bad. I want to be bad. Don't try to change me. import bad_to_the_bone zope.configuration-4.0.3/src/zope/configuration/tests/test___init__.py0000664000175000017500000000231412073042162026171 0ustar tseavertseaver############################################################################## # # Copyright (c) 20!2 Zope Foundation 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. # ############################################################################## """Test zope.configuration.__init__ """ import unittest class Test_namespace(unittest.TestCase): def _callFUT(self, *args, **kw): from zope.configuration import namespace return namespace(*args, **kw) def test_empty(self): self.assertEqual(self._callFUT(''), 'http://namespaces.zope.org/') def test_non_empty(self): self.assertEqual(self._callFUT('test'), 'http://namespaces.zope.org/test') def test_suite(): return unittest.TestSuite(( unittest.makeSuite(Test_namespace), )) zope.configuration-4.0.3/src/zope/configuration/tests/schema.zcml0000664000175000017500000000305212073042162025150 0ustar tseavertseaver Define a schema Use field directives (e.g. text and int directives) to define the schema fields. Define a text field Define an integer field Sample interface I1 A Blah blah B Not feeling very creative Sample interface I2 X zope.configuration-4.0.3/src/zope/configuration/tests/nested.py0000664000175000017500000001030512073042162024654 0ustar tseavertseaver############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """ Utilities for the 'nested directive' section in the narrative docs. """ from zope.interface import Attribute from zope.interface import Interface from zope.interface import implementer from zope.schema import BytesLine from zope.schema import Id from zope.schema import Int from zope.schema import Text from zope.schema import TextLine from zope.configuration.config import GroupingContextDecorator from zope.configuration.config import IConfigurationContext from zope.configuration.fields import Bool from zope.configuration._compat import u schema_registry = {} class ISchemaInfo(Interface): """Parameter schema for the schema directive """ name = TextLine( title=u("The schema name"), description=u("This is a descriptive name for the schema."), ) id = Id(title=u("The unique id for the schema")) class ISchema(Interface): """Interface that distinguishes the schema directive """ fields = Attribute("Dictionary of field definitions") @implementer(IConfigurationContext, ISchema) class Schema(GroupingContextDecorator): """Handle schema directives """ def __init__(self, context, name, id): self.context, self.name, self.id = context, name, id self.fields = {} def after(self): schema = Interface.__class__( self.name, (Interface, ), self.fields ) schema.__doc__ = self.info.text.strip() self.action( discriminator=('schema', self.id), callable=schema_registry.__setitem__, args=(self.id, schema), ) class IFieldInfo(Interface): name = BytesLine( title=u("The field name"), ) title = TextLine( title=u("Title"), description=u("A short summary or label"), default=u(""), required=False, ) required = Bool( title=u("Required"), description=u("Determines whether a value is required."), default=True) readonly = Bool( title=u("Read Only"), description=u("Can the value be modified?"), required=False, default=False) class ITextInfo(IFieldInfo): min_length = Int( title=u("Minimum length"), description=u("Value after whitespace processing cannot have less than " "min_length characters. If min_length is None, there is " "no minimum."), required=False, min=0, # needs to be a positive number default=0) max_length = Int( title=u("Maximum length"), description=u("Value after whitespace processing cannot have greater " "or equal than max_length characters. If max_length is " "None, there is no maximum."), required=False, min=0, # needs to be a positive number default=None) def field(context, constructor, name, **kw): # Compute the field field = constructor(description=context.info.text.strip(), **kw) # Save it in the schema's field dictionary schema = context.context if name in schema.fields: raise ValueError("Duplicate field", name) schema.fields[name] = field def textField(context, **kw): field(context, Text, **kw) class IIntInfo(IFieldInfo): min = Int( title=u("Start of the range"), required=False, default=None ) max = Int( title=u("End of the range (excluding the value itself)"), required=False, default=None ) def intField(context, **kw): field(context, Int, **kw) zope.configuration-4.0.3/src/zope/configuration/zopeconfigure.py0000664000175000017500000001402212073042162025107 0ustar tseavertseaver############################################################################## # # Copyright (c) 2001, 2002, 2003 Zope Foundation 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. # ############################################################################## """Zope configure directive This file contains the implementation of the Zope configure directive. It is broken out in a separate file to provide an example of a grouping directive. The zope configuration directive is a pure grouping directive. It doesn't compute any actions on it's own. Instead, it allows a package to be specified, affecting the interpretation of relative dotted names and file paths. It also allows an i18n domain to be specified. The information collected is used by subdirectives. To define a grouping directive, we need to do three things: - Define a schema for the parameters passed to the directive - Define a handler class. - Register the class The parameter schema is given by IZopeConfigure. It specifies a package parameter and an i18n_domain parameter. The package parameter is specified as a ``GlobalObject``. This means it must be given as a dotted name that can be resolved through import. The i18n domain is just a plain (not unicode) string. The handler class has a constructor that takes a context to be adapted and zero or more arguments (depending on the paramter schema). The handler class must implement ``zope.configuration.interfaces.IGroupingContext``, which defines hooks ``before`` and ``after``, that are called with no arguments before and after nested directives are processed. If a grouping directive handler creates any actions, or does any computation, this is normally done in either the ``before`` or ``after`` hooks. Grouping handlers are normally decorators. The base class, ``zope.configuration.config.GroupingContextDecorator``, is normally used to define grouping directive handlers. It provides: - An implementation of IConfigurationContext, which grouping directive handlers should normally implement, - A default implementation of ``IGroupingContext`` that provides empty hooks. - Decorator support that uses a ``__getattr__`` method to delegate attribute accesses to adapted contexts, and - A constructor that sets the ``context`` attribute to the adapted context and assigns keyword arguments to attributes. The ``ZopeConfigure`` provides handling for the ``configure`` directive. It subclasses GroupingContextDecorator, and overrides the constructor to set the ``basepath`` attribute if a ``package`` argument is provided. Note that it delegates the job of assigning paramters to attribute to the ``GroupingContextDecorator`` constructor. The last step is to register the directive using the meta configuration directive. If we wanted to register the Zope ``configure`` directive for the ``zope`` namespace, we'd use a meta-configuration directive like:: Zope configure The ``configure`` node is normally used as the root node for a configuration file. It can also be used to specify a package or internationalization domain for a group of directives within a file by grouping those directives. We use the groupingDirective meta-directive to register a grouping directive. The parameters are self explanatory. The textual contents of the directive provide documentation text, excluding parameter documentation, which is provided by the schema. (The Zope ``configuration`` directive is actually registered using a lower-level Python API because it is registered for all namespaces, which isn't supported using the meta-configuration directives.) """ __docformat__ = 'restructuredtext' import os from zope.interface import Interface from zope.schema import BytesLine from zope.configuration.config import GroupingContextDecorator from zope.configuration.fields import GlobalObject from zope.configuration._compat import u class IZopeConfigure(Interface): """The ``zope:configure`` Directive The zope configuration directive is a pure grouping directive. It doesn't compute any actions on it's own. Instead, it allows a package to be specified, affecting the interpretation of relative dotted names and file paths. It also allows an i18n domain to be specified. The information collected is used by subdirectives. It may seem that this directive can only be used once per file, but it can be applied whereever it is convenient. """ package = GlobalObject( title=u("Package"), description=u("The package to be used for evaluating relative imports " "and file names."), required=False) i18n_domain = BytesLine( title=u("Internationalization domain"), description=u("This is a name for the software project. It must be a " "legal file-system name as it will be used to contruct " "names for directories containing translation data. " "\n" "The domain defines a namespace for the message ids " "used by a project."), required=False) class ZopeConfigure(GroupingContextDecorator): __doc__ = __doc__ def __init__(self, context, **kw): super(ZopeConfigure, self).__init__(context, **kw) if 'package' in kw: # if we have a package, we want to also define basepath # so we don't acquire one self.basepath = os.path.dirname(self.package.__file__) zope.configuration-4.0.3/src/zope/configuration/exceptions.py0000664000175000017500000000137412073042162024417 0ustar tseavertseaver############################################################################## # # Copyright (c) 2002 Zope Foundation 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. # ############################################################################## """Standard configuration errors """ class ConfigurationError(Exception): """There was an error in a configuration """ zope.configuration-4.0.3/COPYRIGHT.txt0000664000175000017500000000004012073042162017347 0ustar tseavertseaverZope Foundation and Contributorszope.configuration-4.0.3/CHANGES.rst0000664000175000017500000001014412312363166017054 0ustar tseavertseaverzope.configuration Changelog ============================ 4.0.3 (2014-03-19) ------------------ - Added explicit support for Python 3.4. 4.0.2 (2012-12-31) ------------------ - Fleshed out PyPI Trove classifiers. - Removed spurious declaration of 'test' dependency on ``zope.testing``. 4.0.1 (2012-11-21) ------------------ - Added support for Python 3.3. - Removed the deprecated 'zope.configuration.stxdocs' script. and made the 'zope.configuration.tests.conditions' helper module (used in running Sphinx doctest snippets) Py3k compatible. https://bugs.launchpad.net/zope.configuration/+bug/1025390 4.0.0 (2012-05-16) ------------------ - 100% unit test coverage. - Automated build of Sphinx HTML docs and running doctest snippets via tox. - Dropped hard testing dependency on ``zope.testing``. - Added explicit support for PyPy. - Added explicit support for Python 3.2. - Dropped explicit support for Python 2.4 / 2.5. - Added support for continuous integration using ``tox`` and ``jenkins``. - Added ``Sphinx`` documentation. - Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). - Added ``setup.py dev`` alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). 3.8.1 (2012-05-05) ------------------ - Fixed Python 2.4 backwards incompat (itemgetter used with multiple args); Python 2.4 now works (at least if you use zope.schema == 3.8.1). This is the last release which will support Python 2.4 or 2.5. 3.8.0 (2011-12-06) ------------------ - Action structures changed from tuples to dictionaries to allow for action structure extensibility (merged chrism-dictactions branch). 3.7.4 (2011-04-03) ------------------ - Test fixes for Windows. 3.7.3 (2011-03-11) ------------------ - Correctly locate packages with a __path__ attribute but no __file__ attribute (such as namespace packages installed with setup.py install --single-version-externally-managed). - Allow "info" and "includepath" to be passed optionally to context.action. 3.7.2 (2010-04-30) ------------------ - Prefer the standard libraries doctest module over zope.testing.doctest. 3.7.1 (2010-01-05) ------------------ - Jython support: use ``__builtin__`` module import rather than assuming ``__builtins__`` is available. - Jython support: deal with the fact that the Jython SAX parser returns attribute sets that have an empty string indicating no namespace instead of ``None``. - Allow ``setup.py test`` to run at least a subset of the tests that would be run when using the zope testrunner: ``setup.py test`` runs 53 tests, while ``bin/test`` runs 156. 3.7.0 (2009-12-22) ------------------ - Adjust testing output to newer zope.schema. - Prefer zope.testing.doctest over doctestunit. 3.6.0 (2009-04-01) ------------------ - Removed dependency of `zope.deprecation` package. - Don't suppress deprecation warnings any more in 'zope.configuration' package level. This makes it more likely other packages will generate deprecation warnings now, which will allow us to remove more outdated ones. - Don't fail when zope.testing is not installed. - Added missing ``processFile`` method to ``IConfigurationContext``. It is already implemented in the mix-in class, ``zope.configuration.config.ConfigurationContext``, and used by implementations of ``include`` and ``exclude`` directives. 3.5.0 (2009-02-26) ------------------ - Added the ``exclude`` directive to standard directives. It was previously available via ``zc.configuration`` package and now it's merged into ``zope.configuration``. - Changed package's mailing list address to zope-dev at zope.org, change "cheeseshop" to "pypi" in the package's url. 3.4.1 (2008-12-11) ------------------ - Use built-in 'set' type, rather than importin the 'sets' module, which is deprecated in Python 2.6. - Added support to bootstrap on Jython. 3.4.0 (2007-10-02) ------------------ - Initial release as a standalone package. Before 3.4.0 ------------ This package was part of the Zope 3 distribution and did not have its own CHANGES.txt. For earlier changes please refer to either our subversion log or the CHANGES.txt of earlier Zope 3 releases. zope.configuration-4.0.3/LICENSE.txt0000664000175000017500000000402612073042162017071 0ustar tseavertseaverZope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zope.configuration-4.0.3/README.rst0000664000175000017500000000076412073042162016742 0ustar tseavertseaverzope.configuration README ========================= The zope configuration system provides an extensible system for supporting various kinds of configurations. It is based on the idea of configuration directives. Users of the configuration system provide configuration directives in some language that express configuration choices. The intent is that the language be pluggable. An XML language is provided by default. Please see http://docs.zope.org/zope.configuration/ for the documentation. zope.configuration-4.0.3/docs/0000775000175000017500000000000012312363233016175 5ustar tseavertseaverzope.configuration-4.0.3/docs/api.rst0000664000175000017500000000036212073042162017500 0ustar tseavertseaver:mod:`zope.configuration` API Reference ======================================= .. toctree:: :maxdepth: 2 api/config api/docutils api/exceptions api/fields api/interfaces api/name api/xmlconfig api/zopeconfigure zope.configuration-4.0.3/docs/make.bat0000664000175000017500000001177612073042162017615 0ustar tseavertseaver@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\zopeconfiguration.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\zopeconfiguration.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end zope.configuration-4.0.3/docs/Makefile0000664000175000017500000001275012073042162017641 0ustar tseavertseaver# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/zopeconfiguration.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/zopeconfiguration.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/zopeconfiguration" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/zopeconfiguration" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." zope.configuration-4.0.3/docs/api/0000775000175000017500000000000012312363233016746 5ustar tseavertseaverzope.configuration-4.0.3/docs/api/exceptions.rst0000664000175000017500000000023012073042162021653 0ustar tseavertseaver:mod:`zope.configuration.exceptions` ==================================== .. module:: zope.configuration.exceptions .. autoclass:: ConfigurationError zope.configuration-4.0.3/docs/api/xmlconfig.rst0000664000175000017500000001271012073042162021466 0ustar tseavertseaver:mod:`zope.configuration.xmlconfig` =================================== .. module:: zope.configuration.xmlconfig .. autoclass:: ZopeXMLConfigurationError Example .. doctest:: >>> from zope.configuration.xmlconfig import ZopeXMLConfigurationError >>> v = ZopeXMLConfigurationError("blah", AttributeError, "xxx") >>> print v 'blah' AttributeError: xxx .. autoclass:: ZopeSAXParseException Example .. doctest:: >>> from zope.configuration.xmlconfig import ZopeSAXParseException >>> v = ZopeSAXParseException("foo.xml:12:3:Not well formed") >>> print v File "foo.xml", line 12.3, Not well formed .. autoclass:: ParserInfo :members: :member-order: bysource Example .. doctest:: >>> from zope.configuration.xmlconfig import ParserInfo >>> info = ParserInfo('tests//sample.zcml', 1, 0) >>> info File "tests//sample.zcml", line 1.0 >>> print info File "tests//sample.zcml", line 1.0 >>> info.characters("blah\\n") >>> info.characters("blah") >>> info.text u'blah\\nblah' >>> info.end(7, 0) >>> info File "tests//sample.zcml", line 1.0-7.0 >>> print info File "tests//sample.zcml", line 1.0-7.0 .. autoclass:: ConfigurationHandler .. automethod:: evaluateCondition The ``have`` and ``not-have`` verbs each take one argument: the name of a feature: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> from zope.configuration.xmlconfig import ConfigurationHandler >>> context = ConfigurationContext() >>> context.provideFeature('apidoc') >>> c = ConfigurationHandler(context, testing=True) >>> c.evaluateCondition("have apidoc") True >>> c.evaluateCondition("not-have apidoc") False >>> c.evaluateCondition("have onlinehelp") False >>> c.evaluateCondition("not-have onlinehelp") True Ill-formed expressions raise an error: .. doctest:: >>> c.evaluateCondition("want apidoc") Traceback (most recent call last): ... ValueError: Invalid ZCML condition: 'want apidoc' >>> c.evaluateCondition("have x y") Traceback (most recent call last): ... ValueError: Only one feature allowed: 'have x y' >>> c.evaluateCondition("have") Traceback (most recent call last): ... ValueError: Feature name missing: 'have' The ``installed`` and ``not-installed`` verbs each take one argument: the dotted name of a pacakge. If the pacakge is found, in other words, can be imported, then the condition will return true / false: .. doctest:: >>> context = ConfigurationContext() >>> c = ConfigurationHandler(context, testing=True) >>> c.evaluateCondition('installed zope.interface') True >>> c.evaluateCondition('not-installed zope.interface') False >>> c.evaluateCondition('installed zope.foo') False >>> c.evaluateCondition('not-installed zope.foo') True Ill-formed expressions raise an error: .. doctest:: >>> c.evaluateCondition("installed foo bar") Traceback (most recent call last): ... ValueError: Only one package allowed: 'installed foo bar' >>> c.evaluateCondition("installed") Traceback (most recent call last): ... ValueError: Package name missing: 'installed' .. autofunction:: processxmlfile .. autofunction:: openInOrPlain For example, the tests/samplepackage dirextory has files: - configure.zcml - configure.zcml.in - foo.zcml.in If we open configure.zcml, we'll get that file: .. doctest:: >>> import os >>> from zope.configuration.xmlconfig import __file__ >>> from zope.configuration.xmlconfig import openInOrPlain >>> here = os.path.dirname(__file__) >>> path = os.path.join(here, 'tests', 'samplepackage', 'configure.zcml') >>> f = openInOrPlain(path) >>> f.name[-14:] 'configure.zcml' But if we open foo.zcml, we'll get foo.zcml.in, since there isn't a foo.zcml: .. doctest:: >>> path = os.path.join(here, 'tests', 'samplepackage', 'foo.zcml') >>> f = openInOrPlain(path) >>> f.name[-11:] 'foo.zcml.in' Make sure other IOErrors are re-raised. We need to do this in a try-except block because different errors are raised on Windows and on Linux. .. doctest:: >>> try: ... f = openInOrPlain('.') ... except IOError: ... print "passed" ... else: ... print "failed" passed .. autointerface:: IInclude :members: :member-order: bysource .. autofunction:: include .. autofunction:: exclude .. autofunction:: includeOverrides .. autofunction:: registerCommonDirectives .. autofunction:: file .. autofunction:: string .. autoclass:: XMLConfig :members: :member-order: bysource .. autofunction:: xmlconfig .. autofunction:: testxmlconfig zope.configuration-4.0.3/docs/api/zopeconfigure.rst0000664000175000017500000000042312073042162022355 0ustar tseavertseaver:mod:`zope.configuration.zopeconfigure` ======================================= .. automodule:: zope.configuration.zopeconfigure .. autointerface:: IZopeConfigure :members: :member-order: bysource .. autoclass:: ZopeConfigure :members: :member-order: bysource zope.configuration-4.0.3/docs/api/name.rst0000664000175000017500000000027312073042162020421 0ustar tseavertseaver:mod:`zope.configuration.name` ============================== .. module:: zope.configuration.name .. autofunction:: resolve .. autofunction:: getNormalizedName .. autofunction:: path zope.configuration-4.0.3/docs/api/docutils.rst0000664000175000017500000000107412073042162021327 0ustar tseavertseaver:mod:`zope.configuration.docutils` ================================== .. module:: zope.configuration.docutils .. autofunction:: wrap Examples: .. doctest:: >>> from zope.configuration.docutils import wrap >>> print wrap('foo bar')[:-2] foo bar >>> print wrap('foo bar', indent=2)[:-2] foo bar >>> print wrap('foo bar, more foo bar', 10)[:-2] foo bar, more foo bar >>> print wrap('foo bar, more foo bar', 10, 2)[:-2] foo bar, more foo bar .. autofunction:: makeDocStructures zope.configuration-4.0.3/docs/api/config.rst0000664000175000017500000007003312073042162020747 0ustar tseavertseaver:mod:`zope.configuration.config` ================================ .. module:: zope.configuration.config .. autoclass:: ConfigurationContext .. automethod:: resolve Examples: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> from zope.configuration.config import ConfigurationError >>> c = ConfigurationContext() >>> import zope, zope.interface >>> c.resolve('zope') is zope True >>> c.resolve('zope.interface') is zope.interface True >>> c.resolve('zope.configuration.eek') #doctest: +NORMALIZE_WHITESPACE Traceback (most recent call last): ... ConfigurationError: ImportError: Module zope.configuration has no global eek >>> c.resolve('.config.ConfigurationContext') Traceback (most recent call last): ... AttributeError: 'ConfigurationContext' object has no attribute 'package' >>> import zope.configuration >>> c.package = zope.configuration >>> c.resolve('.') is zope.configuration True >>> c.resolve('.config.ConfigurationContext') is ConfigurationContext True >>> c.resolve('..interface') is zope.interface True >>> c.resolve('str') .. automethod:: path Examples: .. doctest:: >>> import os >>> from zope.configuration.config import ConfigurationContext >>> c = ConfigurationContext() >>> c.path("/x/y/z") == os.path.normpath("/x/y/z") True >>> c.path("y/z") Traceback (most recent call last): ... AttributeError: 'ConfigurationContext' object has no attribute 'package' >>> import zope.configuration >>> c.package = zope.configuration >>> import os >>> d = os.path.dirname(zope.configuration.__file__) >>> c.path("y/z") == d + os.path.normpath("/y/z") True >>> c.path("y/./z") == d + os.path.normpath("/y/z") True >>> c.path("y/../z") == d + os.path.normpath("/z") True .. automethod:: checkDuplicate Examples: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> from zope.configuration.config import ConfigurationError >>> c = ConfigurationContext() >>> c.checkDuplicate('/foo.zcml') >>> try: ... c.checkDuplicate('/foo.zcml') ... except ConfigurationError as e: ... # On Linux the exact msg has /foo, on Windows \foo. ... str(e).endswith("foo.zcml' included more than once") True You may use different ways to refer to the same file: .. doctest:: >>> import zope.configuration >>> c.package = zope.configuration >>> import os >>> d = os.path.dirname(zope.configuration.__file__) >>> c.checkDuplicate('bar.zcml') >>> try: ... c.checkDuplicate(d + os.path.normpath('/bar.zcml')) ... except ConfigurationError as e: ... str(e).endswith("bar.zcml' included more than once") ... True .. automethod:: processFile Examples: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> c = ConfigurationContext() >>> c.processFile('/foo.zcml') True >>> c.processFile('/foo.zcml') False You may use different ways to refer to the same file: .. doctest:: >>> import zope.configuration >>> c.package = zope.configuration >>> import os >>> d = os.path.dirname(zope.configuration.__file__) >>> c.processFile('bar.zcml') True >>> c.processFile('bar.zcml') False .. automethod:: action Examples: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> c = ConfigurationContext() Normally, the context gets actions from subclasses. We'll provide an actions attribute ourselves: .. doctest:: >>> c.actions = [] We'll use a test callable that has a convenient string representation .. doctest:: >>> from zope.configuration.tests.directives import f >>> c.action(1, f, (1, ), {'x': 1}) >>> from pprint import PrettyPrinter >>> pprint=PrettyPrinter(width=60).pprint >>> pprint(c.actions) [{'args': (1,), 'callable': f, 'discriminator': 1, 'includepath': (), 'info': '', 'kw': {'x': 1}, 'order': 0}] >>> c.action(None) >>> pprint(c.actions) [{'args': (1,), 'callable': f, 'discriminator': 1, 'includepath': (), 'info': '', 'kw': {'x': 1}, 'order': 0}, {'args': (), 'callable': None, 'discriminator': None, 'includepath': (), 'info': '', 'kw': {}, 'order': 0}] Now set the include path and info: .. doctest:: >>> c.includepath = ('foo.zcml',) >>> c.info = "?" >>> c.action(None) >>> pprint(c.actions[-1]) {'args': (), 'callable': None, 'discriminator': None, 'includepath': ('foo.zcml',), 'info': '?', 'kw': {}, 'order': 0} We can add an order argument to crudely control the order of execution: .. doctest:: >>> c.action(None, order=99999) >>> pprint(c.actions[-1]) {'args': (), 'callable': None, 'discriminator': None, 'includepath': ('foo.zcml',), 'info': '?', 'kw': {}, 'order': 99999} We can also pass an includepath argument, which will be used as the the includepath for the action. (if includepath is None, self.includepath will be used): .. doctest:: >>> c.action(None, includepath=('abc',)) >>> pprint(c.actions[-1]) {'args': (), 'callable': None, 'discriminator': None, 'includepath': ('abc',), 'info': '?', 'kw': {}, 'order': 0} We can also pass an info argument, which will be used as the the source line info for the action. (if info is None, self.info will be used): .. doctest:: >>> c.action(None, info='abc') >>> pprint(c.actions[-1]) {'args': (), 'callable': None, 'discriminator': None, 'includepath': ('foo.zcml',), 'info': 'abc', 'kw': {}, 'order': 0} .. automethod:: hasFeature Examples: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> c = ConfigurationContext() >>> c.hasFeature('onlinehelp') False You can declare that a feature is provided .. doctest:: >>> c.provideFeature('onlinehelp') and it becomes available .. doctest:: >>> c.hasFeature('onlinehelp') True .. automethod:: provideFeature .. autoclass:: ConfigurationAdapterRegistry :members: :member-order: bysource Examples: .. doctest:: >>> from zope.configuration.interfaces import IConfigurationContext >>> from zope.configuration.config import ConfigurationAdapterRegistry >>> from zope.configuration.config import ConfigurationError >>> from zope.configuration.config import ConfigurationMachine >>> r = ConfigurationAdapterRegistry() >>> c = ConfigurationMachine() >>> r.factory(c, ('http://www.zope.com','xxx')) Traceback (most recent call last): ... ConfigurationError: ('Unknown directive', 'http://www.zope.com', 'xxx') >>> def f(): ... pass >>> r.register(IConfigurationContext, ('http://www.zope.com', 'xxx'), f) >>> r.factory(c, ('http://www.zope.com','xxx')) is f True >>> r.factory(c, ('http://www.zope.com','yyy')) is f Traceback (most recent call last): ... ConfigurationError: ('Unknown directive', 'http://www.zope.com', 'yyy') >>> r.register(IConfigurationContext, 'yyy', f) >>> r.factory(c, ('http://www.zope.com','yyy')) is f True Test the documentation feature: .. doctest:: >>> from zope.configuration.config import IFullInfo >>> r._docRegistry [] >>> r.document(('ns', 'dir'), IFullInfo, IConfigurationContext, None, ... 'inf', None) >>> r._docRegistry[0][0] == ('ns', 'dir') True >>> r._docRegistry[0][1] is IFullInfo True >>> r._docRegistry[0][2] is IConfigurationContext True >>> r._docRegistry[0][3] is None True >>> r._docRegistry[0][4] == 'inf' True >>> r._docRegistry[0][5] is None True >>> r.document('all-dir', None, None, None, None) >>> r._docRegistry[1][0] ('', 'all-dir') .. autoclass:: ConfigurationMachine Example: .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> machine = ConfigurationMachine() >>> ns = "http://www.zope.org/testing" Register a directive: .. doctest:: >>> from zope.configuration.config import metans >>> machine((metans, "directive"), ... namespace=ns, name="simple", ... schema="zope.configuration.tests.directives.ISimple", ... handler="zope.configuration.tests.directives.simple") and try it out: .. doctest:: >>> machine((ns, "simple"), a=u"aa", c=u"cc") >>> from pprint import PrettyPrinter >>> pprint = PrettyPrinter(width=60).pprint >>> pprint(machine.actions) [{'args': (u'aa', u'xxx', 'cc'), 'callable': f, 'discriminator': ('simple', u'aa', u'xxx', 'cc'), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}] .. automethod:: begin .. automethod:: end .. automethod:: __call__ .. automethod:: getInfo .. automethod:: setInfo .. automethod:: execute_actions For example: .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> output = [] >>> def f(*a, **k): #* syntax highlighting ... output.append(('f', a, k)) >>> context = ConfigurationMachine() >>> context.actions = [ ... (1, f, (1,)), ... (1, f, (11,), {}, ('x', )), ... (2, f, (2,)), ... ] >>> context.execute_actions() >>> output [('f', (1,), {}), ('f', (2,), {})] If the action raises an error, we convert it to a ConfigurationExecutionError. .. doctest:: >>> from zope.configuration.config import ConfigurationExecutionError >>> output = [] >>> def bad(): ... bad.xxx >>> context.actions = [ ... (1, f, (1,)), ... (1, f, (11,), {}, ('x', )), ... (2, f, (2,)), ... (3, bad, (), {}, (), 'oops') ... ] >>> try: ... v = context.execute_actions() ... except ConfigurationExecutionError as v: ... pass >>> lines = str(v).splitlines() >>> 'exceptions.AttributeError' in lines[0] True >>> lines[0].endswith("'function' object has no attribute 'xxx'") True >>> lines[1:] [' in:', ' oops'] Note that actions executed before the error still have an effect: .. doctest:: >>> output [('f', (1,), {}), ('f', (2,), {})] .. autoclass:: ConfigurationExecutionError .. autointerface:: IStackItem :members: :member-order: bysource .. autoclass:: SimpleStackItem :members: :member-order: bysource .. autoclass:: RootStackItem :members: :member-order: bysource .. autoclass:: GroupingStackItem :members: :member-order: bysource To see how this works, let's look at an example: We need a context. We'll just use a configuration machine .. doctest:: >>> from zope.configuration.config import GroupingStackItem >>> from zope.configuration.config import ConfigurationMachine >>> context = ConfigurationMachine() We need a callable to use in configuration actions. We'll use a convenient one from the tests: .. doctest:: >>> from zope.configuration.tests.directives import f We need a handler for the grouping directive. This is a class that implements a context decorator. The decorator must also provide ``before`` and ``after`` methods that are called before and after any contained directives are processed. We'll typically subclass ``GroupingContextDecorator``, which provides context decoration, and default ``before`` and ``after`` methods. .. doctest:: >>> from zope.configuration.config import GroupingContextDecorator >>> class SampleGrouping(GroupingContextDecorator): ... def before(self): ... self.action(('before', self.x, self.y), f) ... def after(self): ... self.action(('after'), f) We'll use our decorator to decorate our initial context, providing keyword arguments x and y: .. doctest:: >>> dec = SampleGrouping(context, x=1, y=2) Note that the keyword arguments are made attributes of the decorator. Now we'll create the stack item. .. doctest:: >>> item = GroupingStackItem(dec) We still haven't called the before action yet, which we can verify by looking at the context actions: .. doctest:: >>> context.actions [] Subdirectives will get looked up as adapters of the context. We'll create a simple handler: .. doctest:: >>> def simple(context, data, info): ... context.action(("simple", context.x, context.y, data), f) ... return info and register it with the context: .. doctest:: >>> from zope.configuration.interfaces import IConfigurationContext >>> from zope.configuration.config import testns >>> context.register(IConfigurationContext, (testns, 'simple'), simple) This handler isn't really a propert handler, because it doesn't return a new context. It will do for this example. Now we'll call the contained method on the stack item: .. doctest:: >>> item.contained((testns, 'simple'), {'z': 'zope'}, "someinfo") 'someinfo' We can verify thet the simple method was called by looking at the context actions. Note that the before method was called before handling the contained directive. .. doctest:: >>> from pprint import PrettyPrinter >>> pprint = PrettyPrinter(width=60).pprint >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': ('before', 1, 2), 'includepath': (), 'info': '', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('simple', 1, 2, {'z': 'zope'}), 'includepath': (), 'info': '', 'kw': {}, 'order': 0}] Finally, we call finish, which calls the decorator after method: .. doctest:: >>> item.finish() >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': ('before', 1, 2), 'includepath': (), 'info': '', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('simple', 1, 2, {'z': 'zope'}), 'includepath': (), 'info': '', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': 'after', 'includepath': (), 'info': '', 'kw': {}, 'order': 0}] If there were no nested directives: .. doctest:: >>> context = ConfigurationMachine() >>> dec = SampleGrouping(context, x=1, y=2) >>> item = GroupingStackItem(dec) >>> item.finish() Then before will be when we call finish: .. doctest:: >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': ('before', 1, 2), 'includepath': (), 'info': '', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': 'after', 'includepath': (), 'info': '', 'kw': {}, 'order': 0}] .. autoclass:: ComplexStackItem :members: :member-order: bysource To see how this works, let's look at an example: We need a context. We'll just use a configuration machine .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> context = ConfigurationMachine() We need a callable to use in configuration actions. We'll use a convenient one from the tests: .. doctest:: >>> from zope.configuration.tests.directives import f We need a handler for the complex directive. This is a class with a method for each subdirective: .. doctest:: >>> class Handler(object): ... def __init__(self, context, x, y): ... self.context, self.x, self.y = context, x, y ... context.action('init', f) ... def sub(self, context, a, b): ... context.action(('sub', a, b), f) ... def __call__(self): ... self.context.action(('call', self.x, self.y), f) We need a complex directive definition: .. doctest:: >>> from zope.interface import Interface >>> from zope.schema import TextLine >>> from zope.configuration.config import ComplexDirectiveDefinition >>> class Ixy(Interface): ... x = TextLine() ... y = TextLine() >>> definition = ComplexDirectiveDefinition( ... context, name="test", schema=Ixy, ... handler=Handler) >>> class Iab(Interface): ... a = TextLine() ... b = TextLine() >>> definition['sub'] = Iab, '' OK, now that we have the context, handler and definition, we're ready to use a stack item. .. doctest:: >>> from zope.configuration.config import ComplexStackItem >>> item = ComplexStackItem(definition, context, {'x': u'xv', 'y': u'yv'}, ... 'foo') When we created the definition, the handler (factory) was called. .. doctest:: >>> from pprint import PrettyPrinter >>> pprint = PrettyPrinter(width=60).pprint >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': 'init', 'includepath': (), 'info': 'foo', 'kw': {}, 'order': 0}] If a subdirective is provided, the ``contained`` method of the stack item is called. It will lookup the subdirective schema and call the corresponding method on the handler instance: .. doctest:: >>> simple = item.contained(('somenamespace', 'sub'), ... {'a': u'av', 'b': u'bv'}, 'baz') >>> simple.finish() Note that the name passed to ``contained`` is a 2-part name, consisting of a namespace and a name within the namespace. .. doctest:: >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': 'init', 'includepath': (), 'info': 'foo', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('sub', u'av', u'bv'), 'includepath': (), 'info': 'baz', 'kw': {}, 'order': 0}] The new stack item returned by contained is one that doesn't allow any more subdirectives, When all of the subdirectives have been provided, the ``finish`` method is called: .. doctest:: >>> item.finish() The stack item will call the handler if it is callable. .. doctest:: >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': 'init', 'includepath': (), 'info': 'foo', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('sub', u'av', u'bv'), 'includepath': (), 'info': 'baz', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('call', u'xv', u'yv'), 'includepath': (), 'info': 'foo', 'kw': {}, 'order': 0}] .. autoclass:: GroupingContextDecorator :members: :member-order: bysource .. autoclass:: DirectiveSchema :members: :member-order: bysource .. autointerface:: IDirectivesInfo :members: :member-order: bysource .. autointerface:: IDirectivesContext :members: :member-order: bysource .. autoclass:: DirectivesHandler :members: :member-order: bysource .. autointerface:: IDirectiveInfo :members: :member-order: bysource .. autointerface:: IFullInfo :members: :member-order: bysource .. autointerface:: IStandaloneDirectiveInfo :members: :member-order: bysource .. autofunction:: defineSimpleDirective Example: .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> context = ConfigurationMachine() >>> from zope.interface import Interface >>> from zope.schema import TextLine >>> from zope.configuration.tests.directives import f >>> class Ixy(Interface): ... x = TextLine() ... y = TextLine() >>> def s(context, x, y): ... context.action(('s', x, y), f) >>> from zope.configuration.config import defineSimpleDirective >>> defineSimpleDirective(context, 's', Ixy, s, testns) >>> context((testns, "s"), x=u"vx", y=u"vy") >>> from pprint import PrettyPrinter >>> pprint = PrettyPrinter(width=60).pprint >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': ('s', u'vx', u'vy'), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}] >>> context(('http://www.zope.com/t1', "s"), x=u"vx", y=u"vy") Traceback (most recent call last): ... ConfigurationError: ('Unknown directive', 'http://www.zope.com/t1', 's') >>> context = ConfigurationMachine() >>> defineSimpleDirective(context, 's', Ixy, s, "*") >>> context(('http://www.zope.com/t1', "s"), x=u"vx", y=u"vy") >>> pprint(context.actions) [{'args': (), 'callable': f, 'discriminator': ('s', u'vx', u'vy'), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}] .. autofunction:: defineGroupingDirective Example: .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> context = ConfigurationMachine() >>> from zope.interface import Interface >>> from zope.schema import TextLine >>> from zope.configuration.tests.directives import f >>> class Ixy(Interface): ... x = TextLine() ... y = TextLine() We won't bother creating a special grouping directive class. We'll just use :class:`GroupingContextDecorator`, which simply sets up a grouping context that has extra attributes defined by a schema: .. doctest:: >>> from zope.configuration.config import defineGroupingDirective >>> from zope.configuration.config import GroupingContextDecorator >>> defineGroupingDirective(context, 'g', Ixy, ... GroupingContextDecorator, testns) >>> context.begin((testns, "g"), x=u"vx", y=u"vy") >>> context.stack[-1].context.x u'vx' >>> context.stack[-1].context.y u'vy' >>> context(('http://www.zope.com/t1', "g"), x=u"vx", y=u"vy") Traceback (most recent call last): ... ConfigurationError: ('Unknown directive', 'http://www.zope.com/t1', 'g') >>> context = ConfigurationMachine() >>> defineGroupingDirective(context, 'g', Ixy, ... GroupingContextDecorator, "*") >>> context.begin(('http://www.zope.com/t1', "g"), x=u"vx", y=u"vy") >>> context.stack[-1].context.x u'vx' >>> context.stack[-1].context.y u'vy' .. autointerface:: IComplexDirectiveContext :members: :member-order: bysource .. autoclass:: ComplexDirectiveDefinition :members: :member-order: bysource .. autofunction:: subdirective .. autointerface:: IProvidesDirectiveInfo :members: :member-order: bysource .. autofunction:: provides Example: .. doctest:: >>> from zope.configuration.config import ConfigurationContext >>> from zope.configuration.config import provides >>> c = ConfigurationContext() >>> provides(c, 'apidoc') >>> c.hasFeature('apidoc') True Spaces are not allowed in feature names (this is reserved for providing many features with a single directive in the futute). .. doctest:: >>> provides(c, 'apidoc onlinehelp') Traceback (most recent call last): ... ValueError: Only one feature name allowed >>> c.hasFeature('apidoc onlinehelp') False .. autofunction:: toargs Example: .. doctest:: >>> from zope.configuration.config import toargs >>> from zope.schema import BytesLine >>> from zope.schema import Float >>> from zope.schema import Int >>> from zope.schema import TextLine >>> from zope.schema import URI >>> class schema(Interface): ... in_ = Int(constraint=lambda v: v > 0) ... f = Float() ... n = TextLine(min_length=1, default=u"rob") ... x = BytesLine(required=False) ... u = URI() >>> context = ConfigurationMachine() >>> from pprint import PrettyPrinter >>> pprint=PrettyPrinter(width=50).pprint >>> pprint(toargs(context, schema, ... {'in': u'1', 'f': u'1.2', 'n': u'bob', 'x': u'x.y.z', ... 'u': u'http://www.zope.org' })) {'f': 1.2, 'in_': 1, 'n': u'bob', 'u': 'http://www.zope.org', 'x': 'x.y.z'} If we have extra data, we'll get an error: .. doctest:: >>> toargs(context, schema, ... {'in': u'1', 'f': u'1.2', 'n': u'bob', 'x': u'x.y.z', ... 'u': u'http://www.zope.org', 'a': u'1'}) Traceback (most recent call last): ... ConfigurationError: ('Unrecognized parameters:', 'a') Unless we set a tagged value to say that extra arguments are ok: .. doctest:: >>> schema.setTaggedValue('keyword_arguments', True) >>> pprint(toargs(context, schema, ... {'in': u'1', 'f': u'1.2', 'n': u'bob', 'x': u'x.y.z', ... 'u': u'http://www.zope.org', 'a': u'1'})) {'a': u'1', 'f': 1.2, 'in_': 1, 'n': u'bob', 'u': 'http://www.zope.org', 'x': 'x.y.z'} If we omit required data we get an error telling us what was omitted: .. doctest:: >>> pprint(toargs(context, schema, ... {'in': u'1', 'f': u'1.2', 'n': u'bob', 'x': u'x.y.z'})) Traceback (most recent call last): ... ConfigurationError: ('Missing parameter:', 'u') Although we can omit not-required data: .. doctest:: >>> pprint(toargs(context, schema, ... {'in': u'1', 'f': u'1.2', 'n': u'bob', ... 'u': u'http://www.zope.org', 'a': u'1'})) {'a': u'1', 'f': 1.2, 'in_': 1, 'n': u'bob', 'u': 'http://www.zope.org'} And we can omit required fields if they have valid defaults (defaults that are valid values): .. doctest:: >>> pprint(toargs(context, schema, ... {'in': u'1', 'f': u'1.2', ... 'u': u'http://www.zope.org', 'a': u'1'})) {'a': u'1', 'f': 1.2, 'in_': 1, 'n': u'rob', 'u': 'http://www.zope.org'} We also get an error if any data was invalid: .. doctest:: >>> pprint(toargs(context, schema, ... {'in': u'0', 'f': u'1.2', 'n': u'bob', 'x': u'x.y.z', ... 'u': u'http://www.zope.org', 'a': u'1'})) Traceback (most recent call last): ... ConfigurationError: ('Invalid value for', 'in', '0') .. autofunction:: expand_action .. autofunction:: resolveConflicts .. autoclass:: ConfigurationConflictError zope.configuration-4.0.3/docs/api/interfaces.rst0000664000175000017500000000053112073042162021621 0ustar tseavertseaver:mod:`zope.configuration.interfaces` ==================================== .. module:: zope.configuration.interfaces .. autoclass:: InvalidToken :members: :member-order: bysource .. autointerface:: IConfigurationContext :members: :member-order: bysource .. autointerface:: IGroupingContext :members: :member-order: bysource zope.configuration-4.0.3/docs/api/fields.rst0000664000175000017500000002000612073042162020743 0ustar tseavertseaver:mod:`zope.configuration.fields` ================================ .. module:: zope.configuration.fields .. autoclass:: PythonIdentifier :members: :member-order: bysource Let's look at an example: .. doctest:: >>> from zope.configuration.fields import PythonIdentifier >>> class FauxContext(object): ... pass >>> context = FauxContext() >>> field = PythonIdentifier().bind(context) Let's test the fromUnicode method: .. doctest:: >>> field.fromUnicode(u'foo') u'foo' >>> field.fromUnicode(u'foo3') u'foo3' >>> field.fromUnicode(u'_foo3') u'_foo3' Now let's see whether validation works alright .. doctest:: >>> for value in (u'foo', u'foo3', u'foo_', u'_foo3', u'foo_3', u'foo3_'): ... field._validate(value) >>> from zope.schema import ValidationError >>> for value in (u'3foo', u'foo:', u'\\', u''): ... try: ... field._validate(value) ... except ValidationError: ... print 'Validation Error' Validation Error Validation Error Validation Error Validation Error .. autoclass:: GlobalObject :members: :member-order: bysource Let's look at an example: .. doctest:: >>> d = {'x': 1, 'y': 42, 'z': 'zope'} >>> class fakeresolver(dict): ... def resolve(self, n): ... return self[n] >>> fake = fakeresolver(d) >>> from zope.schema import Int >>> from zope.configuration.fields import GlobalObject >>> g = GlobalObject(value_type=Int()) >>> gg = g.bind(fake) >>> gg.fromUnicode("x") 1 >>> gg.fromUnicode(" x \n ") 1 >>> gg.fromUnicode("y") 42 >>> gg.fromUnicode("z") Traceback (most recent call last): ... WrongType: ('zope', (, ), '') >>> g = GlobalObject(constraint=lambda x: x%2 == 0) >>> gg = g.bind(fake) >>> gg.fromUnicode("x") Traceback (most recent call last): ... ConstraintNotSatisfied: 1 >>> gg.fromUnicode("y") 42 >>> g = GlobalObject() >>> gg = g.bind(fake) >>> print gg.fromUnicode('*') None .. autoclass:: GlobalInterface :members: :member-order: bysource Example: First, we need to set up a stub name resolver: .. doctest:: >>> from zope.interface import Interface >>> class IFoo(Interface): ... pass >>> class Foo(object): ... pass >>> d = {'Foo': Foo, 'IFoo': IFoo} >>> class fakeresolver(dict): ... def resolve(self, n): ... return self[n] >>> fake = fakeresolver(d) Now verify constraints are checked correctly: .. doctest:: >>> from zope.configuration.fields import GlobalInterface >>> g = GlobalInterface() >>> gg = g.bind(fake) >>> gg.fromUnicode('IFoo') is IFoo True >>> gg.fromUnicode(' IFoo ') is IFoo True >>> gg.fromUnicode('Foo') Traceback (most recent call last): ... WrongType: ('An interface is required', ... .. autoclass:: Tokens :members: :member-order: bysource Consider GlobalObject tokens: First, we need to set up a stub name resolver: .. doctest:: >>> d = {'x': 1, 'y': 42, 'z': 'zope', 'x.y.x': 'foo'} >>> class fakeresolver(dict): ... def resolve(self, n): ... return self[n] >>> fake = fakeresolver(d) >>> from zope.configuration.fields import Tokens >>> from zope.configuration.fields import GlobalObject >>> g = Tokens(value_type=GlobalObject()) >>> gg = g.bind(fake) >>> gg.fromUnicode(" \n x y z \n") [1, 42, 'zope'] >>> from zope.schema import Int >>> g = Tokens(value_type= ... GlobalObject(value_type= ... Int(constraint=lambda x: x%2 == 0))) >>> gg = g.bind(fake) >>> gg.fromUnicode("x y") Traceback (most recent call last): ... InvalidToken: 1 in x y >>> gg.fromUnicode("z y") Traceback (most recent call last): ... InvalidToken: ('zope', (, ), '') in z y >>> gg.fromUnicode("y y") [42, 42] .. autoclass:: Path :members: :member-order: bysource Let's look at an example: First, we need a "context" for the field that has a path function for converting relative path to an absolute path. We'll be careful to do this in an os-independent fashion. .. doctest:: >>> from zope.configuration.fields import Path >>> class FauxContext(object): ... def path(self, p): ... return os.path.join(os.sep, 'faux', 'context', p) >>> context = FauxContext() >>> field = Path().bind(context) Lets try an absolute path first: .. doctest:: >>> import os >>> p = unicode(os.path.join(os.sep, 'a', 'b')) >>> n = field.fromUnicode(p) >>> n.split(os.sep) [u'', u'a', u'b'] This should also work with extra spaces around the path: .. doctest:: >>> p = " \n %s \n\n " % p >>> n = field.fromUnicode(p) >>> n.split(os.sep) [u'', u'a', u'b'] Now try a relative path: .. doctest:: >>> p = unicode(os.path.join('a', 'b')) >>> n = field.fromUnicode(p) >>> n.split(os.sep) [u'', u'faux', u'context', u'a', u'b'] .. autoclass:: Bool :members: :member-order: bysource .. doctest:: >>> from zope.configuration.fields import Bool >>> Bool().fromUnicode(u"yes") True >>> Bool().fromUnicode(u"y") True >>> Bool().fromUnicode(u"true") True >>> Bool().fromUnicode(u"no") False .. autoclass:: MessageID :members: :member-order: bysource .. doctest:: >>> from zope.configuration.fields import MessageID >>> class Info(object): ... file = 'file location' ... line = 8 >>> class FauxContext(object): ... i18n_strings = {} ... info = Info() >>> context = FauxContext() >>> field = MessageID().bind(context) There is a fallback domain when no domain has been specified. Exchange the warn function so we can make test whether the warning has been issued .. doctest:: >>> warned = None >>> def fakewarn(*args, **kw): #* syntax highlighting ... global warned ... warned = args >>> import warnings >>> realwarn = warnings.warn >>> warnings.warn = fakewarn >>> i = field.fromUnicode(u"Hello world!") >>> i u'Hello world!' >>> i.domain 'untranslated' >>> warned ("You did not specify an i18n translation domain for the '' field in file location",) >>> warnings.warn = realwarn With the domain specified: .. doctest:: >>> context.i18n_strings = {} >>> context.i18n_domain = 'testing' We can get a message id: .. doctest:: >>> i = field.fromUnicode(u"Hello world!") >>> i u'Hello world!' >>> i.domain 'testing' In addition, the string has been registered with the context: .. doctest:: >>> context.i18n_strings {'testing': {u'Hello world!': [('file location', 8)]}} >>> i = field.fromUnicode(u"Foo Bar") >>> i = field.fromUnicode(u"Hello world!") >>> from pprint import PrettyPrinter >>> pprint=PrettyPrinter(width=70).pprint >>> pprint(context.i18n_strings) {'testing': {u'Foo Bar': [('file location', 8)], u'Hello world!': [('file location', 8), ('file location', 8)]}} >>> from zope.i18nmessageid import Message >>> isinstance(context.i18n_strings['testing'].keys()[0], Message) True Explicit Message IDs .. doctest:: >>> i = field.fromUnicode(u'[View-Permission] View') >>> i u'View-Permission' >>> i.default u'View' >>> i = field.fromUnicode(u'[] [Some] text') >>> i u'[Some] text' >>> i.default is None True zope.configuration-4.0.3/docs/conf.py0000664000175000017500000001753512073042162017506 0ustar tseavertseaver# -*- coding: utf-8 -*- # # zope.configuration documentation build configuration file, created by # sphinx-quickstart on Sat May 5 13:59:34 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'repoze.sphinx.autointerface', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'zope.configuration' copyright = u'2012, Zope Foundation Contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.0' # The full version, including alpha/beta/rc tags. release = '4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'zopeconfigurationdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'zopeconfiguration.tex', u'zope.configuration Documentation', u'Zope Foundation Contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'zopeconfiguration', u'zope.configuration Documentation', [u'Zope Foundation Contributors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'zopeconfiguration', u'zope.configuration Documentation', u'Zope Foundation Contributors', 'zopeconfiguration', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' zope.configuration-4.0.3/docs/index.rst0000664000175000017500000000036212073042162020036 0ustar tseavertseaver:mod:`zope.configuration` Documentation ======================================= Contents: .. toctree:: :maxdepth: 2 narr api hacking Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` zope.configuration-4.0.3/docs/narr.rst0000664000175000017500000011047212073042162017675 0ustar tseavertseaver========================== Zope configuration system ========================== The zope configuration system provides an extensible system for supporting variouse kinds of configurations. It is based on the idea of configuration directives. Users of the configuration system provide configuration directives in some language that express configuration choices. The intent is that the language be pluggable. An XML language is provided by default. Configuration is performed in three stages. In the first stage, directives are processed to compute configuration actions. Configuration actions consist of: - A discriminator - A callable - Positional arguments - Keyword arguments The actions are essentially delayed function calls. Two or more actions conflict if they have the same discriminator. The configuration system has rules for resolving conflicts. If conflicts cannot be resolved, an error will result. Conflict resolution typically discards all but one of the conflicting actions, so that the remaining action of the originally-conflicting actions no longer conflicts. Non-conflicting actions are executed in the order that they were created by passing the positional and non-positional arguments to the action callable. The system is extensible. There is a meta-configuration language for defining configuration directives. A directive is defined by providing meta data about the directive and handler code to process the directive. There are four kinds of directives: - Simple directives compute configuration actions. Their handlers are typically functions that take a context and zero or more keyword arguments and return a sequence of configuration actions. To learn how to create simple directives, see `tests/simple.py`. - Grouping directives collect information to be used by nested directives. They are called with a context object which they adapt to some interface that extends IConfigurationContext. To learn how to create grouping directives, look at the documentation in zopeconfigure.py, which provides the implementation of the zope `configure` directive. Other directives can be nested in grouping directives. To learn how to implement nested directives, look at the documentation in the "Creating Nested Directives" section below. - Complex directives are directives that have subdirectives. Subdirectives have handlers that are simply methods of complex directives. Complex diretives are handled by factories, typically classes, that create objects that have methods for handling subdirectives. These objects also have __call__ methods that are called when processing of subdirectives is finished. Complex directives only exist to support old directive handlers. They will probably be deprecated in the future. - Subdirectives are nested in complex directives. They are like simple directives except that they hane handlers that are complex directive methods. Subdirectives, like complex directives only exist to support old directive handlers. They will probably be deprecated in the future. .. todo:: Flesh out narrative docs. Using the configuration machinery programatically ================================================== An extended example: .. doctest:: >>> from zope.configuration.config import ConfigurationMachine >>> from zope.configuration.config import metans >>> machine = ConfigurationMachine() >>> ns = "http://www.zope.org/testing" Register some test directives: Start with a grouping directive that sets a package: .. doctest:: >>> machine((metans, "groupingDirective"), ... name="package", namespace=ns, ... schema="zope.configuration.tests.directives.IPackaged", ... handler="zope.configuration.tests.directives.Packaged", ... ) Now we can set the package: .. doctest:: >>> machine.begin((ns, "package"), ... package="zope.configuration.tests.directives", ... ) Which makes it easier to define the other directives: First, define some simple directives: .. doctest:: >>> machine((metans, "directive"), ... namespace=ns, name="simple", ... schema=".ISimple", handler=".simple") >>> machine((metans, "directive"), ... namespace=ns, name="newsimple", ... schema=".ISimple", handler=".newsimple") and try them out: .. doctest:: >>> machine((ns, "simple"), "first", a=u"aa", c=u"cc") >>> machine((ns, "newsimple"), "second", a=u"naa", c=u"ncc", b=u"nbb") >>> from pprint import PrettyPrinter >>> pprint = PrettyPrinter(width=50).pprint >>> pprint(machine.actions) [{'args': (u'aa', u'xxx', 'cc'), 'callable': f, 'discriminator': ('simple', u'aa', u'xxx', 'cc'), 'includepath': (), 'info': 'first', 'kw': {}, 'order': 0}, {'args': (u'naa', u'nbb', 'ncc'), 'callable': f, 'discriminator': ('newsimple', u'naa', u'nbb', 'ncc'), 'includepath': (), 'info': 'second', 'kw': {}, 'order': 0}] Define and try a simple directive that uses a component: .. doctest:: >>> machine((metans, "directive"), ... namespace=ns, name="factory", ... schema=".IFactory", handler=".factory") >>> machine((ns, "factory"), factory=u".f") >>> pprint(machine.actions[-1:]) [{'args': (), 'callable': f, 'discriminator': ('factory', 1, 2), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}] Define and try a complex directive: .. doctest:: >>> machine.begin((metans, "complexDirective"), ... namespace=ns, name="testc", ... schema=".ISimple", handler=".Complex") >>> machine((metans, "subdirective"), ... name="factory", schema=".IFactory") >>> machine.end() >>> machine.begin((ns, "testc"), None, "third", a=u'ca', c='cc') >>> machine((ns, "factory"), "fourth", factory=".f") Note that we can't call a complex method unless there is a directive for it: .. doctest:: >>> machine((ns, "factory2"), factory=".f") Traceback (most recent call last): ... ConfigurationError: ('Invalid directive', 'factory2') >>> machine.end() >>> pprint(machine.actions) [{'args': (u'aa', u'xxx', 'cc'), 'callable': f, 'discriminator': ('simple', u'aa', u'xxx', 'cc'), 'includepath': (), 'info': 'first', 'kw': {}, 'order': 0}, {'args': (u'naa', u'nbb', 'ncc'), 'callable': f, 'discriminator': ('newsimple', u'naa', u'nbb', 'ncc'), 'includepath': (), 'info': 'second', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('factory', 1, 2), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}, {'args': (), 'callable': None, 'discriminator': 'Complex.__init__', 'includepath': (), 'info': 'third', 'kw': {}, 'order': 0}, {'args': (u'ca',), 'callable': f, 'discriminator': ('Complex.factory', 1, 2), 'includepath': (), 'info': 'fourth', 'kw': {}, 'order': 0}, {'args': (u'xxx', 'cc'), 'callable': f, 'discriminator': ('Complex', 1, 2), 'includepath': (), 'info': 'third', 'kw': {}, 'order': 0}] Done with the package .. doctest:: >>> machine.end() Verify that we can use a simple directive outside of the package: .. doctest:: >>> machine((ns, "simple"), a=u"oaa", c=u"occ", b=u"obb") But we can't use the factory directive, because it's only valid inside a package directive: .. doctest:: >>> machine((ns, "factory"), factory=u".F") Traceback (most recent call last): ... ConfigurationError: ('Invalid value for', 'factory',""" \ """ "Can't use leading dots in dotted names, no package has been set.") >>> pprint(machine.actions) [{'args': (u'aa', u'xxx', 'cc'), 'callable': f, 'discriminator': ('simple', u'aa', u'xxx', 'cc'), 'includepath': (), 'info': 'first', 'kw': {}, 'order': 0}, {'args': (u'naa', u'nbb', 'ncc'), 'callable': f, 'discriminator': ('newsimple', u'naa', u'nbb', 'ncc'), 'includepath': (), 'info': 'second', 'kw': {}, 'order': 0}, {'args': (), 'callable': f, 'discriminator': ('factory', 1, 2), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}, {'args': (), 'callable': None, 'discriminator': 'Complex.__init__', 'includepath': (), 'info': 'third', 'kw': {}, 'order': 0}, {'args': (u'ca',), 'callable': f, 'discriminator': ('Complex.factory', 1, 2), 'includepath': (), 'info': 'fourth', 'kw': {}, 'order': 0}, {'args': (u'xxx', 'cc'), 'callable': f, 'discriminator': ('Complex', 1, 2), 'includepath': (), 'info': 'third', 'kw': {}, 'order': 0}, {'args': (u'oaa', u'obb', 'occ'), 'callable': f, 'discriminator': ('simple', u'oaa', u'obb', 'occ'), 'includepath': (), 'info': None, 'kw': {}, 'order': 0}] Overriding Included Configuration ================================== When we have conflicting directives, we can resolve them if one of the conflicting directives was from a file that included all of the others. The problem with this is that this requires that all of the overriding directives be in one file, typically the top-most including file. This isn't very convenient. Fortunately, we can overcome this with the includeOverrides directive. Let's look at an example to see how this works. Look at the file ``bar.zcml`` (in ``zope/configuration/tests/samplepackage``): - It includes ``bar1.zcml`` and ``bar2.zcml``. - ``bar1.zcml`` includes ``configure.zcml`` and has a ``foo`` directive. - ``bar2.zcml`` includes ``bar21.zcml``, and has a ``foo`` directive that conflicts with one in ``bar1.zcml``. - ``bar2.zcml`` also overrides a foo directive in ``bar21.zcml``. - ``bar21.zcml`` has a ``foo`` directive that conflicts with one in in ``configure.zcml``. Whew! Let's see what happens when we try to process ``bar.zcml``. .. doctest:: >>> import os >>> from zope.configuration.config import ConfigurationMachine >>> from zope.configuration.xmlconfig import include >>> from zope.configuration.xmlconfig import registerCommonDirectives >>> context = ConfigurationMachine() >>> registerCommonDirectives(context) >>> from zope.configuration.tests import __file__ >>> here = os.path.dirname(__file__) >>> path = os.path.join(here, "samplepackage", "bar.zcml") >>> include(context, path) So far so good, let's look at the configuration actions: .. doctest:: >>> from zope.configuration.tests.test_xmlconfig import clean_actions >>> pprint = PrettyPrinter(width=70).pprint >>> pprint(clean_actions(context.actions)) [{'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar1.zcml', 'tests/samplepackage/configure.zcml'], 'info': 'File "tests/samplepackage/configure.zcml", line 12.2-12.29'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar1.zcml'], 'info': 'File "tests/samplepackage/bar1.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar2.zcml', 'tests/samplepackage/bar21.zcml'], 'info': 'File "tests/samplepackage/bar21.zcml", line 3.2-3.24'}, {'discriminator': (('x', 'blah'), ('y', 2)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar2.zcml', 'tests/samplepackage/bar21.zcml'], 'info': 'File "tests/samplepackage/bar21.zcml", line 4.2-4.24'}, {'discriminator': (('x', 'blah'), ('y', 2)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar2.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/bar.zcml', 'tests/samplepackage/bar2.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 6.2-6.24'}] As you can see, there are a number of conflicts (actions with the same discriminator). Some of these can be resolved, but many can't, as we'll find if we try to execuse the actions: .. doctest:: >>> from zope.configuration.config import ConfigurationConflictError >>> from zope.configuration.tests.test_xmlconfig import clean_text_w_paths >>> try: ... v = context.execute_actions() ... except ConfigurationConflictError, v: ... pass >>> print clean_text_w_paths(str(v)) Conflicting configuration actions For: (('x', 'blah'), ('y', 0)) File "tests/samplepackage/configure.zcml", line 12.2-12.29 File "tests/samplepackage/bar21.zcml", line 3.2-3.24 For: (('x', 'blah'), ('y', 1)) File "tests/samplepackage/bar1.zcml", line 5.2-5.24 File "tests/samplepackage/bar2.zcml", line 6.2-6.24 Note that the conflicts for (('x', 'blah'), ('y', 2)) aren't included in the error because they could be resolved. Let's try this again using includeOverrides. We'll include baro.zcml which includes bar2.zcml as overrides. .. doctest:: >>> context = ConfigurationMachine() >>> registerCommonDirectives(context) >>> path = os.path.join(here, "samplepackage", "baro.zcml") >>> include(context, path) Now, if we look at the actions: .. doctest:: >>> pprint(clean_actions(context.actions)) [{'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/baro.zcml', 'tests/samplepackage/bar1.zcml', 'tests/samplepackage/configure.zcml'], 'info': 'File "tests/samplepackage/configure.zcml", line 12.2-12.29'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/baro.zcml', 'tests/samplepackage/bar1.zcml'], 'info': 'File "tests/samplepackage/bar1.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/baro.zcml'], 'info': 'File "tests/samplepackage/bar21.zcml", line 3.2-3.24'}, {'discriminator': (('x', 'blah'), ('y', 2)), 'includepath': ['tests/samplepackage/baro.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/baro.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 6.2-6.24'}] We see that: - The conflicting actions between bar2.zcml and bar21.zcml have been resolved, and - The remaining (after conflict resolution) actions from bar2.zcml and bar21.zcml have the includepath that they would have if they were defined in baro.zcml and this override the actions from bar1.zcml and configure.zcml. We can now execute the actions without problem, since the remaining conflicts are resolvable: .. doctest:: >>> context.execute_actions() We should now have three entries in foo.data: .. doctest:: >>> from zope.configuration.tests.samplepackage import foo >>> from zope.configuration.tests.test_xmlconfig import clean_info_path >>> len(foo.data) 3 >>> data = foo.data.pop(0) >>> data.args (('x', 'blah'), ('y', 0)) >>> print clean_info_path(`data.info`) File "tests/samplepackage/bar21.zcml", line 3.2-3.24 >>> data = foo.data.pop(0) >>> data.args (('x', 'blah'), ('y', 2)) >>> print clean_info_path(`data.info`) File "tests/samplepackage/bar2.zcml", line 5.2-5.24 >>> data = foo.data.pop(0) >>> data.args (('x', 'blah'), ('y', 1)) >>> print clean_info_path(`data.info`) File "tests/samplepackage/bar2.zcml", line 6.2-6.24 We expect the exact same results when using includeOverrides with the ``files`` argument instead of the ``file`` argument. The baro2.zcml file uses the former: .. doctest:: >>> context = ConfigurationMachine() >>> registerCommonDirectives(context) >>> path = os.path.join(here, "samplepackage", "baro2.zcml") >>> include(context, path) Actions look like above: .. doctest:: >>> pprint(clean_actions(context.actions)) [{'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/baro2.zcml', 'tests/samplepackage/bar1.zcml', 'tests/samplepackage/configure.zcml'], 'info': 'File "tests/samplepackage/configure.zcml", line 12.2-12.29'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/baro2.zcml', 'tests/samplepackage/bar1.zcml'], 'info': 'File "tests/samplepackage/bar1.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 0)), 'includepath': ['tests/samplepackage/baro2.zcml'], 'info': 'File "tests/samplepackage/bar21.zcml", line 3.2-3.24'}, {'discriminator': (('x', 'blah'), ('y', 2)), 'includepath': ['tests/samplepackage/baro2.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 5.2-5.24'}, {'discriminator': (('x', 'blah'), ('y', 1)), 'includepath': ['tests/samplepackage/baro2.zcml'], 'info': 'File "tests/samplepackage/bar2.zcml", line 6.2-6.24'}] >>> context.execute_actions() >>> len(foo.data) 3 >>> del foo.data[:] Making specific directives conditional ====================================== There is a ``condition`` attribute in the "http://namespaces.zope.org/zcml" namespace which is honored on all elements in ZCML. The value of the attribute is an expression which is used to determine if that element and its descendents are used. If the condition is true, processing continues normally, otherwise that element and its descendents are ignored. Currently the expression is always of the form "have featurename", and it checks for the presence of a ````. Our demonstration uses a trivial registry; each registration consists of a simple id inserted in the global `registry` in this module. We can checked that a registration was made by checking whether the id is present in `registry`. .. doctest:: >>> from zope.configuration.tests.conditions import registry >>> registry [] We start by loading the example ZCML file, *conditions.zcml*: .. doctest:: >>> import zope.configuration.tests >>> from zope.configuration.xmlconfig import file >>> context = file("conditions.zcml", zope.configuration.tests) To show that our sample directive works, we see that the unqualified registration was successful: .. doctest:: >>> "unqualified.registration" in registry True When the expression specified with ``zcml:condition`` evaluates to true, the element it is attached to and all contained elements (not otherwise conditioned) should be processed normally: .. doctest:: >>> "direct.true.condition" in registry True >>> "nested.true.condition" in registry True However, when the expression evaluates to false, the conditioned element and all contained elements should be ignored: .. doctest:: >>> "direct.false.condition" in registry False >>> "nested.false.condition" in registry False Conditions on container elements affect the conditions in nested elements in a reasonable way. If an "outer" condition is true, nested conditions are processed normally: .. doctest:: >>> "true.condition.nested.in.true" in registry True >>> "false.condition.nested.in.true" in registry False If the outer condition is false, inner conditions are not even evaluated, and the nested elements are ignored: .. doctest:: >>> "true.condition.nested.in.false" in registry False >>> "false.condition.nested.in.false" in registry False .. testcleanup:: del registry[:] Filtering and Inhibiting Configuration ====================================== The ``exclude`` standard directive is provided for inhibiting unwanted configuration. It is used to exclude processing of configuration files. It is useful when including a configuration that includes some other configuration that you don't want. It must be used BEFORE including the files to be excluded. First, let's look at an example. The zope.configuration.tests.excludedemo package has a ZCML configuration that includes some other configuration files. We'll set a log handler so we can see what's going on: .. doctest:: >>> import logging >>> import logging.handlers >>> import sys >>> logger = logging.getLogger('config') >>> oldlevel = logger.level >>> logger.setLevel(logging.DEBUG) >>> handler = logging.handlers.MemoryHandler(10) >>> logger.addHandler(handler) Now, we'll include the zope.configuration.tests.excludedemo config: .. doctest:: >>> from zope.configuration.xmlconfig import string >>> _ = string('') >>> len(handler.buffer) 3 >>> logged = [x.msg for x in handler.buffer] >>> logged[0].startswith('include ') True >>> logged[0].endswith('zope/configuration/tests/excludedemo/configure.zcml') True >>> logged[1].startswith('include ') True >>> logged[1].endswith('zope/configuration/tests/excludedemo/sub/configure.zcml') True >>> logged[2].startswith('include ') True >>> logged[2].endswith('zope/configuration/tests/excludedemo/spam.zcml') True >>> del handler.buffer[:] Each run of the configuration machinery runs with fresh state, so rerunning gives the same thing: .. doctest:: >>> _ = string('') >>> len(handler.buffer) 3 >>> logged = [x.msg for x in handler.buffer] >>> logged[0].startswith('include ') True >>> logged[0].endswith('zope/configuration/tests/excludedemo/configure.zcml') True >>> logged[1].startswith('include ') True >>> logged[1].endswith('zope/configuration/tests/excludedemo/sub/configure.zcml') True >>> logged[2].startswith('include ') True >>> logged[2].endswith('zope/configuration/tests/excludedemo/spam.zcml') True >>> del handler.buffer[:] Now, we'll use the exclude directive to exclude the two files included by the configuration file in zope.configuration.tests.excludedemo: .. doctest:: >>> _ = string( ... ''' ... ... ... ... ... ... ''') >>> len(handler.buffer) 1 >>> logged = [x.msg for x in handler.buffer] >>> logged[0].startswith('include ') True >>> logged[0].endswith('zope/configuration/tests/excludedemo/configure.zcml') True .. testcleanup:: logger.setLevel(oldlevel) logger.removeHandler(handler) Creating simple directives ========================== A simple directive is a directive that doesn't contain other directives. It can be implemented via a fairly simple function. To implement a simple directive, you need to do 3 things: - You need to create a schema to describe the directive parameters, - You need to write a directive handler, and - You need to register the directive. In this example, we'll implement a contrived example that records information about files in a file registry. The file registry is just the list, ``file_registry``. .. doctest:: >>> from zope.configuration.tests.simple import file_registry Our registry will contain tuples with: - file path - file title - description - Information about where the file was defined Our schema is defined in ``zope.configuration.tests.simple.IRegisterFile`` (q.v). .. doctest:: >>> from zope.configuration.tests.simple import IRegisterFile Our schema lists the ``path`` and ``title`` attributes. We'll get the description and other information for free, as we'll see later. The title is not required, and may be omitted. The job of a configuration handler is to compute one or more configuration actions. Configuration actions are defered function calls. The handler doesn't perform the actions. It just computes actions, which may be performed later if they are not overridden by other directives. Our handler is given in the function, ``zope.configuration.tests.simple.registerFile``. .. doctest:: >>> from zope.configuration.tests.simple import registerFile It takes a context, a path and a title. All directive handlers take the directive context as the first argument. A directive context, at a minimim, implements, ``zope.configuration.IConfigurationContext``. (Specialized contexts can implement more specific interfaces. We'll say more about that when we talk about grouping directives.) The title argument must have a default value, because we indicated that the title was not required in the schema. (Alternatively, we could have made the title required, but provided a default value in the schema. In the first line of function ``registerFile``, we get the context information object. This object contains information about the configuration directive, such as the file and location within the file of the directive. The context information object also has a text attribute that contains the textual data contained by the configuration directive. (This is the concatenation of all of the xml text nodes directly contained by the directive.) We use this for our description in the second line of the handler. The last thing the handler does is to compute an action by calling the action method of the context. It passes the action method 3 keyword arguments: - discriminator The discriminator is used to identify the action to be performed so that duplicate actions can be detected. Two actions are duplicated, and this conflict, if they have the same discriminator values and the values are not ``None``. Conflicting actions can be resolved if one of the conflicting actions is from a configuration file that directly or indirectly includes the files containing the other conflicting actions. In function ``registerFile``, we a tuple with the string ``'RegisterFile'`` and the path to be registered. - callable The callable is the object to be called to perform the action. - args The args argument contains positinal arguments to be passed to the callable. In function ``registerFile``, we pass a tuple containing a ``FileInfo`` object. (Note that there's nothing special about the FileInfo class. It has nothing to do with creating simple directives. It's just used in this example to organize the application data.) The final step in implementing the simple directive is to register it. We do that with the zcml ``meta:directive`` directive. This is given in the file simple.zcml. Here we specify the name, namespace, schema, and handler for the directive. We also provide a documentation for the directive as text between the start and end tags. The file simple.zcml also includes some directives that use the new directive to register some files. Now let's try it all out: .. doctest:: >>> from zope.configuration import tests >>> from zope.configuration.xmlconfig import file >>> context = file("simple.zcml", tests) Now we should see some file information in the registry: .. doctest:: >>> from zope.configuration.tests.test_xmlconfig import clean_text_w_paths >>> from zope.configuration.tests.test_xmlconfig import clean_path >>> print clean_path(file_registry[0].path) tests/simple.py >>> print file_registry[0].title How to create a simple directive >>> print file_registry[0].description Describes how to implement a simple directive >>> print clean_text_w_paths(file_registry[0].info) File "tests/simple.zcml", line 19.2-24.2 Describes how to implement a simple directive >>> print clean_path(file_registry[1].path) tests/simple.zcml >>> print file_registry[1].title >>> desc = file_registry[1].description >>> print '\n'.join([l.rstrip() ... for l in desc.strip().splitlines() ... if l.rstrip()]) Shows the ZCML directives needed to register a simple directive. Also show some usage examples, >>> print clean_text_w_paths(file_registry[1].info) File "tests/simple.zcml", line 26.2-30.2 Shows the ZCML directives needed to register a simple directive. Also show some usage examples, >>> print clean_path(file_registry[2].path) tests/__init__.py >>> print file_registry[2].title Make this a package >>> print file_registry[2].description >>> print clean_text_w_paths(file_registry[2].info) File "tests/simple.zcml", line 32.2-32.67 Clean up after ourselves: .. doctest:: >>> del file_registry[:] Creating nested directives ========================== When using ZCML, you sometimes nest ZCML directives. This is typically done either to: - Avoid repetative input. Information shared among multiple directives is provided in a surrounding directive. - Put together information that is too complex or structured to express with a single set of directive parameters. Grouping directives are used to handle both of these cases. See the documentation in :mod:`zope.configure.zopeconfigure`. This file describes the implementation of the zope ``configure`` directive, which groups directives that use a common package or internationalization domain. You should also have read the section on "Creating simple directives." This file shows you how to handle the second case above. In this case, we have grouping directives that are meant to collaborate with specific contained directives. To do this, you have the grouping directives declare a more specific (or alternate) interface to ``IConfigurationContext``. Directives designed to work with those grouping directives are registered for the new interface. Let's look at example. Suppose we wanted to be able to define schema using ZCML. We'd use a grouping directive to specify schemas and contained directives to specify fields within the schema. We'll use a schema registry to hold the defined schemas:: .. doctest:: >>> from zope.configuration.tests.nested import schema_registry A schema has a name, an id, some documentation, and some fields. We'll provide the name and the id as parameters. We'll define fields as subdirectives and documentation as text contained in the schema directive. The schema directive uses the schema, ``ISchemaInfo`` for it's parameters. .. doctest:: >>> from zope.configuration.tests.nested import ISchemaInfo We also define the schema, ISchema, that specifies an attribute that nested field directives will use to store the fields they define. .. doctest:: >>> from zope.configuration.tests.nested import ISchema The class, ``Schema``, provides the handler for the schema directive. (If you haven't read the documentation in ``zopeconfigure.py``, you need to do so now.) The constructor saves its arguments as attributes and initializes its ``fields`` attribute: .. doctest:: >>> from zope.configuration.tests.nested import Schema The ``after`` method of the ``Schema`` class creates a schema and computes an action to register the schema in the schema registry. The discriminator prevents two schema directives from registering the same schema. It's important to note that when we call the ``action`` method on ``self``, rather than on ``self.context``. This is because, in a grouping directive handler, the handler instance is itself a context. When we call the ``action`` method, the method stores additional meta data associated with the context it was called on. This meta data includes an include path, used when resolving conflicting actions, and an object that contains information about the XML source used to invole the directive. If we called the action method on ``self.context``, the wrong meta data would be associated with the configuration action. The file ``schema.zcml`` contains the meta-configuration directive that defines the schema directive. To define fields, we'll create directives to define the fields. Let's start with a ``text`` field. ``ITextField`` defines the schema for text field parameters. It extends ``IFieldInfo``, which defines data common to all fields. We also define a simple handler method, textField, that takes a context and keyword arguments. (For information on writing simple directives, see ``test_simple.py``.) We've abstracted most of the logic into the function ``field``. The ``field`` function computes a field instance using the constructor, and the keyword arguments passed to it. It also uses the context information object to get the text content of the directive, which it uses for the field description. After computing the field instance, it gets the ``Schema`` instance, which is the context of the context passed to the function. The function checks to see if there is already a field with that name. If there is, it raises an error. Otherwise, it saves the field. We also define an ``IIntInfo`` schema and ``intField`` handler function to support defining integer fields. We register the ``text`` and ``int`` directives in ``schema.zcml``. These are like the simple directive definition we saw in ``test_simple.py`` with an important exception. We provide a ``usedIn`` parameter to say that these directives can *only* ne used in a ``ISchema`` context. In other words, these can only be used inside of ``schema`` directives. The ``schema.zcml`` file also contains some sample ``schema`` directives. We can execute the file: .. doctest:: >>> from zope.configuration import tests >>> from zope.configuration.xmlconfig import file >>> context = file("schema.zcml", tests) And verify that the schema registery has the schemas we expect: .. doctest:: >>> pprint(sorted(schema_registry)) ['zope.configuration.tests.nested.I1', 'zope.configuration.tests.nested.I2'] >>> def sorted(x): ... r = list(x) ... r.sort() ... return r >>> i1 = schema_registry['zope.configuration.tests.nested.I1'] >>> sorted(i1) ['a', 'b'] >>> i1['a'].__class__.__name__ 'Text' >>> i1['a'].description.strip() u'A\n\n Blah blah' >>> i1['a'].min_length 1 >>> i1['b'].__class__.__name__ 'Int' >>> i1['b'].description.strip() u'B\n\n Not feeling very creative' >>> i1['b'].min 1 >>> i1['b'].max 10 >>> i2 = schema_registry['zope.configuration.tests.nested.I2'] >>> sorted(i2) ['x', 'y'] Now let's look at some error situations. For example, let's see what happens if we use a field directive outside of a schema dorective. (Note that we used the context we created above, so we don't have to redefine our directives: .. doctest:: >>> from zope.configuration.xmlconfig import string >>> from zope.configuration.xmlconfig import ZopeXMLConfigurationError >>> try: ... v = string( ... '', ... context) ... except ZopeXMLConfigurationError, v: ... pass >>> print v File "", line 1.0 ConfigurationError: The directive (u'http://sample.namespaces.zope.org/schema', u'text') cannot be used in this context Let's see what happens if we declare duplicate fields: .. doctest:: >>> try: ... v = string( ... ''' ... ... ... ... ... ''', ... context) ... except ZopeXMLConfigurationError, v: ... pass >>> print v File "", line 5.7-5.24 ValueError: ('Duplicate field', 'x') zope.configuration-4.0.3/docs/hacking.rst0000664000175000017500000002377712073042162020352 0ustar tseavertseaverHacking on :mod:`zope.configuration` ==================================== Getting the Code ----------------- The main repository for :mod:`zope.configuration` is in the Zope Subversion repository: http://svn.zope.org/zope.configuration You can get a read-only Subversion checkout from there: .. code-block:: sh $ svn checkout svn://svn.zope.org/repos/main/zope.configuration/trunk zope.configuration The project also mirrors the trunk from the Subversion repository as a Bazaar branch on Launchpad: https://code.launchpad.net/zope.configuration You can branch the trunk from there using Bazaar: .. code-block:: sh $ bzr branch lp:zope.configuration Running the tests in a ``virtualenv`` ------------------------------------- If you use the ``virtualenv`` package to create lightweight Python development environments, you can run the tests using nothing more than the ``python`` binary in a virtualenv. First, create a scratch environment: .. code-block:: sh $ /path/to/virtualenv --no-site-packages /tmp/hack-zope.configuration Next, get this package registered as a "development egg" in the environment: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/python setup.py develop Finally, run the tests using the build-in ``setuptools`` testrunner: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/python setup.py test running test ........ ---------------------------------------------------------------------- Ran 249 tests in 0.366s OK If you have the :mod:`nose` package installed in the virtualenv, you can use its testrunner too: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/easy_install nose ... $ /tmp/hack-zope.configuration/bin/python setup.py nosetests running nosetests ....... ---------------------------------------------------------------------- Ran 249 tests in 0.366s OK or: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/nosetests ....... ---------------------------------------------------------------------- Ran 249 tests in 0.366s OK If you have the :mod:`coverage` pacakge installed in the virtualenv, you can see how well the tests cover the code: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/easy_install nose coverage ... $ /tmp/hack-zope.configuration/bin/python setup.py nosetests \ --with coverage --cover-package=zope.configuration running nosetests ... Name Stmts Miss Cover Missing ---------------------------------------------------------------- zope.configuration 3 0 100% zope.configuration._compat 2 0 100% zope.configuration.config 439 0 100% zope.configuration.docutils 34 0 100% zope.configuration.exceptions 2 0 100% zope.configuration.fields 111 0 100% zope.configuration.interfaces 18 0 100% zope.configuration.name 54 0 100% zope.configuration.xmlconfig 269 0 100% zope.configuration.zopeconfigure 17 0 100% ---------------------------------------------------------------- TOTAL 955 0 100% ---------------------------------------------------------------------- Ran 256 tests in 1.063s OK Building the documentation in a ``virtualenv`` ---------------------------------------------- :mod:`zope.configuration` uses the nifty :mod:`Sphinx` documentation system for building its docs. Using the same virtualenv you set up to run the tests, you can build the docs: .. code-block:: sh $ /tmp/hack-zope.configuration/bin/easy_install Sphinx ... $ cd docs $ PATH=/tmp/hack-zope.configuration/bin:$PATH make html sphinx-build -b html -d _build/doctrees . _build/html ... build succeeded. Build finished. The HTML pages are in _build/html. You can also test the code snippets in the documentation: .. code-block:: sh $ PATH=/tmp/hack-zope.configuration/bin:$PATH make doctest sphinx-build -b doctest -d _build/doctrees . _build/doctest ... Doctest summary =============== 554 tests 0 failures in tests 0 failures in setup code build succeeded. Testing of doctests in the sources finished, look at the \ results in _build/doctest/output.txt. Running the tests using :mod:`zc.buildout` ------------------------------------------- :mod:`zope.configuration` ships with its own :file:`buildout.cfg` file and :file:`bootstrap.py` for setting up a development buildout: .. code-block:: sh $ /path/to/python2.6 bootstrap.py ... Generated script '.../bin/buildout' $ bin/buildout Develop: '/home/tseaver/projects/Zope/BTK/configuration/.' ... Generated script '.../bin/sphinx-quickstart'. Generated script '.../bin/sphinx-build'. You can now run the tests: .. code-block:: sh $ bin/test --all Running zope.testing.testrunner.layer.UnitTests tests: Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Ran 249 tests with 0 failures and 0 errors in 0.366 seconds. Tearing down left over layers: Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Building the documentation using :mod:`zc.buildout` --------------------------------------------------- The :mod:`zope.configuration` buildout installs the Sphinx scripts required to build the documentation, including testing its code snippets: .. code-block:: sh $ cd docs $ bin/sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest ... Doctest summary =============== 554 tests 0 failures in tests 0 failures in setup code build succeeded. Testing of doctests in the sources finished, look at the results in .../docs/_build/doctest/output.txt. .../bin/sphinx-build -b html -d .../docs/_build/doctrees .../docs .../docs/_build/html ... build succeeded. Running Tests on Multiple Python Versions via :mod:`tox` -------------------------------------------------------- `tox `_ is a Python-based test automation tool designed to run tests against multiple Python versions. It creates a ``virtualenv`` for each configured version, installs the current package and configured dependencies into each ``virtualenv``, and then runs the configured commands. :mod:`zope.configuration` configures the following :mod:`tox` environments via its ``tox.ini`` file: - The ``py26`` environment builds a ``virtualenv`` with ``python2.6``, installs :mod:`zope.configuration`, and runs the tests via ``python setup.py test -q``. - The ``py27`` environment builds a ``virtualenv`` with ``python2.7``, installs :mod:`zope.configuration`, and runs the tests via ``python setup.py test -q``. - The ``py32`` environment builds a ``virtualenv`` with ``python3.2``, installs :mod:`zope.configuration` and dependencies, and runs the tests via ``python setup.py test -q``. - The ``pypy`` environment builds a ``virtualenv`` with ``pypy``, installs :mod:`zope.configuration`, and runs the tests via ``python setup.py test -q``. - The ``coverage`` environment builds a ``virtualenv`` with ``python2.6``, installs :mod:`zope.configuration`, installs :mod:`nose` and :mod:`coverage`, and runs ``nosetests`` with statement coverage. - The ``docs`` environment builds a virtualenv with ``python2.6``, installs :mod:`zope.configuration`, installs ``Sphinx`` and dependencies, and then builds the docs and exercises the doctest snippets. This example requires that you have a working ``python2.6`` on your path, as well as installing ``tox``: .. code-block:: sh $ tox -e py26 GLOB sdist-make: .../zope.interface/setup.py py26 sdist-reinst: .../zope.interface/.tox/dist/zope.interface-4.0.2dev.zip py26 runtests: commands[0] .......... ---------------------------------------------------------------------- Ran 249 tests in 0.366s OK ___________________________________ summary ____________________________________ py26: commands succeeded congratulations :) Running ``tox`` with no arguments runs all the configured environments, including building the docs and testing their snippets: .. code-block:: sh $ tox GLOB sdist-make: .../zope.interface/setup.py py26 sdist-reinst: .../zope.interface/.tox/dist/zope.interface-4.0.2dev.zip py26 runtests: commands[0] ... Doctest summary =============== 544 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code build succeeded. ___________________________________ summary ____________________________________ py26: commands succeeded py27: commands succeeded py32: commands succeeded pypy: commands succeeded coverage: commands succeeded docs: commands succeeded congratulations :) Submitting a Bug Report ----------------------- :mod:`zope.configuration` tracks its bugs on Launchpad: https://bugs.launchpad.net/zope.configuration Please submit bug reports and feature requests there. Sharing Your Changes -------------------- .. note:: Please ensure that all tests are passing before you submit your code. If possible, your submission should include new tests for new features or bug fixes, although it is possible that you may have tested your new code by updating existing tests. If you got a read-only checkout from the Subversion repository, and you have made a change you would like to share, the best route is to let Subversion help you make a patch file: .. code-block:: sh $ svn diff > zope.configuration-cool_feature.patch You can then upload that patch file as an attachment to a Launchpad bug report. If you branched the code from Launchpad using Bazaar, you have another option: you can "push" your branch to Launchpad: .. code-block:: sh $ bzr push lp:~tseaver/zope.configuration/cool_feature After pushing your branch, you can link it to a bug report on Launchpad, or request that the maintainers merge your branch using the Launchpad "merge request" feature. zope.configuration-4.0.3/MANIFEST.in0000664000175000017500000000024212074062437017010 0ustar tseavertseaverinclude *.rst include *.txt recursive-include docs * recursive-include src * global-exclude *.dll global-exclude *.pyc global-exclude *.pyo global-exclude *.so