[Checkins] SVN: zope.generic/trunk/src/zope/generic/ new
multiInformationProvider directive.
Dominik Huber
dominik.huber at perse.ch
Thu May 4 14:56:15 EDT 2006
Log message for revision 67971:
new multiInformationProvider directive.
remove informations subdirective of the informationProvider directive
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/face/api.py
U zope.generic/trunk/src/zope/generic/face/helper.py
U zope.generic/trunk/src/zope/generic/face/tests.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
-=-
Modified: zope.generic/trunk/src/zope/generic/configuration/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/api.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/configuration/api.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -24,6 +24,7 @@
from zope.generic.configuration.helper import configuratonToDict
from zope.generic.configuration.helper import getValue
from zope.generic.configuration.helper import requiredInOrder
+from zope.generic.configuration.helper import toConfigFaceTriple
Modified: zope.generic/trunk/src/zope/generic/configuration/base.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/base.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/configuration/base.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -24,6 +24,8 @@
from zope.interface import directlyProvides
from zope.interface import implements
+from zope.schema.interfaces import IObject
+from zope.schema.interfaces import IContainer
from zope.generic.face import IAttributeFaced
from zope.generic.face import IFace
@@ -32,10 +34,64 @@
from zope.generic.configuration import IConfigurationData
from zope.generic.configuration import IConfigurations
+from zope.generic.configuration import IConfigurationType
from zope.generic.configuration.helper import getValue
+def subData(name, data):
+ """Return a subdata dict and remove the subdata from the given data dict.
+
+ Example 1:
+
+ >>> data = {'x.y': 2, 'x.a': 3, 'x.': 4, 'xa': 5}
+ >>> subData('x', data)
+ {'y': 2, 'a': 3}
+ """
+
+ subdata = {}
+
+ prefix = name + '.'
+ prefix_len = len(name + '.')
+
+ # add subdata to dictionary
+ for key, value in data.items():
+ if len(key) > prefix_len and key.startswith(prefix):
+ subdata[key[prefix_len:]] = value
+ del data[key]
+
+ return subdata
+
+
+
+def prepareData(__keyface__, data):
+ """Nested configuration support."""
+ missedArguments = []
+ for name in __keyface__:
+ # forget missing but none-required
+ if name not in data:
+ field = __keyface__[name]
+ # handle nested configuration data
+ if IObject.providedBy(field) and IConfigurationType.providedBy(field.schema):
+ try:
+ subdata = subData(name, data)
+ if subdata or field.required is True:
+ data[name] = ConfigurationData(field.schema, subData(name, data))
+ break
+
+ except:
+ pass
+
+ if field.required is True:
+ missedArguments.append(name)
+
+ if missedArguments:
+ raise TypeError("__init__ requires '%s' of '%s'." % (', '.join(missedArguments), __keyface__.__name__))
+
+ return data
+
+
+
_marker = object()
class ConfigurationData(Persistent):
@@ -117,19 +173,8 @@
implements(IAttributeFaced, IConfigurationData)
def __init__(self, __keyface__, data):
- # preconditions
- missedArguments = []
- for name in __keyface__:
- if name not in data:
- field = __keyface__[name]
- if field.required is True:
- missedArguments.append(name)
-
- if missedArguments:
- raise TypeError("__init__ requires '%s' of '%s'." % (', '.join(missedArguments), __keyface__.__name__))
-
# essentials
- self.__dict__['_ConfigurationData__data'] = PersistentDict(data)
+ self.__dict__['_ConfigurationData__data'] = PersistentDict(prepareData(__keyface__, data))
self.__dict__['__keyface__'] = __keyface__
self.__dict__['__conface__'] = IUndefinedContext
directlyProvides(self, __keyface__)
Modified: zope.generic/trunk/src/zope/generic/configuration/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -22,6 +22,10 @@
from zope.schema.interfaces import IField
from zope.generic.face import IFace
+from zope.generic.face import IUndefinedContext
+from zope.generic.face import IUndefinedKeyface
+from zope.generic.face.api import toFaceTuple
+from zope.generic.face.api import toInterface
@@ -69,11 +73,11 @@
>>> from zope.generic.configuration.base import ConfigurationData
>>> configuration = ConfigurationData(IAnyConfiguration, {'a': 'a bla'})
- >>> configuratonToDict(configuration)
+ >>> api.configuratonToDict(configuration)
{'a': 'a bla'}
Including defaults:
- >>> configuratonToDict(configuration, all=True)
+ >>> api.configuratonToDict(configuration, all=True)
{'a': 'a bla', 'c': u'c default', 'b': None}
"""
@@ -121,9 +125,36 @@
... c = TextLine(required=False, readonly=True, default=u'c bla')
... d = TextLine()
- >>> requiredInOrder(IAnyConfiguration)
+ >>> api.requiredInOrder(IAnyConfiguration)
['a', 'd']
"""
return [name for name in configuration if configuration[name].required is True]
+
+
+
+def toConfigFaceTriple(identifier):
+ """Split configface:keyface at conface to (configface, keyface, conface).
+
+ >>> from zope.interface import Interface
+
+ >>> class IA(Interface):
+ ... pass
+
+ >>> from zope.generic.face.api import toDottedName
+
+ >>> api.toConfigFaceTriple(toDottedName(IA) + ':')
+ (<InterfaceClass example.IA>, <....IUndefinedKeyface>, <....IUndefinedContext>)
+ """
+
+ parts = identifier.split(':')
+
+ if len(parts) == 1:
+ return (toInterface(parts[0]), IUndefinedKeyface, IUndefinedContext)
+
+ else:
+ keyface, conface = toFaceTuple(parts[1])
+ return (toInterface(parts[0]), keyface, conface)
+
+
Modified: zope.generic/trunk/src/zope/generic/configuration/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -65,7 +65,6 @@
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ConfigurationDataTest),
- doctest.DocTestSuite('zope.generic.configuration.helper'),
doctest.DocTestSuite('zope.generic.configuration.base'),
doctest.DocTestSuite('zope.generic.configuration.event'),
doctest.DocTestSuite('zope.generic.configuration.adapter',
@@ -76,6 +75,14 @@
'testing': testing, 'api': api},
optionflags=doctest.NORMALIZE_WHITESPACE+
doctest.ELLIPSIS),
+ doctest.DocTestSuite('zope.generic.configuration.helper',
+ setUp=testing.placelesssetup.setUp,
+ tearDown=testing.placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'registerDirective': registerDirective,
+ 'testing': testing, 'api': api},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
doctest.DocFileSuite('README.txt',
setUp=testing.placelesssetup.setUp,
tearDown=testing.placelesssetup.tearDown,
Modified: zope.generic/trunk/src/zope/generic/face/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/face/api.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/face/api.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -23,6 +23,7 @@
from zope.generic.face.base import Face
from zope.generic.face.helper import toDescription
from zope.generic.face.helper import toDottedName
+from zope.generic.face.helper import toFaceTuple
from zope.generic.face.helper import toInterface
Modified: zope.generic/trunk/src/zope/generic/face/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/face/helper.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/face/helper.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -19,6 +19,8 @@
__docformat__ = 'restructuredtext'
from zope.dottedname.resolve import resolve
+from zope.generic.face import IUndefinedContext
+from zope.generic.face import IUndefinedKeyface
@@ -48,7 +50,7 @@
>>> class A:
... pass
- >>> label, hint = toDescription(A)
+ >>> label, hint = api.toDescription(A)
>>> label
u''
>>> hint
@@ -60,7 +62,7 @@
... '''Test label.
... '''
- >>> label, hint = toDescription(B)
+ >>> label, hint = api.toDescription(B)
>>> label
u'Test label.'
>>> hint
@@ -75,7 +77,7 @@
... bla bla bla:
... - bla, bla, bla. '''
- >>> label, hint = toDescription(C)
+ >>> label, hint = api.toDescription(C)
>>> label
u'Test label.'
>>> hint
@@ -84,13 +86,13 @@
You can overwrite the underlying doc string providing your own
label or hint:
- >>> label, hint = toDescription(C, label=u'My label')
+ >>> label, hint = api.toDescription(C, label=u'My label')
>>> label
u'My label'
>>> hint
u'Test hint, bla bla .\\\\nbla bla bla:\\\\n- bla, bla, bla.'
- >>> label, hint = toDescription(C, hint=u'My hint')
+ >>> label, hint = api.toDescription(C, hint=u'My hint')
>>> label
u'Test label.'
>>> hint
@@ -129,4 +131,72 @@
else:
return (unicode(lines[0].strip()), u'')
- return (u'', u'')
+ return (u'', u'')
+
+
+
+def toFaceTuple(identifier):
+ """Resolve 'keyface at conface' to (keyface, conface).
+
+ >>> from zope.interface import Interface
+
+ >>> class IK(Interface):
+ ... pass
+
+ >>> class IC(Interface):
+ ... pass
+
+ Example 1:
+
+ >>> api.toFaceTuple(api.toDottedName(IK))
+ (<InterfaceClass example.IK>, <....IUndefinedContext>)
+
+ Example 2:
+
+ >>> api.toFaceTuple('wrong')
+ (<....IUndefinedKeyface>, <....IUndefinedContext>)
+
+ Example 3:
+
+ >>> api.toFaceTuple(api.toDottedName(IK) + '@' + api.toDottedName(IC))
+ (<InterfaceClass example.IK>, <InterfaceClass example.IC>)
+
+ Example 4:
+
+ >>> api.toFaceTuple('@' + api.toDottedName(IC))
+ (<....IUndefinedKeyface>, <InterfaceClass example.IC>)
+
+ Example 5:
+
+ >>> api.toFaceTuple(api.toDottedName(IK) + '@')
+ (<InterfaceClass example.IK>, <....IUndefinedContext>)
+
+ Example 6:
+
+ >>> api.toFaceTuple('@')
+ (<....IUndefinedKeyface>, <....IUndefinedContext>)
+
+ """
+
+ parts = identifier.split('@')
+
+ if len(parts) == 1:
+ try:
+ return (toInterface(parts[0]), IUndefinedContext)
+
+ except:
+ return (IUndefinedKeyface, IUndefinedContext)
+
+ else:
+ try:
+ keyface = toInterface(parts[0])
+
+ except:
+ keyface = IUndefinedKeyface
+
+ try:
+ return (keyface, toInterface(parts[1]))
+
+ except:
+ return (keyface, IUndefinedContext)
+
Modified: zope.generic/trunk/src/zope/generic/face/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/face/tests.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/face/tests.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -61,7 +61,14 @@
unittest.makeSuite(FaceAdapterTest),
doctest.DocTestSuite('zope.generic.face.adapter'),
doctest.DocTestSuite('zope.generic.face.base'),
- doctest.DocTestSuite('zope.generic.face.helper'),
+ doctest.DocTestSuite('zope.generic.face.helper',
+ setUp=testing.placelesssetup.setUp,
+ tearDown=testing.placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'registerDirective': registerDirective,
+ 'testing': testing, 'api': api},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
doctest.DocFileSuite('README.txt',
setUp=testing.placelesssetup.setUp,
tearDown=testing.placelesssetup.tearDown,
Modified: zope.generic/trunk/src/zope/generic/informationprovider/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/README.txt 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/informationprovider/README.txt 2006-05-04 18:56:14 UTC (rev 67971)
@@ -424,6 +424,22 @@
... />
... ''')
+ >>> from zope.schema import Dict, Object, Tuple
+
+ >>> class INestedConfiguration(Interface):
+ ... one = Object(title=u'One configuration', schema=IOneConfiguration)
+ ... optionalother = Object(title=u'Other configuration', required=False, schema=IOtherConfiguration)
+ ... requiredother = Object(title=u'Other configuration', schema=IOtherConfiguration)
+ ... tuple = Tuple(title=u'Tuple of Int', value_type=Int())
+ ... dict = Dict(title=u'Dict of TextLine', value_type=TextLine())
+
+ >>> registerDirective('''
+ ... <generic:interface
+ ... interface="example.INestedConfiguration"
+ ... type="zope.generic.configuration.IConfigurationType"
+ ... />
+ ... ''')
+
>>> import os, tempfile
>>> temp_dir = tempfile.mkdtemp()
>>> iniFile = os.path.join(temp_dir, 'example.ini')
@@ -435,32 +451,114 @@
... [example.IOtherConfiguration]
... bool = True
... int = 77
+ ...
+ ... [example.INestedConfiguration]
+ ... one.textline = Bingo
+ ... one.text = Lotto.
+ ... requiredother.bool = False
+ ... tuple.0 = 2
+ ... tuple.1 = 3
+ ... tuple.2 = 19
+ ... dict.roger = ineichen
+ ... dict.dominik = huber
+ ... dict.daniel = meier
... ''')
+Such a file can be used for the configuration initializiation. Therefore you
+have to declare one or more files within the iniFiles attribute of the
+informaiton subdirective of the informationProvider direcitve:
+
>>> registerDirective('''
... <generic:informationProvider
... keyface="example.IFoo"
... conface="example.ISpecialContext"
... >
- ... <informations
+ ... <information
... iniFiles="%s"
... />
- ... </generic:informationProvider>
+ ... </generic:informationProvider>
... ''' % iniFile)
- >>> foo_config = api.getInformation(IOneConfiguration, IFoo, ISpecialContext)
- >>> foo_config.textLine
+ >>> one_config = api.getInformation(IOneConfiguration, IFoo, ISpecialContext)
+ >>> one_config.textLine
u'Foo'
- >>> foo_config.text
+ >>> one_config.text
u'Bla bla bla bla.'
- >>> bar_config = api.getInformation(IOtherConfiguration, IFoo, ISpecialContext)
- >>> bar_config.bool
+ >>> other_config = api.getInformation(IOtherConfiguration, IFoo, ISpecialContext)
+ >>> other_config.bool
True
- >>> bar_config.int
+ >>> other_config.int
77
+ >>> nested_config = api.getInformation(INestedConfiguration, IFoo, ISpecialContext)
+ >>> nested_config.one.textLine
+ u'Bingo'
+
+ >>> nested_config.one.text
+ u'Lotto.'
+
+ >>> nested_config.optionalother is None
+ True
+
+ >>> nested_config.requiredother.bool
+ False
+
+ >>> nested_config.requiredother.int
+ 42
+
+ >>> nested_config.tuple
+ (2, 3, 19)
+
+ >>> nested_config.dict
+ {'dominik': u'huber', 'daniel': u'meier', 'roger': u'ineichen'}
+
+Ini-file based configurations for an multi information provider
+---------------------------------------------------------------
+
+ >>> temp_dir = tempfile.mkdtemp()
+ >>> iniFile = os.path.join(temp_dir, 'example2.ini')
+ >>> open(iniFile, 'w').write('''
+ ... [example.IOneConfiguration:example.IBar at example.IMyContext]
+ ... textline = Gaga
+ ... text : Bla bla bla bla.
+ ...
+ ... [example.IOneConfiguration:example.IBarFoo at example.IMyContext]
+ ... textline = Gugu
+ ... text : Bla bla bla bla.
+ ...
+ ... [example.INestedConfiguration:example.IBar at example.IMyContext]
+ ... one.textline = Gogo
+ ... one.text = Lotto.
+ ... requiredother.bool = False
+ ... tuple.0 = 2
+ ... tuple.1 = 3
+ ... tuple.2 = 19
+ ... dict.roger = ineichen
+ ... dict.dominik = huber
+ ... dict.daniel = meier
+ ... ''')
+
+Such a file can be used for the configuration initializiation. Therefore you
+have to declare one or more files within the iniFiles attribute of the
+informaiton directive:
+
+ >>> registerDirective('''
+ ... <generic:multiInformationProviders
+ ... iniFiles="%s"
+ ... />
+ ... ''' % iniFile)
+
+ >>> api.getInformation(IOneConfiguration, IBar, IMyContext).textLine
+ u'Gaga'
+
+ >>> api.getInformation(IOneConfiguration, IBarFoo, IMyContext).textLine
+ u'Gugu'
+
+ >>> api.getInformation(INestedConfiguration, IBar, IMyContext).one.textLine
+ u'Gogo'
+
>>> 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 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/informationprovider/meta.zcml 2006-05-04 18:56:14 UTC (rev 67971)
@@ -15,13 +15,14 @@
schema=".metadirectives.IInformationSubdirective"
/>
- <meta:subdirective
- name="informations"
- schema=".metadirectives.IInformationsSubdirective"
- />
-
</meta:complexDirective>
+ <meta:directive
+ name="multiInformationProviders"
+ schema=".metadirectives.IMultiInformationProviderDirectives"
+ handler=".metaconfigure.multiInformationProviderDirectives"
+ />
+
</meta:directives>
</configure>
Modified: zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py 2006-05-04 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/informationprovider/metaconfigure.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -21,16 +21,23 @@
from ConfigParser import SafeConfigParser
from zope.annotation import IAnnotations
+from zope.component import getUtility
from zope.component import provideUtility
-from zope.component import getUtility
from zope.component import queryUtility
from zope.component.interface import provideInterface
from zope.configuration.exceptions import ConfigurationError
from zope.interface import alsoProvides
+from zope.schema.interfaces import IDict
from zope.schema.interfaces import IFromUnicode
+from zope.schema.interfaces import IList
+from zope.schema.interfaces import IObject
+from zope.schema.interfaces import ISequence
+from zope.schema.interfaces import ITuple
from zope.generic.configuration import IConfigurations
+from zope.generic.configuration import IConfigurationType
from zope.generic.configuration.api import ConfigurationData
+from zope.generic.configuration.api import toConfigFaceTriple
from zope.generic.face import IConfaceType
from zope.generic.face import IKeyfaceType
from zope.generic.face import IUndefinedContext
@@ -116,41 +123,125 @@
annotations[annotation_key] = annotation
+def nestedConfigurationData(configparser, section, keyface, prefix=''):
+ """Nested configuration support."""
+ missedArguments = []
+ data = {}
+
+ for name in keyface:
+ field = keyface[name]
+ lookup_name = prefix + name.lower()
+ # evalutate name: config parser options are always lower case
+ try:
+ value = configparser.get(section, lookup_name)
+ try:
+ data[name] = field.fromUnicode(unicode(value))
+
+ except:
+ data[name] = IFromUnicode(field).fromUnicode(unicode(value))
+
+ except:
+ if IObject.providedBy(field) and IConfigurationType.providedBy(field.schema):
+ subkeyface = field.schema
+ try:
+ subdata = nestedConfigurationData(configparser, section, subkeyface, lookup_name + '.')
+ except:
+ subdata = {}
+
+ if subdata or field.required is True:
+ try:
+ data[name] = ConfigurationData(subkeyface, subdata)
+ continue
+ except:
+ if field.required is False:
+ continue
+
+ elif ISequence.providedBy(field):
+ counter = 0
+ subfield = field.value_type
+ sequence = []
+ while True:
+ try:
+ value = configparser.get(section, lookup_name + '.' + str(counter))
+
+ try:
+ sequence.append(subfield.fromUnicode(unicode(value)))
+
+ except:
+ sequence.append(IFromUnicode(subfield).fromUnicode(unicode(value)))
+
+ except:
+ break
+
+ counter += 1
+
+ if sequence or field.required is True:
+ if ITuple.providedBy(field):
+ data[name] = tuple(sequence)
+
+ else:
+ data[name] = sequence
+
+ continue
+
+ elif IDict.providedBy(field):
+ sublookup_name = lookup_name + '.'
+ sublookup_len = len(sublookup_name)
+ subfield = field.value_type
+ subdict = {}
+ for key, value in configparser.items(section):
+ if len(key) > sublookup_len and key.startswith(sublookup_name):
+ subkey = key[sublookup_len:]
+ if subkey.count('.'):
+ raise NotImplementedError('Not supported yet!')
+
+ try:
+ value = configparser.get(section, key)
+
+ try:
+ subdict[subkey] = subfield.fromUnicode(unicode(value))
+
+ except:
+ subdict[subkey] = IFromUnicode(subfield).fromUnicode(unicode(value))
+
+ except:
+ break
+
+ if subdict or field.required is True:
+ data[name] = subdict
+ continue
+
+ if field.required is True:
+ missedArguments.append(lookup_name)
+
+ if missedArguments:
+ raise TypeError("__init__ requires '%s' of '%s'." % (', '.join(missedArguments), keyface.__name__))
+
+ return data
+
+
+
_marker = object()
-def iniFileToConfiguration(path):
+def iniFileToConfiguration(path, strict=True):
"""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())
+ if strict:
+ configuration, keyface, conface = toConfigFaceTriple(section)
+ yield (configuration, keyface, conface, nestedConfigurationData(configparser, section, configuration))
- except:
- value = _marker
+ else:
+ configuration = toInterface(section)
+ yield (configuration, nestedConfigurationData(configparser, section, configuration))
- 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 provider."""
@@ -185,10 +276,25 @@
"Handle empty/simple declaration."
return ()
- def information(self, _context, keyface=None, configuration=None, key=None, annotation=None):
+ def information(self, _context, keyface=None, configuration=None, key=None, annotation=None, iniFiles=()):
"""Add a configuration to the information provider."""
+
+ # handle ini files
+ if iniFiles:
+ if keyface or configuration or key or annotation:
+ raise ConfigurationError('Attribute iniFiles does not allow other attributes.')
+
+ for path in iniFiles:
+ for configuration, data in iniFileToConfiguration(path, False):
+ _context.action(
+ discriminator = (
+ 'informationprovider.configuration', self._keyface, self._conface, configuration),
+ callable = provideConfiguration,
+ args = (self._keyface, self._conface, configuration, data),
+ )
+
# handle configuration
- if keyface and configuration is not None:
+ elif keyface and configuration is not None:
# preconditions
if not (keyface.providedBy(configuration) or type(configuration) is dict):
raise ConfigurationError('Data attribute must provide %s.' % keyface.__name__)
@@ -215,12 +321,29 @@
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."""
+
+
+def multiInformationProviderDirectives(_context, iniFiles=()):
+ """Ini-file based configurations for multi information provider."""
- for path in iniFiles:
- for keyface, configuration in iniFileToConfiguration(path):
- # register corresponding configuration information
- self.information(_context, keyface, configuration)
+ for path in iniFiles:
+ for configuration, keyface, conface, data in iniFileToConfiguration(path):
+ # register corresponding configuration information
+ # provide type as soon as possilbe
+ if not IKeyfaceType.providedBy(keyface):
+ provideInterface(None, keyface, IKeyfaceType)
+
+ if not IConfaceType.providedBy(conface):
+ provideInterface(None, conface, IConfaceType)
+
+ # ensure the corresponding information provider
+ ensureInformationProvider(keyface, conface)
+
+ _context.action(
+ discriminator = (
+ 'informationprovider.configuration', keyface, conface, configuration),
+ callable = provideConfiguration,
+ args = (keyface, conface, configuration, data),
+ )
\ 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 18:30:20 UTC (rev 67970)
+++ zope.generic/trunk/src/zope/generic/informationprovider/metadirectives.py 2006-05-04 18:56:14 UTC (rev 67971)
@@ -55,6 +55,23 @@
+class IIniFileDirective(Interface):
+ """Ini-file based configurations for multi information provider."""
+
+ iniFiles = Tokens(
+ title=_('*.ini-like File'),
+ description=_('Parse ((ConfigParser) configuration and face interfaces '
+ 'from sections resolving the pattern '
+ 'configuration:keyface at conface. The configuration data '
+ 'are retrieved from the corresponding options using '
+ 'IFromUnicode(field).fromUnicode() from the configuration '
+ 'fields.'),
+ required=False,
+ value_type=Path(constraint=lambda v: v.endswith('.ini'))
+ )
+
+
+
class IDescriptionDirective(IKeyfaceDirective):
"""Base information provider attributes."""
@@ -77,7 +94,7 @@
-class IInformationSubdirective(Interface):
+class IInformationSubdirective(IIniFileDirective):
"""Declare a certain information of an information provider."""
keyface = GlobalInterface(
@@ -106,14 +123,6 @@
)
-class IInformationsSubdirective(Interface):
- """Ini-file based configurations for an information provider."""
+class IMultiInformationProviderDirectives(IIniFileDirective):
+ """Ini-file based configurations for multi information providers."""
- 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'))
- )
More information about the Checkins
mailing list