[Checkins] SVN: cipher.configstore/trunk/ - Implemented dependency support among stores at the same level of object.
Stephen Richter
cvs-admin at zope.org
Sat Oct 6 18:27:54 UTC 2012
Log message for revision 127926:
- Implemented dependency support among stores at the same level of object.
- Increased test coverage to over 90%.
Get ready for release.
Thanks goes to Jens who discretely pointed out to me that I might have
had checked out the code with the wrong URL, which I had. I used svn://
instead of svn+ssh://.
Changed:
U cipher.configstore/trunk/CHANGES.txt
U cipher.configstore/trunk/setup.py
U cipher.configstore/trunk/src/cipher/configstore/configstore.py
U cipher.configstore/trunk/src/cipher/configstore/configstore.txt
-=-
Modified: cipher.configstore/trunk/CHANGES.txt
===================================================================
--- cipher.configstore/trunk/CHANGES.txt 2012-10-06 08:33:16 UTC (rev 127925)
+++ cipher.configstore/trunk/CHANGES.txt 2012-10-06 18:27:50 UTC (rev 127926)
@@ -2,12 +2,14 @@
CHANGES
=======
-1.2.3 (unreleased)
+1.3.0 (2012-10-05)
------------------
-- Nothing changed yet.
+- Implemented dependency support among stores at the same level of object.
+- Increased test coverage to over 90%.
+
1.2.2 (2012-08-30)
------------------
Modified: cipher.configstore/trunk/setup.py
===================================================================
--- cipher.configstore/trunk/setup.py 2012-10-06 08:33:16 UTC (rev 127925)
+++ cipher.configstore/trunk/setup.py 2012-10-06 18:27:50 UTC (rev 127926)
@@ -23,7 +23,7 @@
setup(
name='cipher.configstore',
- version='1.2.3.dev0',
+ version='1.3.0',
url="http://pypi.python.org/pypi/cipher.configstore/",
author='Zope Foundation and Contributors',
author_email='zope-dev at zope.org',
Modified: cipher.configstore/trunk/src/cipher/configstore/configstore.py
===================================================================
--- cipher.configstore/trunk/src/cipher/configstore/configstore.py 2012-10-06 08:33:16 UTC (rev 127925)
+++ cipher.configstore/trunk/src/cipher/configstore/configstore.py 2012-10-06 18:27:50 UTC (rev 127926)
@@ -45,6 +45,42 @@
return dateutil.parser.parse(s).time()
+class StoreSorter(object):
+
+ NEW = 'new'
+ OPEN = 'open'
+ CLOSED = 'closed'
+
+ def __init__(self, stores):
+ self.stores = dict([(s.name, s) for s in stores])
+
+ def addStore(self, name, store):
+ if name in self.callstack:
+ raise interfaces.CyclicDependencyError(name)
+ self.callstack.append(name)
+ if name not in self.status:
+ self.status[name] = self.NEW
+ if self.status[name] == self.NEW:
+ self.status[name] = self.OPEN
+ for depName in store.dependencies:
+ if (depName not in self.status or
+ self.status[depName] is not self.CLOSED):
+ self.addStore(depName, self.stores[depName])
+ self.ordered.append(store)
+ self.status[name] = self.CLOSED
+ self.callstack.pop(-1)
+
+ def __call__(self):
+ self.status = {}
+ self.callstack = []
+ self.ordered = []
+
+ for name, store in self.stores.items():
+ self.addStore(name, store)
+
+ return self.ordered
+
+
class ConfigurationStore(object):
zope.interface.implements(interfaces.IConfigurationStore)
listValueSeparator = ', '
@@ -55,6 +91,12 @@
container = None
root = None
+ dependencies = ()
+
+ @property
+ def name(self):
+ return '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
+
def __init__(self, context, schema=None, section=None):
if self.schema is None:
self.schema = schema or zope.component.adaptedBy(self.__class__)[0]
@@ -144,6 +186,7 @@
changed_fields = self._load(config)
stores = zope.component.subscribers(
(self.context,), interfaces.IConfigurationStore)
+ stores = StoreSorter(stores)()
for store in stores:
if not isinstance(store, self.__class__):
store.root = self.root
Modified: cipher.configstore/trunk/src/cipher/configstore/configstore.txt
===================================================================
--- cipher.configstore/trunk/src/cipher/configstore/configstore.txt 2012-10-06 08:33:16 UTC (rev 127925)
+++ cipher.configstore/trunk/src/cipher/configstore/configstore.txt 2012-10-06 18:27:50 UTC (rev 127926)
@@ -15,7 +15,7 @@
>>> class Person(object):
... zope.interface.implements(IPerson)
- ... def __init__(self, fn, ln):
+ ... def __init__(self, fn=u'', ln=u''):
... self.firstName = fn
... self.lastName = ln
... self.nickname = None
@@ -274,3 +274,188 @@
>>> import os
>>> os.unlink(conf_fn)
+External Stores
+---------------
+
+External Configuration Stores allow configuration to be written to another
+file only leaving a reference in the current one. This allows complex
+configuration to be split up into multiple files.
+
+ >>> import tempfile, os
+ >>> conf_dir = tempfile.mkdtemp()
+ >>> os.mkdir(os.path.join(conf_dir, 'test'))
+
+ >>> class ExternalPersonStore(configstore.ExternalConfigurationStore):
+ ... schema = IPerson
+ ...
+ ... def get_config_dir(self):
+ ... return conf_dir
+ ...
+ ... def get_site(self):
+ ... return type('FakeSite', (), {'__name__': 'test'})()
+ ...
+ ... def get_filename(self):
+ ... return 'person.ini'
+
+ >>> store = ExternalPersonStore(stephan)
+
+We can now dump the configuration to a file:
+
+ >>> config = store.dump()
+ >>> config
+ <ConfigParser.RawConfigParser instance at ...>
+
+ >>> conf_fn = os.path.join(conf_dir, 'test', 'main.ini')
+ >>> config.write(open(conf_fn, 'w'))
+ >>> print open(conf_fn, 'r').read()
+ [IPerson]
+ config-path = test/person.ini
+
+ >>> ext_conf_fn = os.path.join(conf_dir, 'test', 'person.ini')
+ >>> print open(ext_conf_fn, 'r').read()
+ [general]
+ firstName = Stephan
+ lastName = Richter
+ nickname =
+ <BLANKLINE>
+ [address]
+ zip = 01754
+ <BLANKLINE>
+ [number:home]
+ name = home
+ number = 555-111-2222
+ <BLANKLINE>
+ [number:work]
+ name = work
+ number = 555-333-4444
+
+Let's now load the configuration again:
+
+ >>> stephan2 = Person()
+ >>> store = ExternalPersonStore(stephan2)
+ >>> store.load(config)
+
+ >>> stephan2.firstName
+ u'Stephan'
+ >>> stephan2.lastName
+ u'Richter'
+ >>> stephan2.nickname
+ u''
+
+Field Support
+-------------
+
+The configuration store supports several field types by default.
+
+ >>> store = configstore.ConfigurationStore(Person(), schema=IPerson)
+
+Time
+~~~~
+
+ >>> import datetime
+ >>> field = None
+
+ >>> store.dump_type_Time(datetime.time(3, 47), field)
+ '03:47'
+ >>> store.load_type_Time('03:47', field)
+ datetime.time(3, 47)
+
+ >>> store.dump_type_Time(datetime.time(15, 47), field)
+ '15:47'
+ >>> store.load_type_Time('15:47', field)
+ datetime.time(15, 47)
+
+Timedelta
+~~~~~~~~~
+
+ >>> field = None
+
+ >>> store.dump_type_Timedelta(datetime.timedelta(seconds=3661), field)
+ '1:01:01'
+ >>> store.load_type_Timedelta('1:01:01', field)
+ datetime.timedelta(0, 3661)
+
+ >>> store.load_type_Timedelta('', field) is None
+ True
+
+Text
+~~~~
+
+ >>> field = None
+
+ >>> store.dump_type_Text('foo\n\nbar', field)
+ 'foo\n<BLANKLINE>\nbar'
+
+ >>> store.load_type_Text('foo\n<BLANKLINE>\nbar', field)
+ 'foo\n\nbar'
+
+ >>> store.dump_type_Text(None, field)
+ ''
+
+Choice
+~~~~~~
+
+ >>> import zope.schema
+ >>> field = zope.schema.Choice(
+ ... vocabulary=zope.schema.vocabulary.SimpleVocabulary([
+ ... zope.schema.vocabulary.SimpleTerm(1, 'one'),
+ ... zope.schema.vocabulary.SimpleTerm(2, 'two')
+ ... ]))
+
+ >>> store.dump_type_Choice(1, field)
+ 'one'
+ >>> store.load_type_Choice('one', field)
+ 1
+
+ >>> store.dump_type_Choice(None, field)
+ ''
+ >>> store.load_type_Choice('', field) is None
+ True
+
+List
+~~~~
+
+ >>> field = None
+
+ >>> store.dump_type_List(['one', 'two', 'three'], field)
+ 'one, two, three'
+
+ >>> store.load_type_List('one, two, three', field)
+ ['one', 'two', 'three']
+
+ >>> store.dump_type_List(None, field)
+ ''
+ >>> store.load_type_List('', field)
+ []
+
+Tuple
+~~~~~
+
+ >>> field = None
+
+ >>> store.dump_type_Tuple(('one', 'two', 'three'), field)
+ 'one, two, three'
+
+ >>> store.load_type_Tuple('one, two, three', field)
+ ('one', 'two', 'three')
+
+ >>> store.dump_type_Tuple(None, field)
+ ''
+ >>> store.load_type_Tuple('', field)
+ ()
+
+Set
+~~~
+
+ >>> field = None
+
+ >>> store.dump_type_Set(set(['one', 'two', 'three']), field)
+ 'three, two, one'
+
+ >>> store.load_type_Set('one, two, three', field)
+ set(['three', 'two', 'one'])
+
+ >>> store.dump_type_Set(None, field)
+ ''
+ >>> store.load_type_Set('', field)
+ set([])
More information about the checkins
mailing list