[Checkins] SVN: zope.security/trunk/ Moved the <class> directive implementation from `zope.app.component` to

Brandon Rhodes brandon at rhodesmill.org
Wed Jan 28 10:11:50 EST 2009


Log message for revision 95326:
  Moved the <class> directive implementation from `zope.app.component` to
  this package.
  

Changed:
  U   zope.security/trunk/CHANGES.txt
  A   zope.security/trunk/src/zope/security/i18n.py
  U   zope.security/trunk/src/zope/security/interfaces.py
  U   zope.security/trunk/src/zope/security/meta.zcml
  A   zope.security/trunk/src/zope/security/metaconfigure.py
  A   zope.security/trunk/src/zope/security/metadirectives.py
  A   zope.security/trunk/src/zope/security/tests/adapter.py
  A   zope.security/trunk/src/zope/security/tests/components.py
  A   zope.security/trunk/src/zope/security/tests/emptymodule.py
  A   zope.security/trunk/src/zope/security/tests/exampleclass.py
  D   zope.security/trunk/src/zope/security/tests/module.py
  A   zope.security/trunk/src/zope/security/tests/module.py
  U   zope.security/trunk/src/zope/security/tests/modulehookup.py
  A   zope.security/trunk/src/zope/security/tests/test_contentdirective.py
  A   zope.security/trunk/src/zope/security/tests/test_directives.py

-=-
Modified: zope.security/trunk/CHANGES.txt
===================================================================
--- zope.security/trunk/CHANGES.txt	2009-01-28 14:59:33 UTC (rev 95325)
+++ zope.security/trunk/CHANGES.txt	2009-01-28 15:11:49 UTC (rev 95326)
@@ -7,10 +7,13 @@
 
 - Added support to bootstrap on Jython.
 
-- Moved the `protectclass` module from `zope.app.security` to reduce the
-  number of dependencies on `zope.app.security`.
+- Moved the `protectclass` module from `zope.app.security` to this
+  package to reduce the number of dependencies on `zope.app.security`.
 
+- Moved the <class> directive implementation from `zope.app.component`
+  to this package.
 
+
 3.5.2 - 2008-07-27
 ------------------
 
@@ -18,14 +21,14 @@
 
 
 3.5.1 - 2008-06-04
--------------------
+------------------
 
 - Add `frozenset`, `set`, `reversed`, and `sorted` to the list of safe
   builtins.
 
 
 3.5.0 - 2008-03-05
--------------------
+------------------
 
 - Changed title for ``zope.security.management.system_user`` to be more
   presentable.

Copied: zope.security/trunk/src/zope/security/i18n.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/i18n.py)
===================================================================
--- zope.security/trunk/src/zope/security/i18n.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/i18n.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Customization of zope.i18n for the Zope application server
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+# import this as _ to create i18n messages in the zope domain
+from zope.i18nmessageid import MessageFactory
+ZopeMessageFactory = MessageFactory('zope')


Property changes on: zope.security/trunk/src/zope/security/i18n.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Modified: zope.security/trunk/src/zope/security/interfaces.py
===================================================================
--- zope.security/trunk/src/zope/security/interfaces.py	2009-01-28 14:59:33 UTC (rev 95325)
+++ zope.security/trunk/src/zope/security/interfaces.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -19,8 +19,7 @@
 from zope.interface import Interface, Attribute, implements
 from zope.interface.common.interfaces import IException, IAttributeError
 from zope.schema import Text, TextLine
-from zope.i18nmessageid import MessageFactory
-_ = MessageFactory('zope')
+from zope.security.i18n import ZopeMessageFactory as _
 
 class IUnauthorized(IException):
     pass

Modified: zope.security/trunk/src/zope/security/meta.zcml
===================================================================
--- zope.security/trunk/src/zope/security/meta.zcml	2009-01-28 14:59:33 UTC (rev 95325)
+++ zope.security/trunk/src/zope/security/meta.zcml	2009-01-28 15:11:49 UTC (rev 95326)
@@ -21,4 +21,34 @@
       schema=".zcml.IRedefinePermission"
       handler=".zcml.redefinePermission" />
 
+  <meta:directives namespace="http://namespaces.zope.org/zope">
+
+    <meta:complexDirective
+        name="class"
+        schema=".metadirectives.IClassDirective"
+        handler=".metaconfigure.ClassDirective"
+        >
+
+      <meta:subdirective
+          name="implements"
+          schema=".metadirectives.IImplementsSubdirective"
+          />
+
+      <meta:subdirective
+          name="require"
+          schema=".metadirectives.IRequireSubdirective"
+          />
+
+      <meta:subdirective
+          name="allow"
+          schema=".metadirectives.IAllowSubdirective"
+          />
+
+      <meta:subdirective
+          name="factory"
+          schema=".metadirectives.IFactorySubdirective"
+          />
+
+    </meta:complexDirective>
+  </meta:directives>
 </configure>

Copied: zope.security/trunk/src/zope/security/metaconfigure.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/contentdirective.py)
===================================================================
--- zope.security/trunk/src/zope/security/metaconfigure.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/metaconfigure.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,172 @@
+#############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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.
+#
+##############################################################################
+""" Register class directive.
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from types import ModuleType
+
+from zope.component.interfaces import IFactory
+from zope.component.factory import Factory
+from zope.component.interface import provideInterface
+from zope.component.zcml import utility
+from zope.interface import classImplements
+from zope.schema.interfaces import IField
+from zope.configuration.exceptions import ConfigurationError
+
+from zope.security.protectclass import protectLikeUnto, protectName
+from zope.security.protectclass import protectSetAttribute
+
+PublicPermission = 'zope.Public'
+
+def dottedName(klass):
+    if klass is None:
+        return 'None'
+    return klass.__module__ + '.' + klass.__name__
+
+class ProtectionDeclarationException(Exception):
+    """Security-protection-specific exceptions."""
+    pass
+
+class ClassDirective(object):
+
+    def __init__(self, _context, class_):
+        self.__id = dottedName(class_)
+        self.__class = class_
+        if isinstance(self.__class, ModuleType):
+            raise ConfigurationError('Content class attribute must be a class')
+        self.__context = _context
+
+    def implements(self, _context, interface):
+        for interface in interface:
+            _context.action(
+                discriminator = (
+                'ContentDirective', self.__class, object()),
+                callable = classImplements,
+                args = (self.__class, interface),
+                )
+            _context.action(
+                discriminator = None,
+                callable = provideInterface,
+                args = (interface.__module__ + '.' + interface.getName(),
+                        interface)
+                )
+
+    def require(self, _context,
+                permission=None, attributes=None, interface=None,
+                like_class=None, set_attributes=None, set_schema=None):
+        """Require a permission to access a specific aspect"""
+        if like_class:
+            self.__mimic(_context, like_class)
+
+        if not (interface or attributes or set_attributes or set_schema):
+            if like_class:
+                return
+            raise ConfigurationError("Nothing required")
+
+        if not permission:
+            raise ConfigurationError("No permission specified")
+
+        if interface:
+            for i in interface:
+                if i:
+                    self.__protectByInterface(i, permission)
+        if attributes:
+            self.__protectNames(attributes, permission)
+        if set_attributes:
+            self.__protectSetAttributes(set_attributes, permission)
+        if set_schema:
+            for s in set_schema:
+                self.__protectSetSchema(s, permission)
+
+    def __mimic(self, _context, class_):
+        """Base security requirements on those of the given class"""
+        _context.action(
+            discriminator=('mimic', self.__class, object()),
+            callable=protectLikeUnto,
+            args=(self.__class, class_),
+            )
+
+    def allow(self, _context, attributes=None, interface=None):
+        """Like require, but with permission_id zope.Public"""
+        return self.require(_context, PublicPermission, attributes, interface)
+
+    def __protectByInterface(self, interface, permission_id):
+        "Set a permission on names in an interface."
+        for n, d in interface.namesAndDescriptions(1):
+            self.__protectName(n, permission_id)
+        self.__context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = (interface.__module__ + '.' + interface.getName(),
+                    interface)
+            )
+
+    def __protectName(self, name, permission_id):
+        "Set a permission on a particular name."
+        self.__context.action(
+            discriminator = ('protectName', self.__class, name),
+            callable = protectName,
+            args = (self.__class, name, permission_id)
+            )
+
+    def __protectNames(self, names, permission_id):
+        "Set a permission on a bunch of names."
+        for name in names:
+            self.__protectName(name, permission_id)
+
+    def __protectSetAttributes(self, names, permission_id):
+        "Set a permission on a bunch of names."
+        for name in names:
+            self.__context.action(
+                discriminator = ('protectSetAttribute', self.__class, name),
+                callable = protectSetAttribute,
+                args = (self.__class, name, permission_id)
+                )
+
+    def __protectSetSchema(self, schema, permission_id):
+        "Set a permission on a bunch of names."
+        _context = self.__context
+        for name in schema:
+            field = schema[name]
+            if IField.providedBy(field) and not field.readonly:
+                _context.action(
+                    discriminator = ('protectSetAttribute', self.__class, name),
+                    callable = protectSetAttribute,
+                    args = (self.__class, name, permission_id)
+                    )
+        _context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = (schema.__module__ + '.' + schema.getName(),
+                    schema)
+            )
+
+    def __call__(self):
+        "Handle empty/simple declaration."
+        return ()
+
+    def factory(self, _context, id=None, title="", description=''):
+        """Register a zmi factory for this class"""
+
+        id = id or self.__id
+        factoryObj = Factory(self.__class, title, description)
+
+        # note factories are all in one pile, utilities and content,
+        # so addable names must also act as if they were all in the
+        # same namespace, despite the utilities/content division
+        utility(_context, IFactory, factoryObj,
+                permission=PublicPermission, name=id)


Property changes on: zope.security/trunk/src/zope/security/metaconfigure.py
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.17
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/metadirectives.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/metadirectives.py)
===================================================================
--- zope.security/trunk/src/zope/security/metadirectives.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/metadirectives.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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.
+#
+##############################################################################
+"""Component architecture related 'zope' ZCML namespace directive interfaces
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.configuration.fields
+import zope.interface
+import zope.schema
+
+import zope.security.zcml
+from zope.security.i18n import ZopeMessageFactory as _
+
+class IClassDirective(zope.interface.Interface):
+    """Make statements about a class"""
+
+    class_ = zope.configuration.fields.GlobalObject(
+        title=_("Class"),
+        required=True
+        )
+
+class IImplementsSubdirective(zope.interface.Interface):
+    """Declare that the class given by the content directive's class
+    attribute implements a given interface
+    """
+
+    interface = zope.configuration.fields.Tokens(
+        title=_("One or more interfaces"),
+        required=True,
+        value_type=zope.configuration.fields.GlobalInterface()
+        )
+
+class IRequireSubdirective(zope.interface.Interface):
+    """Indicate that the a specified list of names or the names in a
+    given Interface require a given permission for access.
+    """
+
+    permission = zope.security.zcml.Permission(
+        title=_("Permission"),
+        description=_("""
+        Specifies the permission by id that will be required to
+        access or mutate the attributes and methods specified."""),
+        required=False,
+        )
+
+    attributes = zope.configuration.fields.Tokens(
+        title=_("Attributes and methods"),
+        description=_("This is a list of attributes and methods"
+                      " that can be accessed."),
+        required=False,
+        value_type=zope.configuration.fields.PythonIdentifier(),
+        )
+
+    set_attributes = zope.configuration.fields.Tokens(
+        title=_("Attributes that can be set"),
+        description=_("This is a list of attributes that can be"
+                      " modified/mutated."),
+        required=False,
+        value_type=zope.configuration.fields.PythonIdentifier(),
+        )
+
+    interface = zope.configuration.fields.Tokens(
+        title=_("Interfaces"),
+        description=_("The listed interfaces' methods and attributes"
+                      " can be accessed."),
+        required=False,
+        value_type=zope.configuration.fields.GlobalInterface(),
+        )
+
+    set_schema = zope.configuration.fields.Tokens(
+        title=_("The attributes specified by the schema can be set"),
+        description=_("The listed schemas' properties can be"
+                      " modified/mutated."),
+        required=False,
+        value_type=zope.configuration.fields.GlobalInterface(),
+        )
+
+    like_class = zope.configuration.fields.GlobalObject(
+        title=_("Configure like this class"),
+        description=_("""
+        This argument says that this content class should be configured in the
+        same way the specified class' security is. If this argument is
+        specified, no other argument can be used."""),
+        required=False,
+        )
+
+class IAllowSubdirective(zope.interface.Interface):
+    """
+    Declare a part of the class to be publicly viewable (that is,
+    requires the zope.Public permission). Only one of the following
+    two attributes may be used.
+    """
+
+    attributes = zope.configuration.fields.Tokens(
+        title=_("Attributes"),
+        required=False,
+        value_type=zope.configuration.fields.PythonIdentifier(),
+        )
+
+    interface = zope.configuration.fields.Tokens(
+        title=_("Interface"),
+        required=False,
+        value_type=zope.configuration.fields.GlobalInterface(),
+        )
+
+class IFactorySubdirective(zope.interface.Interface):
+    """Specify the factory used to create this content object"""
+
+    id = zope.schema.Id(
+        title=_("ID"),
+        description=_("""
+        the identifier for this factory in the ZMI factory
+        identification scheme.  If not given, defaults to the literal
+        string given as the content directive's 'class' attribute."""),
+        required=False,
+        )
+
+    title = zope.configuration.fields.MessageID(
+        title=_("Title"),
+        description=_("Text suitable for use in the 'add content' menu"
+                      " of a management interface"),
+        required=False,
+        )
+
+    description = zope.configuration.fields.MessageID(
+        title=_("Description"),
+        description=_("Longer narrative description of what this"
+                      " factory does"),
+        required=False,
+        )


Property changes on: zope.security/trunk/src/zope/security/metadirectives.py
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.18
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/tests/adapter.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/adapter.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/adapter.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/adapter.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Sample adapter class for testing
+
+$Id$
+"""
+import zope.interface
+import zope.component
+import components
+
+class I1(zope.interface.Interface):
+    pass
+
+class I2(zope.interface.Interface):
+    pass
+
+class I3(zope.interface.Interface):
+    def f1(): pass
+    def f2(): pass
+    def f3(): pass
+
+class IS(zope.interface.Interface):
+    pass
+
+
+class Adapter(object):
+    def __init__(self, *args):
+        self.context = args
+
+class A1(Adapter):
+    zope.interface.implements(I1)
+
+class A2(Adapter):
+    zope.interface.implements(I2)
+
+class A3(Adapter):
+    zope.component.adapts(components.IContent, I1, I2)
+    zope.interface.implements(I3)
+
+class A4:
+    pass
+
+a4 = A4()
+
+class A5:
+    zope.interface.implements(I1, I2)
+
+a5 = A5()
+
+def Handler(content, *args):
+    # uninteresting handler
+    content.args = getattr(content, 'args', ()) + (args, )


Property changes on: zope.security/trunk/src/zope/security/tests/adapter.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/tests/components.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/components.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/components.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/components.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Components for testing
+
+$Id$
+"""
+from zope.interface import Interface, Attribute, implements
+from zope.component import adapts
+
+class IAppb(Interface):
+    a = Attribute('test attribute')
+    def f(): "test func"
+
+class IApp(IAppb):
+    pass
+
+class IContent(Interface): pass
+
+class Content(object):
+    implements(IContent)
+
+class Comp(object):
+    adapts(IContent)
+    implements(IApp)
+
+    def __init__(self, *args):
+        # Ignore arguments passed to constructor
+        pass
+
+    a = 1
+    def f(): pass
+
+comp = Comp()


Property changes on: zope.security/trunk/src/zope/security/tests/components.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/tests/emptymodule.py (from rev 95308, zope.security/trunk/src/zope/security/tests/module.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/emptymodule.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/emptymodule.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,20 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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 empty module is for containing objects used in the course of tests.
+
+(There is a problem with the way the unit tests interact with the modules
+being tests, so the objects can't be expected to show up in place.)
+
+$Id$
+"""

Copied: zope.security/trunk/src/zope/security/tests/exampleclass.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/exampleclass.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/exampleclass.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/exampleclass.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Example test classes
+
+$Id$
+"""
+from zope.interface import Interface
+
+class ExampleClass(object):
+    pass
+
+class IExample(Interface):
+    pass
+
+class IExample2(Interface):
+    pass
+
+class IExampleContainer(Interface):
+    pass


Property changes on: zope.security/trunk/src/zope/security/tests/exampleclass.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Deleted: zope.security/trunk/src/zope/security/tests/module.py
===================================================================
--- zope.security/trunk/src/zope/security/tests/module.py	2009-01-28 14:59:33 UTC (rev 95325)
+++ zope.security/trunk/src/zope/security/tests/module.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -1,20 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.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 empty module is for containing objects used in the course of tests.
-
-(There is a problem with the way the unit tests interact with the modules
-being tests, so the objects can't be expected to show up in place.)
-
-$Id$
-"""

Copied: zope.security/trunk/src/zope/security/tests/module.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/module.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/module.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/module.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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.
+#
+##############################################################################
+"""Preliminaries to hookup a test suite with the external TestModule.
+
+This is necessary because the test framework interferes with seeing changes in
+the running modules via the module namespace.  This enables having some
+subject classes, instances, permissions, etc, that don't live in the test
+modules, themselves.
+
+$Id$
+"""
+from zope.interface import Interface
+from zope.schema import Text
+
+class I(Interface):
+    def m1():
+        pass
+    def m2():
+        pass
+
+class I2(I):
+    def m4():
+        pass
+
+class I3(Interface):
+    def m3():
+        pass
+
+class I4(Interface):
+    def m2():
+        pass
+
+
+class S(Interface):
+    foo = Text()
+    bar = Text()
+    baro = Text(readonly=True)
+
+class S2(Interface):
+    foo2 = Text()
+    bar2 = Text()
+
+
+template_bracket = """<configure
+   xmlns="http://namespaces.zope.org/zope">
+   %s
+</configure>"""


Property changes on: zope.security/trunk/src/zope/security/tests/module.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Modified: zope.security/trunk/src/zope/security/tests/modulehookup.py
===================================================================
--- zope.security/trunk/src/zope/security/tests/modulehookup.py	2009-01-28 14:59:33 UTC (rev 95325)
+++ zope.security/trunk/src/zope/security/tests/modulehookup.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -22,7 +22,7 @@
 """
 from zope.interface import Interface
 
-from zope.security.tests import module as TestModule
+from zope.security.tests import emptymodule as TestModule
 
 class I(Interface):
     def m1():

Copied: zope.security/trunk/src/zope/security/tests/test_contentdirective.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/test_contentdirective.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/test_contentdirective.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/test_contentdirective.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,203 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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:class' directive.
+
+$Id$
+"""
+import unittest
+from StringIO import StringIO
+
+from zope.component.interfaces import IFactory
+from zope.component.interfaces import ComponentLookupError
+from zope.component.interface import queryInterface
+from zope.configuration.xmlconfig import xmlconfig, XMLConfig
+
+import zope.component
+import zope.security
+from zope.component.testing import PlacelessSetup
+
+# explicitly import ExampleClass and IExample using full paths
+# so that they are the same objects as resolve will get.
+from zope.security.tests.exampleclass import ExampleClass
+from zope.security.tests.exampleclass import IExample, IExample2
+
+
+class ParticipationStub(object):
+
+    def __init__(self, principal):
+        self.principal = principal
+        self.interaction = None
+
+
+def configfile(s):
+    return StringIO("""<configure
+      xmlns='http://namespaces.zope.org/zope'
+      i18n_domain='zope'>
+      %s
+      </configure>
+      """ % s)
+
+class TestClassDirective(PlacelessSetup, unittest.TestCase):
+    def setUp(self):
+        super(TestClassDirective, self).setUp()
+        XMLConfig('meta.zcml', zope.security)()
+
+        try:
+            del ExampleClass.__implements__
+        except AttributeError:
+            pass
+
+    def testEmptyDirective(self):
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+</class>
+                       """)
+        xmlconfig(f)
+
+
+    def testImplements(self):
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample"), None)
+
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+  <implements interface="zope.security.tests.exampleclass.IExample" />
+</class>
+                       """)
+        xmlconfig(f)
+        self.failUnless(IExample.implementedBy(ExampleClass))
+
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample"), IExample)
+
+
+    def testMulImplements(self):
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample"), None)
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample2"), None)
+
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+  <implements interface="
+           zope.security.tests.exampleclass.IExample
+           zope.security.tests.exampleclass.IExample2
+                       " />
+</class>
+                       """)
+        xmlconfig(f)
+        self.failUnless(IExample.implementedBy(ExampleClass))
+        self.failUnless(IExample2.implementedBy(ExampleClass))
+
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample"), IExample)
+        self.assertEqual(queryInterface(
+            "zope.security.tests.exampleclass.IExample2"),
+                         IExample2)
+
+    def testRequire(self):
+        f = configfile("""
+<permission id="zope.View" title="Zope view permission" />
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <require permission="zope.View"
+                      attributes="anAttribute anotherAttribute" />
+</class>
+                       """)
+        xmlconfig(f)
+
+    def testAllow(self):
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <allow attributes="anAttribute anotherAttribute" />
+</class>
+                       """)
+        xmlconfig(f)
+
+    def testMimic(self):
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <require like_class="zope.security.tests.exampleclass.ExampleClass" />
+</class>
+                       """)
+        xmlconfig(f)
+
+
+class TestFactorySubdirective(PlacelessSetup, unittest.TestCase):
+    def setUp(self):
+        super(TestFactorySubdirective, self).setUp()
+        XMLConfig('meta.zcml', zope.security)()
+
+    def testFactory(self):
+        f = configfile("""
+<permission id="zope.Foo" title="Zope Foo Permission" />
+
+<class class="zope.security.tests.exampleclass.ExampleClass">
+  <factory
+      id="test.Example"
+      title="Example content"
+      description="Example description"
+      />
+</class>
+                       """)
+        xmlconfig(f)
+        factory = zope.component.getUtility(IFactory, 'test.Example')
+        self.assertEquals(factory.title, "Example content")
+        self.assertEquals(factory.description, "Example description")
+
+    def testFactoryNoId(self):
+        f = configfile("""
+<permission id="zope.Foo" title="Zope Foo Permission" />
+
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <factory
+      title="Example content"
+      description="Example description"
+    />
+</class>
+                       """)
+        xmlconfig(f)
+        self.assertRaises(ComponentLookupError, zope.component.getUtility,
+                          IFactory, 'Example')
+        factory = zope.component.getUtility(
+            IFactory, 'zope.security.tests.exampleclass.ExampleClass')
+        self.assertEquals(factory.title, "Example content")
+        self.assertEquals(factory.description, "Example description")
+
+
+    def testFactoryPublicPermission(self):
+
+        f = configfile("""
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <factory
+      id="test.Example"
+      title="Example content"
+      description="Example description"
+    />
+</class>
+            """)
+        xmlconfig(f)
+        factory = zope.component.getUtility(IFactory, 'test.Example')
+        self.assert_(hasattr(factory, '__Security_checker__'))
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestClassDirective))
+    suite.addTest(loader.loadTestsFromTestCase(TestFactorySubdirective))
+    return suite
+
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


Property changes on: zope.security/trunk/src/zope/security/tests/test_contentdirective.py
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.16
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/tests/test_directives.py (from rev 95313, zope.app.component/trunk/src/zope/app/component/tests/test_directives.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/test_directives.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/test_directives.py	2009-01-28 15:11:49 UTC (rev 95326)
@@ -0,0 +1,375 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.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.
+#
+##############################################################################
+"""Component Directives Tests
+
+$Id$
+"""
+import re
+import unittest
+import pprint
+from cStringIO import StringIO
+
+import zope.component
+from zope.interface import implements
+from zope.testing.doctestunit import DocTestSuite
+from zope.component.interface import queryInterface
+
+from zope.configuration.xmlconfig import xmlconfig, XMLConfig
+from zope.configuration.xmlconfig import ZopeXMLConfigurationError
+from zope.security.checker import selectChecker
+from zope.security import proxy
+
+import zope.security
+from zope.component.testing import PlacelessSetup
+
+from zope.security.tests import module, exampleclass
+
+# TODO: tests for other directives needed
+
+atre = re.compile(' at [0-9a-fA-Fx]+')
+
+class Context(object):
+    actions = ()
+
+    def action(self, discriminator, callable, args):
+        self.actions += ((discriminator, callable, args), )
+
+    def __repr__(self):
+        stream = StringIO()
+        pprinter = pprint.PrettyPrinter(stream=stream, width=60)
+        pprinter.pprint(self.actions)
+        r = stream.getvalue()
+        return (''.join(atre.split(r))).strip()
+
+
+template = """<configure
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:test='http://www.zope.org/NS/Zope3/test'
+   i18n_domain='zope'>
+   %s
+   </configure>"""
+
+def definePermissions():
+    XMLConfig('meta.zcml', zope.security)()
+
+
+class ParticipationStub(object):
+
+    def __init__(self, principal):
+        self.principal = principal
+        self.interaction = None
+
+
+def configfile(s):
+    return StringIO("""<configure
+      xmlns='http://namespaces.zope.org/zope'
+      i18n_domain='zope'>
+      %s
+      </configure>
+      """ % s)
+
+class TestFactoryDirective(PlacelessSetup, unittest.TestCase):
+    def setUp(self):
+        super(TestFactoryDirective, self).setUp()
+        XMLConfig('meta.zcml', zope.security)()
+
+    def testFactory(self):
+        f = configfile('''
+<permission id="zope.Foo" title="Zope Foo Permission" />
+<class class="zope.security.tests.exampleclass.ExampleClass">
+    <factory
+      id="test.Example"
+      title="Example content"
+      description="Example description"
+       />
+</class>''')
+        xmlconfig(f)
+        obj = zope.component.createObject('test.Example')
+        self.failUnless(proxy.isinstance(obj, exampleclass.ExampleClass))
+
+
+
+PREFIX = module.__name__ + '.'
+
+def defineDirectives():
+    XMLConfig('meta.zcml', zope.security)()
+    xmlconfig(StringIO("""<configure
+        xmlns='http://namespaces.zope.org/zope'
+        i18n_domain='zope'>
+       <permission id="zope.Extravagant" title="extravagant" />
+       <permission id="zope.Paltry" title="paltry" />
+    </configure>"""))
+
+NOTSET = []
+
+P1 = "zope.Extravagant"
+P2 = "zope.Paltry"
+
+class TestRequireDirective(PlacelessSetup, unittest.TestCase):
+
+    def setUp(self):
+        super(TestRequireDirective, self).setUp()
+        defineDirectives()
+
+        class B(object):
+            def m1(self):
+                return "m1"
+            def m2(self):
+                return "m2"
+        class C(B):
+            implements(module.I)
+            def m3(self):
+                return "m3"
+            def m4(self):
+                return "m4"
+        module.test_base = B
+        module.test_class = C
+        module.test_instance = C()
+        self.assertState()
+
+    def tearDown(self):
+        PlacelessSetup.tearDown(self)
+        module.test_class = None
+
+    def assertState(self, m1P=NOTSET, m2P=NOTSET, m3P=NOTSET):
+        "Verify that class, instance, and methods have expected permissions."
+
+        checker = selectChecker(module.test_instance)
+        self.assertEqual(checker.permission_id('m1'), (m1P or None))
+        self.assertEqual(checker.permission_id('m2'), (m2P or None))
+        self.assertEqual(checker.permission_id('m3'), (m3P or None))
+
+    def assertDeclaration(self, declaration, **state):
+        apply_declaration(module.template_bracket % declaration)
+        self.assertState(**state)
+
+    # "testSimple*" exercises tags that do NOT have children.  This mode
+    # inherently sets the instances as well as the class attributes.
+
+    def testSimpleMethodsPlural(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                attributes="m1 m3"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1))
+        self.assertDeclaration(declaration, m1P=P1, m3P=P1)
+
+    def assertSetattrState(self, m1P=NOTSET, m2P=NOTSET, m3P=NOTSET):
+        "Verify that class, instance, and methods have expected permissions."
+
+        from zope.security.checker import selectChecker
+
+        checker = selectChecker(module.test_instance)
+        self.assertEqual(checker.setattr_permission_id('m1'), (m1P or None))
+        self.assertEqual(checker.setattr_permission_id('m2'), (m2P or None))
+        self.assertEqual(checker.setattr_permission_id('m3'), (m3P or None))
+
+    def assertSetattrDeclaration(self, declaration, **state):
+        self.assertSetattrState(**state)
+
+    def test_set_attributes(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                set_attributes="m1 m3"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1))
+        apply_declaration(module.template_bracket % declaration)
+        checker = selectChecker(module.test_instance)
+        self.assertEqual(checker.setattr_permission_id('m1'), P1)
+        self.assertEqual(checker.setattr_permission_id('m2'), None)
+        self.assertEqual(checker.setattr_permission_id('m3'), P1)
+
+    def test_set_schema(self):
+
+        self.assertEqual(queryInterface(PREFIX+"S"), None)
+
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                set_schema="%s"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"S"))
+        apply_declaration(module.template_bracket % declaration)
+
+        self.assertEqual(queryInterface(PREFIX+"S"), module.S)
+
+
+        checker = selectChecker(module.test_instance)
+        self.assertEqual(checker.setattr_permission_id('m1'), None)
+        self.assertEqual(checker.setattr_permission_id('m2'), None)
+        self.assertEqual(checker.setattr_permission_id('m3'), None)
+        self.assertEqual(checker.setattr_permission_id('foo'), P1)
+        self.assertEqual(checker.setattr_permission_id('bar'), P1)
+        self.assertEqual(checker.setattr_permission_id('baro'), None)
+
+    def test_multiple_set_schema(self):
+
+        self.assertEqual(queryInterface(PREFIX+"S"), None)
+        self.assertEqual(queryInterface(PREFIX+"S2"), None)
+
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                set_schema="%s %s"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"S", PREFIX+"S2"))
+        apply_declaration(module.template_bracket % declaration)
+
+        self.assertEqual(queryInterface(PREFIX+"S"), module.S)
+        self.assertEqual(queryInterface(PREFIX+"S2"), module.S2)
+
+
+        checker = selectChecker(module.test_instance)
+        self.assertEqual(checker.setattr_permission_id('m1'), None)
+        self.assertEqual(checker.setattr_permission_id('m2'), None)
+        self.assertEqual(checker.setattr_permission_id('m3'), None)
+        self.assertEqual(checker.setattr_permission_id('foo'), P1)
+        self.assertEqual(checker.setattr_permission_id('bar'), P1)
+        self.assertEqual(checker.setattr_permission_id('foo2'), P1)
+        self.assertEqual(checker.setattr_permission_id('bar2'), P1)
+        self.assertEqual(checker.setattr_permission_id('baro'), None)
+
+    def testSimpleInterface(self):
+
+        self.assertEqual(queryInterface(PREFIX+"I"), None)
+
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                interface="%s"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"I"))
+        # m1 and m2 are in the interface, so should be set, and m3 should not:
+        self.assertDeclaration(declaration, m1P=P1, m2P=P1)
+
+        # Make sure we know about the interfaces
+        self.assertEqual(queryInterface(PREFIX+"I"), module.I)
+
+
+    def testMultipleInterface(self):
+
+        self.assertEqual(queryInterface(PREFIX+"I3"), None)
+        self.assertEqual(queryInterface(PREFIX+"I4"), None)
+
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                interface="  %s
+                                             %s  "/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"I3", PREFIX+"I4"))
+        self.assertDeclaration(declaration, m3P=P1, m2P=P1)
+
+        # Make sure we know about the interfaces
+        self.assertEqual(queryInterface(PREFIX+"I3"), module.I3)
+        self.assertEqual(queryInterface(PREFIX+"I4"), module.I4)
+
+    # "testComposite*" exercises tags that DO have children.
+    # "testComposite*TopPerm" exercises tags with permission in containing tag.
+    # "testComposite*ElementPerm" exercises tags w/permission in children.
+
+    def testCompositeNoPerm(self):
+        # Establish rejection of declarations lacking a permission spec.
+        declaration = ('''<class class="%s">
+                            <require
+                                attributes="m1"/>
+                          </class>'''
+                       % (PREFIX+"test_class"))
+        self.assertRaises(ZopeXMLConfigurationError,
+                          self.assertDeclaration,
+                          declaration)
+
+
+
+    def testCompositeMethodsPluralElementPerm(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                attributes="m1 m3"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1))
+        self.assertDeclaration(declaration,
+                               m1P=P1, m3P=P1)
+
+    def testCompositeInterfaceTopPerm(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                interface="%s"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"I"))
+        self.assertDeclaration(declaration,
+                               m1P=P1, m2P=P1)
+
+
+    def testSubInterfaces(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                interface="%s"/>
+                          </class>'''
+                       % (PREFIX+"test_class", P1, PREFIX+"I2"))
+        # m1 and m2 are in the interface, so should be set, and m3 should not:
+        self.assertDeclaration(declaration, m1P=P1, m2P=P1)
+
+
+    def testMimicOnly(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                attributes="m1 m2"/>
+                          </class>
+                          <class class="%s">
+                            <require like_class="%s" />
+                          </class>
+                          ''' % (PREFIX+"test_base", P1,
+                PREFIX+"test_class", PREFIX+"test_base"))
+        # m1 and m2 are in the interface, so should be set, and m3 should not:
+        self.assertDeclaration(declaration,
+                               m1P=P1, m2P=P1)
+
+
+    def testMimicAsDefault(self):
+        declaration = ('''<class class="%s">
+                            <require
+                                permission="%s"
+                                attributes="m1 m2"/>
+                          </class>
+                          <class class="%s">
+                            <require like_class="%s" />
+                            <require
+                                permission="%s"
+                                attributes="m2 m3"/>
+                          </class>
+                          ''' % (PREFIX+"test_base", P1,
+                PREFIX+"test_class", PREFIX+"test_base", P2))
+
+        # m1 and m2 are in the interface, so should be set, and m3 should not:
+        self.assertDeclaration(declaration,
+                               m1P=P1, m2P=P2, m3P=P2)
+
+
+def apply_declaration(declaration):
+    '''Apply the xmlconfig machinery.'''
+    return xmlconfig(StringIO(declaration))
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(TestFactoryDirective),
+        unittest.makeSuite(TestRequireDirective),
+        DocTestSuite(),
+        ))


Property changes on: zope.security/trunk/src/zope/security/tests/test_directives.py
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.33
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native



More information about the Checkins mailing list