[Zope3-checkins] CVS: Zope3/src/zope/configuration/tests - backward.zcml:1.1 backwardkw.zcml:1.1 sample.zcml:1.1 test_backward.py:1.1 test_config.py:1.1 test_xmlconfig.py:1.1 directives.py:1.6 basetestdirectivesxml.py:NONE hooktestdummymodule.py:NONE test_directivesxml.py:NONE test_meta.py:NONE test_metameta.py:NONE test_metametafordocgen.py:NONE test_multiplexml.py:NONE test_names.py:NONE test_xml.py:NONE

Jim Fulton jim@zope.com
Mon, 28 Jul 2003 18:23:30 -0400


Update of /cvs-repository/Zope3/src/zope/configuration/tests
In directory cvs.zope.org:/tmp/cvs-serv30798/src/zope/configuration/tests

Modified Files:
	directives.py 
Added Files:
	backward.zcml backwardkw.zcml sample.zcml test_backward.py 
	test_config.py test_xmlconfig.py 
Removed Files:
	basetestdirectivesxml.py hooktestdummymodule.py 
	test_directivesxml.py test_meta.py test_metameta.py 
	test_metametafordocgen.py test_multiplexml.py test_names.py 
	test_xml.py 
Log Message:
Major refactoring of the configuration system.  Now use a totally new
architecture based on:

- Using schema to describe directive attributes

- Treating most configuration handlers as decorators of configuration
  contexts.

The benefits of this are:

- Conversion of directive input can be automated.

- Much better error reporting. We can now tell people
  what attributes are missing, are extra, or have invalid
  values.

- It's possible to extend existing directives without modifying them.
  Extending subdirectives can even be in different namespaces, if
  desired.

- There is a includeOverrides directive for including files that
  contain directives overriding directives in other files.

- It is possible to have many more sorts of "grouping" directives.
  This will allow things like directives that provide defaults for
  other directives and perhaps even some sort of macro system.

The basic refactoring is done, but there are a number of things to be
done:

- Write new documentation on how to write directives the new and
  better way.

- Update the documentation generation tool to use the new
  configuration framework.

- Add i18n support. This was the motivation for the refactoring. Now
  this is easy. :)


=== Added File Zope3/src/zope/configuration/tests/backward.zcml ===
<configure 
  xmlns="http://namespaces.zope.org/zope"
  xmlns:test="http://namespaces.zope.org/test"
  package="zope.configuration.tests.directives"
  >

  <directives namespace="http://namespaces.zope.org/test">
  
     <directive name="simple" attributes="a b c"
                handler=".simple" description="simple example" />
          
  
     <directive name="newsimple" handler=".newsimple">

        <attribute name="a" description="a descr" required="yes" />
        <attribute name="b">
            <description>b descr</description>
        </attribute>
        <attribute name="c" required="yes" >
            c descr
        </attribute>

     </directive>
  </directives>

  <test:simple a="aa" c="cc">first</test:simple>
  <test:newsimple a="naa" c="ncc" b="nbb">second</test:newsimple>

  <directives namespace="http://namespaces.zope.org/test">

     <directive name="testc" handler=".Complex">

        <attribute name="a" description="a descr" required="yes" />
        <attribute name="b">
            <description>b descr</description>
        </attribute>
        <attribute name="c" required="yes">
            c descr
        </attribute>

        <subdirective name="factory">
          <attribute name="factory" required="yes" />
        </subdirective>
     </directive>

  </directives>
    
  <test:testc a="ca" c="cc">
     Third
     <test:factory factory=".f">
        Fourth
     </test:factory>    
  </test:testc>

</configure>



=== Added File Zope3/src/zope/configuration/tests/backwardkw.zcml ===
<configure 
  xmlns="http://namespaces.zope.org/zope"
  xmlns:test="http://namespaces.zope.org/test"
  package="zope.configuration.tests.directives"
  >

  <directives namespace="http://namespaces.zope.org/test">
  
     <directive name="k" attributes="for class x"
                handler=".k" description="simple example w python keywords" />
          
  
     <directive name="k2" handler=".k">

        <attribute name="for" description="for descr" required="yes" />
        <attribute name="class">
            <description>class descr</description>
        </attribute>
        <attribute name="x" required="yes" >
            x descr
        </attribute>

     </directive>
  </directives>

  <test:k  for="f"  class="c"  x="x" >first</test:k>
  <test:k2 for="ff" class="cc" x="xx">second</test:k2>

</configure>



=== Added File Zope3/src/zope/configuration/tests/sample.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
  <!-- zope.configure -->
  <directives namespace="http://namespaces.zope.org/zope">
    <directive name="hook" attributes="name implementation module"
       handler="zope.configuration.metaconfigure.hook" />
  </directives>
</zopeConfigure>


=== Added File Zope3/src/zope/configuration/tests/test_backward.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""XXX short summary goes here.

$Id: test_backward.py,v 1.1 2003/07/28 22:22:47 jim Exp $
"""
import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.configuration import config, xmlconfig
from zope.configuration.tests.test_xmlconfig import clean_text_w_paths

def test_directive_and_integration():
    r"""

    To see if the backward compatability meta configurations are
    working, well evaluate a test zcml file and see if we get the
    expected actions:

    >>> from zope.configuration import tests
    >>> context = xmlconfig.file("backward.zcml", tests, execute=False)
    >>> for action in context.actions:
    ...   print action[:2]
    ...   print action[2]
    ...   print clean_text_w_paths(unicode(action[5]))
    ...   print action[5].text.strip()
    (('simple', u'aa', u'xxx', u'cc'), f)
    (u'aa', u'xxx', u'cc')
    File "tests/backward.zcml", line 26.2-26.34
       <test:simple a="aa" c="cc">first<
    first
    (('newsimple', u'naa', u'nbb', u'ncc'), f)
    (u'naa', u'nbb', u'ncc')
    File "tests/backward.zcml", line 27.2-27.48
       <test:newsimple a="naa" c="ncc" b="nbb">second<
    second
    ('Complex.__init__', None)
    ()
    File "tests/backward.zcml", line 48.2-55.0
       <test:testc a="ca" c="cc">
           Third
           <test:factory factory=".f">
              Fourth
           </test:factory>
        </test:testc>
    Third
    (('Complex.factory', 1, 2), u'.f')
    (u'ca',)
    File "tests/backward.zcml", line 50.5-52.5
       <test:factory factory=".f">
              Fourth
    Fourth
    (('Complex', 1, 2), f)
    (u'xxx', u'cc')
    File "tests/backward.zcml", line 48.2-55.0
       <test:testc a="ca" c="cc">
           Third
           <test:factory factory=".f">
              Fourth
           </test:factory>
        </test:testc>
    Third
    """

def test_directive_and_integration_w_python_keywords():
    r"""

    >>> from zope.configuration import tests
    >>> context = xmlconfig.file("backwardkw.zcml", tests, execute=False)
    >>> for action in context.actions:
    ...   print action[:2]
    ...   print action[2]
    ...   print clean_text_w_paths(unicode(action[5]))
    ...   print action[5].text.strip()
    (('k', u'f'), f)
    (u'f', u'c', u'x')
    File "tests/backwardkw.zcml", line 26.2-26.43
       <test:k  for="f"  class="c"  x="x" >first<
    first
    (('k', u'ff'), f)
    (u'ff', u'cc', u'xx')
    File "tests/backwardkw.zcml", line 27.2-27.44
       <test:k2 for="ff" class="cc" x="xx">second<
    second
    """

def test_suite():
    return unittest.TestSuite((
        DocTestSuite('zope.configuration.backward'),
        DocTestSuite(),
        ))

if __name__ == '__main__': unittest.main()


=== Added File Zope3/src/zope/configuration/tests/test_config.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""XXX short summary goes here.

$Id: test_config.py,v 1.1 2003/07/28 22:22:47 jim Exp $
"""

import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.configuration.config import metans, ConfigurationMachine

def test_config_extended_example():
    """Configuration machine

    Examples:

    >>> machine = ConfigurationMachine()
    >>> ns = "http://www.zope.org/testing"

    Register some test directives:

    Start 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",
    ...         )

    Now we can set the package:

    >>> machine.begin((ns, "package"),
    ...               package="zope.configuration.tests.directives",
    ...               )

    Which makes it easier to define the other directives:

    First, define some simple directives:

    >>> 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:

    >>> 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)
    [(('simple', u'aa', u'xxx', 'cc'),
      f,
      (u'aa', u'xxx', 'cc'),
      {},
      (),
      'first'),
     (('newsimple', u'naa', u'nbb', 'ncc'),
      f,
      (u'naa', u'nbb', 'ncc'),
      {},
      (),
      'second')]


    Define and try a simple directive that uses a component:

    >>> machine((metans, "directive"),
    ...         namespace=ns, name="factory",
    ...         schema=".IFactory", handler=".factory")


    >>> machine((ns, "factory"), factory=u".f")
    >>> pprint(machine.actions[-1:])
    [(('factory', 1, 2), f)]
    
    Define and try a complex directive:

    >>> 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:

    >>> machine((ns, "factory2"), factory=".f")
    Traceback (most recent call last):
    ...
    ConfigurationError: ('Invalid directive', 'factory2')


    >>> machine.end()
    >>> pprint(machine.actions)
    [(('simple', u'aa', u'xxx', 'cc'),
      f,
      (u'aa', u'xxx', 'cc'),
      {},
      (),
      'first'),
     (('newsimple', u'naa', u'nbb', 'ncc'),
      f,
      (u'naa', u'nbb', 'ncc'),
      {},
      (),
      'second'),
     (('factory', 1, 2), f),
     ('Complex.__init__', None, (), {}, (), 'third'),
     (('Complex.factory', 1, 2),
      f,
      (u'ca',),
      {},
      (),
      'fourth'),
     (('Complex', 1, 2),
      f,
      (u'xxx', 'cc'),
      {},
      (),
      'third')]

    Done with the package
    
    >>> machine.end()


    Verify that we can use a simple directive outside of the package:

    >>> 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:

    >>> 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)
    [(('simple', u'aa', u'xxx', 'cc'),
      f,
      (u'aa', u'xxx', 'cc'),
      {},
      (),
      'first'),
     (('newsimple', u'naa', u'nbb', 'ncc'),
      f,
      (u'naa', u'nbb', 'ncc'),
      {},
      (),
      'second'),
     (('factory', 1, 2), f),
     ('Complex.__init__', None, (), {}, (), 'third'),
     (('Complex.factory', 1, 2),
      f,
      (u'ca',),
      {},
      (),
      'fourth'),
     (('Complex', 1, 2),
      f,
      (u'xxx', 'cc'),
      {},
      (),
      'third'),
     (('simple', u'oaa', u'obb', 'occ'),
      f,
      (u'oaa', u'obb', 'occ'))]

    """
    #'

def test_kyeword_handling():
    """
    >>> machine = ConfigurationMachine()
    >>> ns = "http://www.zope.org/testing"

    Register some test directives:

    Start 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",
    ...         )

    Now we can 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"})

    >>> machine.actions
    [(('k', 'f'), f, ('f', 'c', 'x'), {}, (), 'yee ha')]
    """


def test_suite():
    return unittest.TestSuite((
        DocTestSuite('zope.configuration.fields'),
        DocTestSuite('zope.configuration.config'),
        DocTestSuite(),
        ))

if __name__ == '__main__': unittest.main()


=== Added File Zope3/src/zope/configuration/tests/test_xmlconfig.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""XXX short summary goes here.

$Id: test_xmlconfig.py,v 1.1 2003/07/28 22:22:47 jim Exp $
"""

import unittest
import os
from zope.testing.doctestunit import DocTestSuite
from zope.configuration import xmlconfig, config
from zope.configuration.tests.samplepackage import foo
from pprint import PrettyPrinter, pprint


class FauxLocator:
  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:
  
  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 path(*p):
    return os.path.join(os.path.split(__file__)[0], *p)

def test_ConfigurationHandler_normal():
    """
    >>> context = FauxContext()
    >>> locator = FauxLocator('tests//sample.zcml', 1, 1)
    >>> handler = xmlconfig.ConfigurationHandler(context)
    >>> handler.setDocumentLocator(locator)

    >>> handler.startElementNS((u"ns", u"foo"), u"foo",
    ...                        {(u"xxx", u"splat"): u"splatv",
    ...                         (None, u"a"): u"avalue",
    ...                         (None, u"b"): u"bvalue",
    ...                        })
    >>> context.info
    File "tests//sample.zcml", line 1.1
    >>> from pprint import PrettyPrinter
    >>> pprint=PrettyPrinter(width=50).pprint
    >>> pprint(context.begin_args)
    ((u'ns', u'foo'),
     {'a': u'avalue', 'b': u'bvalue'})
    >>> getattr(context, "end_called", 0)
    0

    >>> locator.line, locator.column = 7, 16
    >>> handler.endElementNS((u"ns", u"foo"), u"foo")
    >>> context.info
    File "tests//sample.zcml", line 1.1-7.16
    >>> context.end_called
    1
    
    """

def test_ConfigurationHandler_err_start():
    """

    >>> class FauxContext(FauxContext):
    ...   def begin(self, *args):
    ...     raise AttributeError("xxx")
    
    >>> context = FauxContext()
    >>> locator = FauxLocator('tests//sample.zcml', 1, 1)
    >>> handler = xmlconfig.ConfigurationHandler(context)
    >>> handler.setDocumentLocator(locator)

    >>> try:
    ...   v = handler.startElementNS((u"ns", u"foo"), u"foo",
    ...                              {(u"xxx", u"splat"): u"splatv",
    ...                               (None, u"a"): u"avalue",
    ...                               (None, u"b"): u"bvalue",
    ...                              })
    ... except xmlconfig.ZopeXMLConfigurationError, v:
    ...   pass
    >>> print v
    File "tests//sample.zcml", line 1.1
        AttributeError: xxx
    
    """

def test_ConfigurationHandler_err_end():
    """

    >>> class FauxContext(FauxContext):
    ...   def end(self):
    ...     raise AttributeError("xxx")

    >>> context = FauxContext()
    >>> locator = FauxLocator('tests//sample.zcml', 1, 1)
    >>> handler = xmlconfig.ConfigurationHandler(context)
    >>> handler.setDocumentLocator(locator)

    >>> handler.startElementNS((u"ns", u"foo"), u"foo",
    ...                        {(u"xxx", u"splat"): u"splatv",
    ...                         (None, u"a"): u"avalue",
    ...                         (None, u"b"): u"bvalue",
    ...                        })

    >>> locator.line, locator.column = 7, 16
    >>> try:
    ...   v = handler.endElementNS((u"ns", u"foo"), u"foo")
    ... except xmlconfig.ZopeXMLConfigurationError, v:
    ...   pass
    >>> print v
    File "tests//sample.zcml", line 1.1-7.16
        AttributeError: xxx
    
    """

def clean_info_path(s):
    part1 = s[:6]
    part2 = s[6:s.find('"', 6)]
    part2 = part2[part2.find("tests"):]
    part2 = part2.replace(os.sep, '/')
    part3 = s[s.find('"', 6):].rstrip()
    return part1+part2+part3

def clean_path(s):
    s = s[s.find("tests"):]
    s = s.replace(os.sep, '/')
    return s

def test_processxmlfile():
    """

    >>> file = open(path("samplepackage", "configure.zcml"))
    >>> context = config.ConfigurationMachine()
    >>> xmlconfig._registerIncludes(context)
    >>> xmlconfig.processxmlfile(file, context)

    >>> foo.data
    []

    >>> context.execute_actions()
    
    >>> data = foo.data.pop()

    >>> data.args
    (('x', 'blah'), ('y', 0))
    
    >>> print clean_info_path(`data.info`)
    File "tests/samplepackage/configure.zcml", line 12.2-12.29

    >>> print clean_info_path(str(data.info))
    File "tests/samplepackage/configure.zcml", line 12.2-12.29
       <test:foo x="blah" y="0" />

    >>> data.package
    >>> data.basepath
    """

def test_file():
    """

    >>> file_name = path("samplepackage", "configure.zcml")
    >>> context = xmlconfig.file(file_name)
    
    >>> data = foo.data.pop()

    >>> data.args
    (('x', 'blah'), ('y', 0))
    
    >>> print clean_info_path(`data.info`)
    File "tests/samplepackage/configure.zcml", line 12.2-12.29

    >>> print clean_info_path(str(data.info))
    File "tests/samplepackage/configure.zcml", line 12.2-12.29
       <test:foo x="blah" y="0" />

    >>> data.package
    >>> print clean_path(data.basepath)
    tests/samplepackage
    """

def test_include_by_package():
    """
    >>> context = config.ConfigurationMachine()
    >>> xmlconfig._registerIncludes(context)
    >>> import zope.configuration.tests.samplepackage as package
    >>> xmlconfig.include(context, 'configure.zcml', package)
    >>> context.execute_actions()
    
    >>> data = foo.data.pop()

    >>> data.args
    (('x', 'blah'), ('y', 0))
    
    >>> print clean_info_path(`data.info`)
    File "tests/samplepackage/configure.zcml", line 12.2-12.29

    >>> print clean_info_path(str(data.info))
    File "tests/samplepackage/configure.zcml", line 12.2-12.29
       <test:foo x="blah" y="0" />

    >>> data.package is package
    1
    
    >>> data.basepath[-13:]
    'samplepackage'

    >>> [clean_path(p) for p in data.includepath]
    ['tests/samplepackage/configure.zcml']

    """

def test_include_by_file():
    """
    >>> context = config.ConfigurationMachine()
    >>> xmlconfig._registerIncludes(context)
    >>> here = os.path.split(__file__)[0]
    >>> path = os.path.join(here, "samplepackage", "foo.zcml")
    >>> xmlconfig.include(context, path)
    >>> context.execute_actions()
    
    >>> data = foo.data.pop()

    >>> data.args
    (('x', 'foo'), ('y', 2))
    
    >>> print clean_info_path(`data.info`)
    File "tests/samplepackage/foo.zcml.in", line 12.2-12.28

    >>> print clean_info_path(str(data.info))
    File "tests/samplepackage/foo.zcml.in", line 12.2-12.28
       <test:foo x="foo" y="2" />

    >>> data.package
    
    >>> data.basepath[-13:]
    'samplepackage'

    >>> [clean_path(p) for p in data.includepath]
    ['tests/samplepackage/foo.zcml.in']
    """

def clean_actions(actions):
    return [
      {'discriminator': discriminator,
       'info': clean_info_path(`info`),
       'includepath': [clean_path(p) for p in includepath],
       }
      for (discriminator, callable, args, kw, includepath, info)
      in actions]

def clean_text_w_paths(error):
    r = []
    for line in 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 test_includeOverrides():
    """
    When we have conflicting directives, we can resolve them if oe of
    the conflicting directives was from a file that included all of
    tyhe 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. It includes bar1.zcml and bar2.zcml.
    bar2.zcml includes configure.zcml and has a foo
    directive. bar2.zcml includes bar21.zcml.  bar2.zcml 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.

    >>> context = config.ConfigurationMachine()
    >>> xmlconfig._registerIncludes(context)
    
    >>> here = os.path.split(__file__)[0]
    >>> path = os.path.join(here, "samplepackage", "bar.zcml")
    >>> xmlconfig.include(context, path)

    So far so good, let's look at the configuration 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:

    >>> try:
    ...    v = context.execute_actions()
    ... except config.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
           <test:foo x="blah" y="0" />
        File "tests/samplepackage/bar21.zcml", line 3.2-3.24
           <foo x="blah" y="0" />
      For: (('x', 'blah'), ('y', 1))
        File "tests/samplepackage/bar1.zcml", line 5.2-5.24
           <foo x="blah" y="1" />
        File "tests/samplepackage/bar2.zcml", line 6.2-6.24
           <foo x="blah" y="1" />

    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.

    >>> context = config.ConfigurationMachine()
    >>> xmlconfig._registerIncludes(context)
    >>> path = os.path.join(here, "samplepackage", "baro.zcml")
    >>> xmlconfig.include(context, path)

    Now, if we look at the actions:
    
    >>> 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 resolves, 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:

    >>> context.execute_actions()

    We should now have three entries in foo.data:

    >>> 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

    """

def test_XMLConfig():
    """Test processing a configuration file.

    We'll use the same example from test_includeOverrides:

    >>> here = os.path.split(__file__)[0]
    >>> path = os.path.join(here, "samplepackage", "baro.zcml")

    First, process the configuration file:
    
    >>> x = xmlconfig.XMLConfig(path)

    Second, call the resulting object to process the actions:

    >>> x()

    And verify the data as above:

    >>> 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
    
    """

def test_XMLConfig_w_module():
    """Test processing a configuration file for a module.

    We'll use the same example from test_includeOverrides:

    >>> import zope.configuration.tests.samplepackage as module

    First, process the configuration file:
    
    >>> x = xmlconfig.XMLConfig("baro.zcml", module)

    Second, call the resulting object to process the actions:

    >>> x()

    And verify the data as above:

    >>> 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
    
    """
    


def test_suite():
    return unittest.TestSuite((
        DocTestSuite('zope.configuration.xmlconfig'),
        DocTestSuite(),
        ))

if __name__ == '__main__': unittest.main()


=== Zope3/src/zope/configuration/tests/directives.py 1.5 => 1.6 ===
--- Zope3/src/zope/configuration/tests/directives.py:1.5	Wed Jun  4 06:22:20 2003
+++ Zope3/src/zope/configuration/tests/directives.py	Mon Jul 28 18:22:47 2003
@@ -11,74 +11,78 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""
-Test class for use by test modules
+"""Test directives
 
 $Id$
 """
 
-from zope.interface import directlyProvides, classProvides, implements
-from zope.configuration.interfaces import INonEmptyDirective
-from zope.configuration.interfaces import ISubdirectiveHandler
+from zope.interface import Interface, implements
+from zope.schema import Text, BytesLine
+from zope.configuration.config import GroupingContextDecorator
+from zope.configuration.interfaces import IConfigurationContext
+from zope.configuration.fields import GlobalObject
+
+
+class F:
+    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))
+
 
-protections=[]
+class IPackaged(Interface):
 
-count = 0
+    package = GlobalObject()
 
-def _increment():
-    global count
-    count += 1
+class IPackagedContext(IPackaged, IConfigurationContext):
+    pass
 
-def increment(_context):
-    return [(None, _increment, (), )]
+class Packaged(GroupingContextDecorator):
 
-class protectClass:
+    implements(IPackagedContext)
 
-    classProvides(INonEmptyDirective)
-    implements(ISubdirectiveHandler)
 
-    def __init__(self, _context, name, permission=None, names=None):
-        self._name=name
-        self._permission=permission
-        self._names=names
-        self._children=[]
-        self.__context = _context
+class IFactory(Interface):
+
+    factory = GlobalObject()
+
+def factory(context, factory):
+    context.action(('factory', 1,2), factory)
+
+class Complex:
+
+    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):
-        if not self._children:
-            p = self._name, self._permission, self._names
-            d = self._name, self._names
-            return [(d, protections.append, (p,))]
-        else:
-            return ()
-
-    def protect(self, _context, permission=None, names=None):
-        if permission is None: permission=self._permission
-        if permission is None: raise 'no perm'
-        p=self._name, permission, names
-        d=self._name, names
-        self._children.append(p)
-        return [(d, protections.append, (p,))]
-
-    def subsub(self, _context):
-        #Dummy subdirective-with-subdirectives.  Define this and you
-        #can define 'protect' subdirectives within it.  This lets
-        #us excercise the subdirectives-of-subdirectives code.
-        #If you put a protect inside a subsub, that'll set children,
-        #so when the parser calls us, __call__ will return ().
-        return self
-    directlyProvides(subsub, INonEmptyDirective)
-
-done = []
-
-def doit(_context, name):
-    return [('d', done.append, (name,))]
-
-def clearDirectives():
-    del protections[:]
-    del done[:]
-
-# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
-from zope.testing.cleanup import addCleanUp
-addCleanUp(clearDirectives)
-del addCleanUp
+        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))

=== Removed File Zope3/src/zope/configuration/tests/basetestdirectivesxml.py ===

=== Removed File Zope3/src/zope/configuration/tests/hooktestdummymodule.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_directivesxml.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_meta.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_metameta.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_metametafordocgen.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_multiplexml.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_names.py ===

=== Removed File Zope3/src/zope/configuration/tests/test_xml.py ===