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 and store them in the content object's annotations.
>>> from zope.app.annotation.interfaces import IAttributeAnnotatable, IAnnotations
>>> from zope.app.annotation.attribute import AttributeAnnotations
>>> from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
>>> from zope.annotation.attribute import AttributeAnnotations
>>> component.provideAdapter(AttributeAnnotations, (SomeObject,), IAnnotations)
The configurator is called automatically from the controller if there is

View file

@ -166,5 +166,5 @@ Macros / renderers
>>> fieldRenderers = form.fieldRenderers
>>> 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']

View file

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

View file

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

View file

@ -3,7 +3,7 @@
import unittest, doctest
from zope.app.testing.functional import FunctionalTestCase
from zope.app.testing import setup
from zope.testbrowser import Browser
from zope.testbrowser.testing import Browser
from zope.app import component, intid, zapi
@ -23,7 +23,7 @@ class BrowserTest(FunctionalTestCase):
key = default.registrationManager.addRegistration(reg)
default.registrationManager[key].status = component.interfaces.registration.ActiveStatus
def test(self):
def test(self):
browser = Browser()
browser.handleErrors = False
browser.addHeader('Authorization', 'Basic mgr:mgrpw')
@ -38,7 +38,7 @@ class BrowserTest(FunctionalTestCase):
button = browser.getControl('Apply')
button.click()
self.assert_(browser.isHtml)
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS

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.DocFileSuite('adapter.txt', optionflags=flags),
doctest.DocFileSuite('aop.txt', optionflags=flags),
doctest.DocFileSuite('config.txt', optionflags=flags),
doctest.DocFileSuite('defer.txt', optionflags=flags),
doctest.DocFileSuite('format.txt', optionflags=flags),
doctest.DocFileSuite('property.txt', optionflags=flags),

View file

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