[Checkins] SVN: zope.generic/trunk/src/zope/generic/ add new
informations subdirecitve for information provider which is
providing configuration from a ini-File
Dominik Huber
dominik.huber at perse.ch
Thu May 4 08:35:12 EDT 2006
Log message for revision 67961:
add new informations subdirecitve for information provider which is providing configuration from a ini-File
Changed:
U zope.generic/trunk/src/zope/generic/configuration/api.py
U zope.generic/trunk/src/zope/generic/configuration/base.py
U zope.generic/trunk/src/zope/generic/configuration/helper.py
U zope.generic/trunk/src/zope/generic/configuration/tests.py
U zope.generic/trunk/src/zope/generic/factory/DEPENDENCIES.cfg
D zope.generic/trunk/src/zope/generic/factory/adapter.py
U zope.generic/trunk/src/zope/generic/factory/factory.py
U zope.generic/trunk/src/zope/generic/factory/metaconfigure.py
U zope.generic/trunk/src/zope/generic/informationprovider/README.txt
U zope.generic/trunk/src/zope/generic/informationprovider/meta.zcml
U zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py
U zope.generic/trunk/src/zope/generic/informationprovider/metadirectives.py
U zope.generic/trunk/src/zope/generic/informationprovider/testing.py
-=-
Modified: zope.generic/trunk/src/zope/generic/configuration/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/api.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/configuration/api.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -21,8 +21,8 @@
from zope.generic.configuration import *
from zope.generic.configuration.adapter import AttributeConfigurations
from zope.generic.configuration.base import ConfigurationData
-from zope.generic.configuration.helper import parameterToConfiguration
from zope.generic.configuration.helper import configuratonToDict
+from zope.generic.configuration.helper import getValue
from zope.generic.configuration.helper import requiredInOrder
@@ -40,3 +40,108 @@
except:
return default
+
+
+
+def parameterToConfiguration(__keyface__, *pos, **kws):
+ """Create configuration data
+
+ The generic signature *pos, **kws can will be resolved into a configuration.
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IAnyConfiguration(Interface):
+ ... a = TextLine()
+ ... b = TextLine(required=False)
+ ... c = TextLine(required=False, readonly=True, default=u'c default')
+ ... d = TextLine()
+
+ A: No arguments does not satisfy the configuration:
+
+ >>> parameterToConfiguration(IAnyConfiguration)
+ Traceback (most recent call last):
+ ...
+ TypeError: __init__ requires 'a, d' of 'IAnyConfiguration'.
+
+ B: Provide the required as positionals:
+
+ >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', u'd bla')
+ >>> config.a, config.b, config.c, config.d
+ (u'a bla', None, u'c default', u'd bla')
+
+ C: Provide the required as positional and keyword:
+
+ >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', d=u'd bla')
+ >>> config.a, config.b, config.c, config.d
+ (u'a bla', None, u'c default', u'd bla')
+
+ D: Provide all required as keyword:
+
+ >>> config = parameterToConfiguration(IAnyConfiguration, d=u'd bla', c=u'c bla', a=u'a bla')
+ >>> config.a, config.b, config.c, config.d
+ (u'a bla', None, u'c bla', u'd bla')
+
+ E: You can also use an existing configuration as input:
+
+ >>> parameterToConfiguration(IAnyConfiguration, config) == config
+ True
+
+
+ F: Provide the required as positional and keyword, do not messup the order otherwise
+ a duplacted arguments error could occur:
+
+ >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', d=u'd bla', c=u'c bla')
+ >>> config.a, config.b, config.c, config.d
+ (u'a bla', None, u'c bla', u'd bla')
+
+ >>> parameterToConfiguration(IAnyConfiguration, u'd bla', a=u'd bla', c=u'c bla')
+ Traceback (most recent call last):
+ ...
+ AttributeError: Duplicated arguments: a.
+
+ G: Sometimes any parameters are allowed. This use case is indicated by a None key interface:
+
+ >>> parameterToConfiguration(None) is None
+ True
+
+ >>> parameterToConfiguration(None, 'not allowed parameter')
+
+ """
+ # no arguments declared
+ if __keyface__ is None:
+# if pos or kws:
+# raise AttributeError('No arguments allowed.')
+
+ return None
+
+ # assume that kws are ok
+ if not pos:
+ try:
+ return ConfigurationData(__keyface__, kws)
+
+ except:
+ pass
+
+ # assume that first pos is already a configuration
+ if len(pos) == 1 and not kws and __keyface__.providedBy(pos[0]):
+ return pos[0]
+
+ # pos and kws mixture
+ attribution = requiredInOrder(__keyface__)
+ errors = []
+ for i in range(len(pos)):
+ key = attribution[i]
+ value = pos[i]
+
+
+ if key not in kws:
+ kws[key] = value
+ else:
+ errors.append(key)
+
+ if errors:
+ raise AttributeError('Duplicated arguments: %s.' % ', '.join(errors))
+
+ return ConfigurationData(__keyface__, kws)
+
\ No newline at end of file
Modified: zope.generic/trunk/src/zope/generic/configuration/base.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/base.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/configuration/base.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -24,8 +24,6 @@
from zope.interface import directlyProvides
from zope.interface import implements
-from zope.interface.interfaces import IMethod
-from zope.schema.interfaces import IField
from zope.generic.face import IAttributeFaced
from zope.generic.face import IFace
@@ -34,6 +32,7 @@
from zope.generic.configuration import IConfigurationData
from zope.generic.configuration import IConfigurations
+from zope.generic.configuration.helper import getValue
@@ -146,27 +145,10 @@
keyface = self.__dict__['__keyface__']
data = self.__dict__['_ConfigurationData__data']
- try:
- field = keyface[name]
- except KeyError:
- raise AttributeError(name)
- else:
- value = data.get(name, _marker)
- if value is _marker:
- value = getattr(field, 'default', _marker)
- if value is _marker:
- raise RuntimeError('Data is missing', name)
- if IMethod.providedBy(field):
- if not IField.providedBy(field):
- raise RuntimeError('Data value is not a schema field', name)
- v = lambda: value
- else:
- v = value
- #setattr(self, name, v)
- return v
- raise AttributeError(name)
+ return getValue(keyface, name, data)
+
def __setattr__(self, name, value):
if not(name == '__provides__' or name in IPersistent):
Modified: zope.generic/trunk/src/zope/generic/configuration/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -18,15 +18,40 @@
__docformat__ = 'restructuredtext'
+from zope.interface.interfaces import IMethod
+from zope.schema.interfaces import IField
from zope.generic.face import IFace
-from zope.generic.configuration.base import ConfigurationData
-
_marker = object()
+def getValue(keyface, name, data):
+ """Return a declared value."""
+ try:
+ field = keyface[name]
+ except KeyError:
+ raise AttributeError(name)
+ else:
+ value = data.get(name, _marker)
+ if value is _marker:
+ value = getattr(field, 'default', _marker)
+ if value is _marker:
+ raise RuntimeError('Data is missing', name)
+
+ if IMethod.providedBy(field):
+ if not IField.providedBy(field):
+ raise RuntimeError('Data value is not a schema field', name)
+ v = lambda: value
+ else:
+ v = value
+
+ return v
+ raise AttributeError(name)
+
+
+
def configuratonToDict(configuration, all=False):
"""Extract values from configuration to a dictionary.
@@ -102,108 +127,3 @@
"""
return [name for name in configuration if configuration[name].required is True]
-
-
-
-def parameterToConfiguration(__keyface__, *pos, **kws):
- """Create configuration data
-
- The generic signature *pos, **kws can will be resolved into a configuration.
-
- >>> from zope.interface import Interface
- >>> from zope.schema import TextLine
-
- >>> class IAnyConfiguration(Interface):
- ... a = TextLine()
- ... b = TextLine(required=False)
- ... c = TextLine(required=False, readonly=True, default=u'c default')
- ... d = TextLine()
-
- A: No arguments does not satisfy the configuration:
-
- >>> parameterToConfiguration(IAnyConfiguration)
- Traceback (most recent call last):
- ...
- TypeError: __init__ requires 'a, d' of 'IAnyConfiguration'.
-
- B: Provide the required as positionals:
-
- >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', u'd bla')
- >>> config.a, config.b, config.c, config.d
- (u'a bla', None, u'c default', u'd bla')
-
- C: Provide the required as positional and keyword:
-
- >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', d=u'd bla')
- >>> config.a, config.b, config.c, config.d
- (u'a bla', None, u'c default', u'd bla')
-
- D: Provide all required as keyword:
-
- >>> config = parameterToConfiguration(IAnyConfiguration, d=u'd bla', c=u'c bla', a=u'a bla')
- >>> config.a, config.b, config.c, config.d
- (u'a bla', None, u'c bla', u'd bla')
-
- E: You can also use an existing configuration as input:
-
- >>> parameterToConfiguration(IAnyConfiguration, config) == config
- True
-
-
- F: Provide the required as positional and keyword, do not messup the order otherwise
- a duplacted arguments error could occur:
-
- >>> config = parameterToConfiguration(IAnyConfiguration, u'a bla', d=u'd bla', c=u'c bla')
- >>> config.a, config.b, config.c, config.d
- (u'a bla', None, u'c bla', u'd bla')
-
- >>> parameterToConfiguration(IAnyConfiguration, u'd bla', a=u'd bla', c=u'c bla')
- Traceback (most recent call last):
- ...
- AttributeError: Duplicated arguments: a.
-
- G: Sometimes any parameters are allowed. This use case is indicated by a None key interface:
-
- >>> parameterToConfiguration(None) is None
- True
-
- >>> parameterToConfiguration(None, 'not allowed parameter')
-
- """
- # no arguments declared
- if __keyface__ is None:
-# if pos or kws:
-# raise AttributeError('No arguments allowed.')
-
- return None
-
- # assume that kws are ok
- if not pos:
- try:
- return ConfigurationData(__keyface__, kws)
-
- except:
- pass
-
- # assume that first pos is already a configuration
- if len(pos) == 1 and not kws and __keyface__.providedBy(pos[0]):
- return pos[0]
-
- # pos and kws mixture
- attribution = requiredInOrder(__keyface__)
- errors = []
- for i in range(len(pos)):
- key = attribution[i]
- value = pos[i]
-
-
- if key not in kws:
- kws[key] = value
- else:
- errors.append(key)
-
- if errors:
- raise AttributeError('Duplicated arguments: %s.' % ', '.join(errors))
-
- return ConfigurationData(__keyface__, kws)
-
\ No newline at end of file
Modified: zope.generic/trunk/src/zope/generic/configuration/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -22,7 +22,6 @@
from zope import interface
from zope.testing import doctest
-
from zope.generic.testing.testing import InterfaceBaseTest
from zope.generic.testing.testing import registerDirective
Modified: zope.generic/trunk/src/zope/generic/factory/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/factory/DEPENDENCIES.cfg 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/factory/DEPENDENCIES.cfg 2006-05-04 12:35:11 UTC (rev 67961)
@@ -13,4 +13,4 @@
zope.interface
zope.lifecycleevent
zope.security
-zope.testing
\ No newline at end of file
+zope.testing
Deleted: zope.generic/trunk/src/zope/generic/factory/adapter.py
===================================================================
--- zope.generic/trunk/src/zope/generic/factory/adapter.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/factory/adapter.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -1,45 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-
-"""
-$Id$
-"""
-
-__docformat__ = 'restructuredtext'
-
-from zope.component import adapts
-from zope.interface import implements
-
-from zope.generic.informationprovider.api import queryInformation
-from zope.generic.informationprovider.api import getInformationProvider
-from zope.generic.face import IFaced
-from zope.generic.operation import IOperationConfiguration
-
-from zope.generic.factory import IFactoryInformation
-from zope.generic.factory import IInitializer
-
-
-
-class Initializer(object):
- """Initialize an object."""
-
- implements(IInitializer)
-
- adapts(IFaced)
-
- def __init__(self, context):
- self.context = context
-
- def __call__(self, *pos, **kws):
-
Modified: zope.generic/trunk/src/zope/generic/factory/factory.py
===================================================================
--- zope.generic/trunk/src/zope/generic/factory/factory.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/factory/factory.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -33,8 +33,6 @@
from zope.generic.face import IProvidesAttributeFaced
from zope.generic.face.api import Face
from zope.generic.operation import IOperationConfiguration
-
-from zope.generic.factory import IFactoryType
Modified: zope.generic/trunk/src/zope/generic/factory/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/factory/metaconfigure.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/factory/metaconfigure.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -28,12 +28,9 @@
from zope.security.checker import CheckerPublic
from zope.security.checker import InterfaceChecker
-from zope.generic.face import IKeyfaceType
from zope.generic.face import IUndefinedContext
from zope.generic.face.api import toDescription
from zope.generic.face.api import toDottedName
-from zope.generic.informationprovider.api import getInformationProvider
-from zope.generic.informationprovider.api import provideInformation
from zope.generic.informationprovider.metaconfigure import InformationProviderDirective
from zope.generic.operation import IOperationConfiguration
from zope.generic.operation.api import assertOperation
Modified: zope.generic/trunk/src/zope/generic/informationprovider/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/README.txt 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/informationprovider/README.txt 2006-05-04 12:35:11 UTC (rev 67961)
@@ -147,15 +147,15 @@
... keyface="example.IMyFoo"
... conface="example.ISpecialContext"
... >
- ... <information
- ... key="example.my_annotation"
- ... annotation="example.my_annotation"
- ... />
- ... <information
- ... keyface="example.IMyConfiguration"
- ... configuration="example.my_configuration"
- ... />
- ... </generic:informationProvider>
+ ... <information
+ ... key="example.my_annotation"
+ ... annotation="example.my_annotation"
+ ... />
+ ... <information
+ ... keyface="example.IMyConfiguration"
+ ... configuration="example.my_configuration"
+ ... />
+ ... </generic:informationProvider>
... ''')
>>> provider = api.queryInformationProvider(IMyFoo, ISpecialContext)
@@ -349,6 +349,7 @@
>>> [i.__name__ for i,p in api.getInformationProvidersFor(IBarFoo)]
['IOurContext', 'IUndefinedContext']
+
Components can suggest key and context interfaces
-------------------------------------------------
@@ -389,3 +390,77 @@
>>> api.acquireInformationProvider(bar)
<GlobalInformationProvider IBar at IUndefinedContext>
+
+
+Ini-file based configurations for an information provider
+---------------------------------------------------------
+
+The configuration file holds several configuration in the ini-file style.
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import Text, TextLine
+
+ >>> class IOneConfiguration(Interface):
+ ... textLine = TextLine(title=u'TextLine')
+ ... text = Text(title=u'Text', required=False, default=u'Bla\\n')
+
+ >>> registerDirective('''
+ ... <generic:interface
+ ... interface="example.IOneConfiguration"
+ ... type="zope.generic.configuration.IConfigurationType"
+ ... />
+ ... ''')
+
+ >>> from zope.schema import Bool, Int
+
+ >>> class IOtherConfiguration(Interface):
+ ... bool = Bool(title=u'Bool')
+ ... int = Int(title=u'Int', required=False, default=42)
+
+ >>> registerDirective('''
+ ... <generic:interface
+ ... interface="example.IOtherConfiguration"
+ ... type="zope.generic.configuration.IConfigurationType"
+ ... />
+ ... ''')
+
+ >>> import os, tempfile
+ >>> temp_dir = tempfile.mkdtemp()
+ >>> iniFile = os.path.join(temp_dir, 'example.ini')
+ >>> open(iniFile, 'w').write('''
+ ... [example.IOneConfiguration]
+ ... textline = Foo
+ ... text : Bla bla bla bla.
+ ...
+ ... [example.IOtherConfiguration]
+ ... bool = True
+ ... int = 77
+ ... ''')
+
+ >>> registerDirective('''
+ ... <generic:informationProvider
+ ... keyface="example.IFoo"
+ ... conface="example.ISpecialContext"
+ ... >
+ ... <informations
+ ... iniFiles="%s"
+ ... />
+ ... </generic:informationProvider>
+ ... ''' % iniFile)
+
+ >>> foo_config = api.getInformation(IOneConfiguration, IFoo, ISpecialContext)
+ >>> foo_config.textLine
+ u'Foo'
+
+ >>> foo_config.text
+ u'Bla bla bla bla.'
+
+ >>> bar_config = api.getInformation(IOtherConfiguration, IFoo, ISpecialContext)
+ >>> bar_config.bool
+ True
+
+ >>> bar_config.int
+ 77
+
+ >>> import shutil
+ >>> shutil.rmtree(temp_dir)
Modified: zope.generic/trunk/src/zope/generic/informationprovider/meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/meta.zcml 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/informationprovider/meta.zcml 2006-05-04 12:35:11 UTC (rev 67961)
@@ -15,6 +15,11 @@
schema=".metadirectives.IInformationSubdirective"
/>
+ <meta:subdirective
+ name="informations"
+ schema=".metadirectives.IInformationsSubdirective"
+ />
+
</meta:complexDirective>
</meta:directives>
Modified: zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -18,6 +18,8 @@
__docformat__ = 'restructuredtext'
+from ConfigParser import SafeConfigParser
+
from zope.annotation import IAnnotations
from zope.component import provideUtility
from zope.component import getUtility
@@ -25,6 +27,7 @@
from zope.component.interface import provideInterface
from zope.configuration.exceptions import ConfigurationError
from zope.interface import alsoProvides
+from zope.schema.interfaces import IFromUnicode
from zope.generic.configuration import IConfigurations
from zope.generic.configuration.api import ConfigurationData
@@ -36,6 +39,7 @@
from zope.generic.face.api import getKeyface
from zope.generic.face.api import toDescription
from zope.generic.face.api import toDottedName
+from zope.generic.face.api import toInterface
from zope.generic.informationprovider.base import GlobalInformationProvider
@@ -113,8 +117,42 @@
+_marker = object()
+
+def iniFileToConfiguration(path):
+ """Parse ini file to an iterator over keyface, configuration pairs."""
+
+ configparser = SafeConfigParser()
+ configparser.read(path)
+
+ for section in configparser.sections():
+ # convert section to configuration interface
+ keyface = toInterface(section)
+
+ data = {}
+
+ for name in keyface:
+ field = keyface[name]
+ # evalutate name: config parser options are always lower case
+ try:
+ value = configparser.get(section, name.lower())
+
+ except:
+ value = _marker
+
+ if value is not _marker:
+ try:
+ data[name] = field.fromUnicode(unicode(value))
+
+ except:
+ data[name] = IFromUnicode(field).fromUnicode(unicode(value))
+
+ yield (keyface, data)
+
+
+
class InformationProviderDirective(object):
- """Provide a new information of a certain information registry."""
+ """Provide a new information provider."""
def __init__(self, _context, keyface=IUndefinedKeyface, conface=IUndefinedContext):
# preconditions
@@ -176,4 +214,13 @@
else:
raise ConfigurationError('Information subdirective must provide ' +
'key and annotation or keyface and configuration.')
+
+ def informations(self, _context, iniFiles=()):
+ """Ini-file based configurations for an information provider."""
+
+ for path in iniFiles:
+ for keyface, configuration in iniFileToConfiguration(path):
+ # register corresponding configuration information
+ self.information(_context, keyface, configuration)
+
\ No newline at end of file
Modified: zope.generic/trunk/src/zope/generic/informationprovider/metadirectives.py
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/metadirectives.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/informationprovider/metadirectives.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -22,6 +22,8 @@
from zope.configuration.fields import GlobalInterface
from zope.configuration.fields import GlobalObject
from zope.configuration.fields import MessageID
+from zope.configuration.fields import Path
+from zope.configuration.fields import Tokens
from zope.interface import Interface
from zope.schema import DottedName
@@ -102,3 +104,16 @@
description=_('Annotation component expected undert the key.'),
required=False
)
+
+
+class IInformationsSubdirective(Interface):
+ """Ini-file based configurations for an information provider."""
+
+ iniFiles = Tokens(
+ title=_('*.ini-like File'),
+ description=_('Parse configuration key interfaces from sections. '
+ 'and the configuration data from theirs options using '
+ 'the config parser and IFromUnicode(field).fromUnicode().'),
+ required=False,
+ value_type=Path(constraint=lambda v: v.endswith('.ini'))
+ )
Modified: zope.generic/trunk/src/zope/generic/informationprovider/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/testing.py 2006-05-04 08:00:22 UTC (rev 67960)
+++ zope.generic/trunk/src/zope/generic/informationprovider/testing.py 2006-05-04 12:35:11 UTC (rev 67961)
@@ -24,7 +24,6 @@
import zope.generic.face.testing
import zope.generic.testing.testing
-from zope.interface import classImplements
from zope.configuration.xmlconfig import XMLConfig
@@ -57,9 +56,6 @@
from zope.generic.informationprovider.api import GlobalInformationProvider
from zope.generic.informationprovider.api import LocalInformationProvider
- classImplements(GlobalInformationProvider, IAttributeConfigurable, IAttributeAnnotatable)
- classImplements(LocalInformationProvider, IAttributeConfigurable, IAttributeAnnotatable)
-
def tearDown(doctest=None):
pass
More information about the Checkins
mailing list