added util.config (experimental); clean-up of doctests

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2103 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-10-09 05:50:38 +00:00
parent e8db37544f
commit caf8b60b83
9 changed files with 255 additions and 7 deletions

View file

@ -171,8 +171,8 @@ The default configurator uses attribute annotations for retrieving view
properties; that means that there could be a form somewhere to edit those properties; that means that there could be a form somewhere to edit those
properties and store them in the content object's annotations. properties and store them in the content object's annotations.
>>> from zope.app.annotation.interfaces import IAttributeAnnotatable, IAnnotations >>> from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
>>> from zope.app.annotation.attribute import AttributeAnnotations >>> from zope.annotation.attribute import AttributeAnnotations
>>> component.provideAdapter(AttributeAnnotations, (SomeObject,), IAnnotations) >>> component.provideAdapter(AttributeAnnotations, (SomeObject,), IAnnotations)
The configurator is called automatically from the controller if there is The configurator is called automatically from the controller if there is

View file

@ -166,5 +166,5 @@ Macros / renderers
>>> fieldRenderers = form.fieldRenderers >>> fieldRenderers = form.fieldRenderers
>>> sorted(fieldRenderers.keys()) >>> sorted(fieldRenderers.keys())
[u'field', u'field_spacer', u'fields', u'form', u'input_dropdown', [u'field', u'field_spacer', u'fields', u'form', u'input_date', u'input_dropdown',
u'input_fileupload', u'input_password', u'input_textarea', u'input_textline'] u'input_fileupload', u'input_password', u'input_textarea', u'input_textline']

View file

@ -33,6 +33,9 @@ from cybertools.composer.schema.schema import Schema
class SchemaFactory(object): class SchemaFactory(object):
""" Creates a cybertools.composer schema from an
interface (a zope.schema schema).
"""
implements(ISchemaFactory) implements(ISchemaFactory)
adapts(Interface) adapts(Interface)

View file

@ -95,6 +95,7 @@ fieldTypes = SimpleVocabulary((
fieldRenderer='field_spacer', storeData=False), fieldRenderer='field_spacer', storeData=False),
)) ))
# TODO: move this to organize.service...
standardFieldNames = SimpleVocabulary(( standardFieldNames = SimpleVocabulary((
SimpleTerm('', '', 'Not selected'), SimpleTerm('', '', 'Not selected'),
SimpleTerm('lastName', 'lastName', 'Last name'), SimpleTerm('lastName', 'lastName', 'Last name'),

View file

@ -3,7 +3,7 @@
import unittest, doctest import unittest, doctest
from zope.app.testing.functional import FunctionalTestCase from zope.app.testing.functional import FunctionalTestCase
from zope.app.testing import setup from zope.app.testing import setup
from zope.testbrowser import Browser from zope.testbrowser.testing import Browser
from zope.app import component, intid, zapi from zope.app import component, intid, zapi

143
util/config.py Normal file
View file

@ -0,0 +1,143 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Formulating configuration options.
$Id$
"""
import os
from zope.interface import implements
_not_found = object()
class Configurator(dict):
filenamePrefix = 'cybertools'
def __init__(self, *sections, **kw):
for s in sections:
setattr(self, s, ConfigSection(s))
self.filename = kw.get('filename')
def __getitem__(self, key):
item = getattr(self, key, _not_found)
if item is _not_found:
item = ConfigSection(key)
setattr(self, key, item)
return item
def load(self, p=None, filename=None):
if p is None:
fn = self.getConfigFile(filename)
if fn is not None:
f = open(fn, 'r')
p = f.read()
f.close()
if p is None:
return
exec p in self
def save(self, filename=None):
fn = self.getConfigFile(filename)
if fn is None:
fn = self.getDefaultConfigFile()
if fn is not None:
f = open(fn, 'w')
f.write(repr(self))
f.close()
def __repr__(self):
result = []
for name, value in self.__dict__.items():
if isinstance(value, ConfigSection):
value.collect(name, result)
return '\n'.join(sorted(result))
def getConfigFile(self, filename=None):
if filename is not None:
self.filename = filename
if self.filename is None:
fn = self.getDefaultConfigFile()
if os.path.isfile(fn):
self.filename = fn
return self.filename
def getDefaultConfigFile(self):
return os.path.join(os.path.expanduser('~'),
'.%s.cfg' % self.filenamePrefix)
class ConfigSection(list):
__name__ = '???'
def __init__(self, name=None):
if name is not None:
self.__name__ = name
def __getattr__(self, attr):
value = ConfigSection(attr)
setattr(self, attr, value)
return value
def __getitem__(self, idx):
while idx >= len(self):
self.append(ConfigSection())
return list.__getitem__(self, idx)
def setdefault(self, attr, value):
if attr not in self.__dict__:
setattr(self, attr, value)
return value
return getattr(self, attr)
def items(self):
for name, value in self.__dict__.items():
if isinstance(value, (str, int)):
yield name, value
def __call__(self, *args, **kw):
for s in args:
if isinstance(s, ConfigSection):
# should we update an existing entry?
#old = getattr(self, s.__name__, None)
#if old is not None: # this would have to be done recursively
# old.__dict__.update(s.__dict__)
# for elem in s:
# old.append(elem)
#else:
# or just keep the new one?
setattr(self, s.__name__, s)
for k, v in kw.items():
setattr(self, k, v)
return self
def collect(self, ident, result):
for idx, element in enumerate(self):
element.collect('%s[%i]' % (ident, idx), result)
for name, value in self.__dict__.items():
if isinstance(value, ConfigSection):
value.collect('%s.%s' % (ident, name), result)
elif name != '__name__' and isinstance(value, (str, int)):
result.append('%s.%s = %s' % (ident, name, repr(value)))

100
util/config.txt Normal file
View file

@ -0,0 +1,100 @@
=============================
Setting Configuration Options
=============================
$Id$
>>> from cybertools import util
>>> from cybertools.util.config import Configurator
>>> config = Configurator()
>>> config.load('transport.serverURL = "http://demo.cy55.de"')
>>> config.transport.serverURL
'http://demo.cy55.de'
This setting may also contain indexed access; thus we can model
configuration parameters with multiple instances (like crawling
jobs).
>>> config.load('''
... crawl[0].type = "filesystem"
... crawl[0].directory = "documents/projects"
... ''')
>>> config.crawl[0].type
'filesystem'
>>> config.crawl[0].directory
'documents/projects'
Subsections are created automatically when they are first accessed.
>>> config.load('ui.web.port = 8081')
>>> config.ui.web.port
8081
The ``setdefault()`` method allows to retrieve a value and set
it with a default if not found, in one statement.
>>> config.ui.web.setdefault('port', 8080)
8081
>>> config.transport.setdefault('userName', 'demo')
'demo'
>>> sorted(config.transport.items())
[('__name__', 'transport'), ('serverURL', 'http://demo.cy55.de'),
('userName', 'demo')]
We can output a configuration in a form that is ready for loading
just by converting it to a string representation.
>>> print config
crawl[0].directory = 'documents/projects'
crawl[0].type = 'filesystem'
transport.serverURL = 'http://demo.cy55.de'
transport.userName = 'demo'
ui.web.port = 8081
The configuration may also be saved to a file -
for testing purposes let's use the cybertools.util package directory
for storage; normally it would be stored in the users home directory.
>>> import os
>>> os.environ['HOME'] = os.path.dirname(util.__file__)
>>> config.save()
>>> fn = config.getDefaultConfigFile()
>>> fn
'....cybertools.cfg'
>>> print open(fn).read()
crawl[0].directory = 'documents/projects'
crawl[0].type = 'filesystem'
transport.serverURL = 'http://demo.cy55.de'
transport.userName = 'demo'
ui.web.port = 8081
The simplified syntax
---------------------
>>> config.load('''
... ui(
... web(
... port=11080,
... ))
... crawl[1](
... type='outlook',
... folder='inbox',
... )
... ''')
>>> config.ui.web.port
11080
>>> config.crawl[1].type
'outlook'
>>> #print config
Cleaning up
-----------
>>> os.unlink(fn)

View file

@ -20,6 +20,7 @@ def test_suite():
#doctest.DocTestSuite(cybertools.util.property, optionflags=flags), #doctest.DocTestSuite(cybertools.util.property, optionflags=flags),
doctest.DocFileSuite('adapter.txt', optionflags=flags), doctest.DocFileSuite('adapter.txt', optionflags=flags),
doctest.DocFileSuite('aop.txt', optionflags=flags), doctest.DocFileSuite('aop.txt', optionflags=flags),
doctest.DocFileSuite('config.txt', optionflags=flags),
doctest.DocFileSuite('defer.txt', optionflags=flags), doctest.DocFileSuite('defer.txt', optionflags=flags),
doctest.DocFileSuite('format.txt', optionflags=flags), doctest.DocFileSuite('format.txt', optionflags=flags),
doctest.DocFileSuite('property.txt', optionflags=flags), doctest.DocFileSuite('property.txt', optionflags=flags),

View file

@ -22,7 +22,7 @@ Generic template base class.
$Id$ $Id$
""" """
from zope.app.traversing.adapters import DefaultTraversable from zope.traversing.adapters import DefaultTraversable
from zope import component from zope import component