diff --git a/meta/README.txt b/meta/README.txt index 602d828..22d4aa2 100644 --- a/meta/README.txt +++ b/meta/README.txt @@ -23,6 +23,9 @@ be created as elements within the Options object. >>> config.i18n.languages ['de', 'en', 'it'] + >>> config('i18n.languages') + ['de', 'en', 'it'] + Loading options as Python code ------------------------------ diff --git a/meta/config.py b/meta/config.py index 93ea4c0..dd32d6b 100644 --- a/meta/config.py +++ b/meta/config.py @@ -22,8 +22,10 @@ Basic implementations for configuration options $Id$ """ +import os from zope.interface import implements +from cybertools.meta.element import Element from cybertools.meta.interfaces import IOptions, IConfigurator from cybertools.meta.namespace import AutoNamespace, Executor, ExecutionError @@ -32,6 +34,30 @@ class Options(AutoNamespace): implements(IOptions) + def __call__(self, key, default=None): + value = self + for part in key.split('.'): + value = getattr(value, part) + if isinstance(value, Element): + value = default + return value + + +class GlobalOptions(Options): + + _filename = None + _lastChange = None + + def __call__(self, key, default): + if self._filename is not None: + fn = self._filename + if os.path.exists(fn): + modified = os.path.getmtime(fn) + if self._lastChange is None or self._lastChange < modified: + Configurator(self).load(file=fn) + self._lastChange = modified + return super(GlobalOptions, self).__call__(key, default) + class Configurator(object): diff --git a/meta/element.py b/meta/element.py index a9b046d..22ed1dd 100644 --- a/meta/element.py +++ b/meta/element.py @@ -73,7 +73,7 @@ class Element(dict): return result def __setattr__(self, key, value): - if key in self.realAttributes: + if key in self.realAttributes or key.startswith('_'): super(Element, self).__setattr__(key, value) else: self[key] = value @@ -116,6 +116,8 @@ class AutoElement(Element): typeName = 'AutoElement' def __getattr__(self, key): + if key.startswith('_'): # no auto-creation for special attributes + raise AttributeError(key) result = self.get(key, _not_found) if result is _not_found: result = self.children.get(key, _not_found) diff --git a/meta/interfaces.py b/meta/interfaces.py index 78f5dad..39c7cbb 100644 --- a/meta/interfaces.py +++ b/meta/interfaces.py @@ -31,27 +31,24 @@ class IOptions(Interface): a file. """ - def __contains__(key): - """ Return True if this object provides the option identified - by the key given. - """ + def __call__(key): + """ Return the value belonging to the key given. The key may be a + dotted name - it will be splitted on dots and attributes + will be looked up in turn on the resulting objects. - def __iter__(): - """ Return an iterator over the option keys provided by this - object. - """ + Return None if no corresponding setting can be found. - def values(): - """ Return an iterator over all settings. + The method may also provide some fallback mechanism when + the element is not defined in the current object. """ def __getitem__(key): - """ Return the value belonging to the key given. + """ Return the value belonging to the key given. The key + must not contain dots. """ def __getattr__(key): - """ Return the value belonging to the key given - (same as ``__getitem__()``). + """ Return the value belonging to the key given. """ def __str__(): diff --git a/meta/namespace.py b/meta/namespace.py index 3db565b..70951eb 100644 --- a/meta/namespace.py +++ b/meta/namespace.py @@ -87,6 +87,8 @@ class AutoNamespace(BaseNamespace): return result def __getattr__(self, key): + if key.startswith('_'): # no auto-creation for special attributes + raise AttributeError(key) return self[key]