diff --git a/agent/README.txt b/agent/README.txt index 3778fb4..60677d8 100644 --- a/agent/README.txt +++ b/agent/README.txt @@ -80,7 +80,7 @@ it with a default if not found, in one statement. 'loops' >>> sorted(config.transport.items()) - [('serverURL', 'http://loops.cy55.de'), ('userName', 'loops')] + [('__name__', 'transport'), ('serverURL', 'http://loops.cy55.de'), ('userName', 'loops')] We can output a configuration in a form that is ready for loading just by converting it to a string representation. @@ -112,11 +112,22 @@ for storage; normally it would be stored in the users home directory. transport.userName = 'loops' ui.web.port = 8081 -Cleaning up up... +The simplified syntax +--------------------- + + >>> config.load(''' + ... ui( + ... web( + ... port=11080, + ... ))''') + >>> print config.ui.web.port + 11080 + +Cleaning up +----------- >>> os.unlink(fn) - Scheduling ========== diff --git a/agent/config.py b/agent/config.py index fce202c..ced33a8 100644 --- a/agent/config.py +++ b/agent/config.py @@ -27,15 +27,21 @@ from zope.interface import implements from loops.agent.interfaces import IConfigurator -class Configurator(object): +_not_found = object() + + +class Configurator(dict): implements(IConfigurator) def __init__(self, *sections, **kw): for s in sections: - setattr(self, s, ConfigSection()) + setattr(self, s, ConfigSection(s)) self.filename = kw.get('filename') + def __getitem__(self, key): + return getattr(self, key, ConfigSection(key)) + def load(self, p=None, filename=None): if p is None: fn = self.getConfigFile(filename) @@ -45,7 +51,7 @@ class Configurator(object): f.close() if p is None: return - exec p in self.__dict__ + exec p in self def save(self, filename=None): fn = self.getConfigFile(filename) @@ -78,8 +84,14 @@ class Configurator(object): class ConfigSection(list): + __name__ = '???' + + def __init__(self, name=None): + if name is not None: + self.__name__ = name + def __getattr__(self, attr): - value = ConfigSection() + value = ConfigSection(attr) setattr(self, attr, value) return value @@ -99,12 +111,28 @@ class ConfigSection(list): 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 isinstance(value, (str, int)): + elif name != '__name__' and isinstance(value, (str, int)): result.append('%s.%s = %s' % (ident, name, repr(value))) diff --git a/agent/tests.py b/agent/tests.py index d6f0dd9..0b81ce0 100755 --- a/agent/tests.py +++ b/agent/tests.py @@ -13,9 +13,13 @@ from twisted.internet import reactor from twisted.internet.defer import Deferred from twisted.trial import unittest -from loops.agent.core import Agent from loops.agent.schedule import Job - +try: + from loops.agent.core import Agent # needs twisted.internet.task.coiterate + ignore = False +except ImportError: # wrong environment, skip all loops.agent tests + print 'Skipping loops.agent' + ignore = True baseDir = os.path.dirname(__file__) @@ -57,6 +61,8 @@ class Test(unittest.TestCase): def test_suite(): + if ignore: + return standard_unittest.TestSuite() # do nothing flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS return standard_unittest.TestSuite(( #standard_unittest.makeSuite(Test),