work in progress: loops.config for generic management of configuration options, settings, preferences
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2518 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
4d5bfed47f
commit
87ec9a2860
10 changed files with 194 additions and 13 deletions
|
@ -53,16 +53,19 @@ class CrawlingJob(BaseCrawlingJob):
|
||||||
for path, dirs, files in os.walk(directory):
|
for path, dirs, files in os.walk(directory):
|
||||||
if '.svn' in dirs:
|
if '.svn' in dirs:
|
||||||
del dirs[dirs.index('.svn')]
|
del dirs[dirs.index('.svn')]
|
||||||
for f in filter(files, pattern):
|
self.loadFiles(files, pattern)
|
||||||
filename = os.path.join(path, f)
|
|
||||||
mtime = datetime.fromtimestamp(os.path.getmtime(filename))
|
def loadFiles(self, files, pattern):
|
||||||
if mtime <= lastRun: # file not changed
|
for f in filter(files, pattern):
|
||||||
continue
|
filename = os.path.join(path, f)
|
||||||
meta = dict(
|
mtime = datetime.fromtimestamp(os.path.getmtime(filename))
|
||||||
path=filename,
|
if mtime <= lastRun: # file not changed
|
||||||
)
|
continue
|
||||||
self.collected.append(FileResource(filename, Metadata(meta)))
|
meta = dict(
|
||||||
yield None
|
path=filename,
|
||||||
|
)
|
||||||
|
self.collected.append(FileResource(filename, Metadata(meta)))
|
||||||
|
yield None
|
||||||
|
|
||||||
|
|
||||||
class FileResource(object):
|
class FileResource(object):
|
||||||
|
|
|
@ -433,7 +433,8 @@ class BaseView(GenericView, I18NView):
|
||||||
|
|
||||||
def registerDojoDateWidget(self):
|
def registerDojoDateWidget(self):
|
||||||
self.registerDojo()
|
self.registerDojo()
|
||||||
jsCall = 'dojo.require("dijit.form.DateTextBox");'
|
jsCall = ('dojo.require("dijit.form.DateTextBox"); '
|
||||||
|
'dojo.require("dijit.form.TimeTextBox");')
|
||||||
self.controller.macros.register('js-execute', jsCall, jsCall=jsCall)
|
self.controller.macros.register('js-execute', jsCall, jsCall=jsCall)
|
||||||
|
|
||||||
def registerDojoTextWidget(self):
|
def registerDojoTextWidget(self):
|
||||||
|
|
73
config/README.txt
Normal file
73
config/README.txt
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
===============================================================
|
||||||
|
loops - Linked Objects for Organization and Processing Services
|
||||||
|
===============================================================
|
||||||
|
|
||||||
|
Management of configuration settings and preferences.
|
||||||
|
|
||||||
|
($Id$)
|
||||||
|
|
||||||
|
|
||||||
|
Setting up a loops Site and Utilities
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Let's do some basic set up
|
||||||
|
|
||||||
|
>>> from zope import component, interface
|
||||||
|
>>> from zope.traversing.api import getName
|
||||||
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
|
and build a simple loops site with a concept manager and some concepts
|
||||||
|
(with a relation registry, a catalog, and all the type machinery - what
|
||||||
|
in real life is done via standard ZCML setup or via local utility
|
||||||
|
configuration):
|
||||||
|
|
||||||
|
>>> from loops.integrator.testsetup import TestSite
|
||||||
|
>>> t = TestSite(site)
|
||||||
|
>>> concepts, resources, views = t.setup()
|
||||||
|
>>> loopsRoot = concepts.getLoopsRoot()
|
||||||
|
|
||||||
|
|
||||||
|
Options Adapters
|
||||||
|
================
|
||||||
|
|
||||||
|
Global and site options
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
>>> from loops.config.base import LoopsOptions
|
||||||
|
>>> component.provideAdapter(LoopsOptions)
|
||||||
|
|
||||||
|
>>> from cybertools.meta.interfaces import IOptions
|
||||||
|
>>> opt = IOptions(loopsRoot)
|
||||||
|
>>> opt
|
||||||
|
<loops.config.base.LoopsOptions object ...>
|
||||||
|
>>> str(opt)
|
||||||
|
''
|
||||||
|
|
||||||
|
We now use the loops root object's options field to define
|
||||||
|
some options.
|
||||||
|
|
||||||
|
>>> loopsRoot.options = ['useVersioning', 'organize.tracking:changes, access']
|
||||||
|
>>> opt = IOptions(loopsRoot)
|
||||||
|
>>> print opt
|
||||||
|
organize(tracking=['changes', 'access'])
|
||||||
|
useVersioning=True
|
||||||
|
|
||||||
|
>>> opt.organize.tracking
|
||||||
|
['changes', 'access']
|
||||||
|
>>> opt.useVersioning
|
||||||
|
True
|
||||||
|
|
||||||
|
If we query an option that is not defined on the site level we get a
|
||||||
|
dummy element that corresponds to False.
|
||||||
|
|
||||||
|
>>> opt.i18n.languages
|
||||||
|
<AutoElement 'languages'>
|
||||||
|
>>> bool(opt.i18n.languages)
|
||||||
|
False
|
||||||
|
|
||||||
|
|
||||||
|
Fin de partie
|
||||||
|
=============
|
||||||
|
|
||||||
|
>>> placefulTearDown()
|
4
config/__init__.py
Normal file
4
config/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
68
config/base.py
Normal file
68
config/base.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Adapters and others classes for analyzing resources.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope import component
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.traversing.api import getName, getParent
|
||||||
|
|
||||||
|
from cybertools.meta.config import Options
|
||||||
|
from cybertools.meta.namespace import Executor, ExecutionError
|
||||||
|
from cybertools.typology.interfaces import IType
|
||||||
|
from loops.interfaces import ILoops
|
||||||
|
|
||||||
|
|
||||||
|
class LoopsOptions(Options):
|
||||||
|
|
||||||
|
adapts(ILoops)
|
||||||
|
|
||||||
|
builtins = Options.builtins + ('True', 'False')
|
||||||
|
True, False = True, False
|
||||||
|
|
||||||
|
def __init__(self, context, *args, **kw):
|
||||||
|
self.context = context
|
||||||
|
super(LoopsOptions, self).__init__(*args, **kw)
|
||||||
|
self.loadContextOptions()
|
||||||
|
|
||||||
|
def parseContextOptions(self):
|
||||||
|
def result():
|
||||||
|
for opt in self.context.options:
|
||||||
|
parts = opt.split(':', 1)
|
||||||
|
key = parts[0].strip()
|
||||||
|
if len(parts) == 1:
|
||||||
|
value = 'True'
|
||||||
|
else:
|
||||||
|
value = repr([p.strip() for p in parts[1].split(',')])
|
||||||
|
yield '='.join((key, value))
|
||||||
|
return '\n'.join(result())
|
||||||
|
|
||||||
|
def loadContextOptions(self):
|
||||||
|
code = self.parseContextOptions()
|
||||||
|
rc = Executor(self).execute(code)
|
||||||
|
if rc:
|
||||||
|
raise ExecutionError('\n' + result)
|
||||||
|
|
||||||
|
#def __getitem__(self, key):
|
||||||
|
# opt = self.baseOptions.get(key)
|
||||||
|
# return opt
|
23
config/tests.py
Executable file
23
config/tests.py
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
import unittest, doctest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
|
from zope.interface.verify import verifyClass
|
||||||
|
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
"Basic tests for the config sub-package."
|
||||||
|
|
||||||
|
def testSomething(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
|
return unittest.TestSuite((
|
||||||
|
unittest.makeSuite(Test),
|
||||||
|
DocFileSuite('README.txt', optionflags=flags),
|
||||||
|
))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='test_suite')
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -54,6 +54,8 @@ class LanguageInfo(object):
|
||||||
if opt.startswith('languages:'):
|
if opt.startswith('languages:'):
|
||||||
return opt[len('languages:'):].split(',')
|
return opt[len('languages:'):].split(',')
|
||||||
return []
|
return []
|
||||||
|
# new implementation:
|
||||||
|
# return IOptions(self.context).i18n.languages
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def defaultLanguage(self):
|
def defaultLanguage(self):
|
||||||
|
|
|
@ -121,6 +121,8 @@ class I18NAdapterBase(AdapterBase):
|
||||||
tp = IType(self.context)
|
tp = IType(self.context)
|
||||||
attrs = tp.optionsDict.get('i18nattributes', '')
|
attrs = tp.optionsDict.get('i18nattributes', '')
|
||||||
return [attr.strip() for attr in attrs.split(',')]
|
return [attr.strip() for attr in attrs.split(',')]
|
||||||
|
# new implementation:
|
||||||
|
# return self.options.i18n.attributes
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
self.checkAttr(attr)
|
self.checkAttr(attr)
|
||||||
|
|
|
@ -60,8 +60,8 @@ class Events(ConceptView):
|
||||||
cm = self.loopsRoot.getConceptManager()
|
cm = self.loopsRoot.getConceptManager()
|
||||||
tEvent = cm['event']
|
tEvent = cm['event']
|
||||||
hasType = cm.getTypePredicate()
|
hasType = cm.getTypePredicate()
|
||||||
sort = lambda x: x.adapted.start
|
|
||||||
now = datetime.today()
|
now = datetime.today()
|
||||||
|
sort = lambda x: x.adapted.start or now
|
||||||
relViews = (self.childViewFactory(r, self.request, contextIsSecond=True)
|
relViews = (self.childViewFactory(r, self.request, contextIsSecond=True)
|
||||||
for r in tEvent.getChildRelations([hasType], sort=None))
|
for r in tEvent.getChildRelations([hasType], sort=None))
|
||||||
return sorted((rv for rv in relViews
|
return sorted((rv for rv in relViews
|
||||||
|
|
|
@ -47,11 +47,16 @@ class ChangeManager(object):
|
||||||
return
|
return
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def options(self):
|
||||||
|
return IOptions(self.context)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def valid(self):
|
def valid(self):
|
||||||
return not (self.context is None or
|
return not (self.context is None or
|
||||||
self.storage is None or
|
self.storage is None or
|
||||||
self.person is None)
|
self.person is None)
|
||||||
|
# and 'changes' in self.options.tracking
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def loopsRoot(self):
|
def loopsRoot(self):
|
||||||
|
|
Loading…
Add table
Reference in a new issue