[Checkins] SVN: zope.component/branches/wosc-test-stacking/ Create stackable classes in advance so they are picklable
Wolfgang Schnerring
wosc at wosc.de
Thu Jun 9 07:02:52 EDT 2011
Log message for revision 121898:
Create stackable classes in advance so they are picklable
Changed:
U zope.component/branches/wosc-test-stacking/NOTES.txt
U zope.component/branches/wosc-test-stacking/src/zope/component/stackable.py
U zope.component/branches/wosc-test-stacking/src/zope/component/tests.py
-=-
Modified: zope.component/branches/wosc-test-stacking/NOTES.txt
===================================================================
--- zope.component/branches/wosc-test-stacking/NOTES.txt 2011-06-08 18:09:31 UTC (rev 121897)
+++ zope.component/branches/wosc-test-stacking/NOTES.txt 2011-06-09 11:02:51 UTC (rev 121898)
@@ -3,6 +3,9 @@
- persisting/pickling stackable registries
+- Name StackableBase methods with a prefix so they don't conflict with
+ delegated methods (e.g. pop).
+
- Tests for zope.component-Stacking: can we run the existing tests on a push
and then pop "level"? (Maybe use another existing application as a
cross-check, too).
@@ -17,9 +20,6 @@
- stackable.reset() needs to take into account "dying" stackables
-- don't create a new class object for each stackable() call
-- prettier class name, repr, etc.
-
- have a name or "stack context", so you can say push('zope.component')
- do we leak memory regarding unregistering of stackables?
Modified: zope.component/branches/wosc-test-stacking/src/zope/component/stackable.py
===================================================================
--- zope.component/branches/wosc-test-stacking/src/zope/component/stackable.py 2011-06-08 18:09:31 UTC (rev 121897)
+++ zope.component/branches/wosc-test-stacking/src/zope/component/stackable.py 2011-06-09 11:02:51 UTC (rev 121898)
@@ -2,42 +2,71 @@
import inspect
-def delegate(name):
- def inner(self, *args, **kw):
- return getattr(self.stack[-1], name)(*args, **kw)
- return inner
+class StackableBase(object):
+ def __init__(self, original):
+ self.stack = [original]
-def stackable(original):
- type_ = type(original)
+ def push(self):
+ self.stack.append(copy.copy(self.stack[-1]))
- class inner(object):
+ def pop(self):
+ self.stack.pop()
+ def can_pop(self):
+ return len(self.stack) > 1
+
+ def reset(self):
+ del self.stack[1:]
+
+ def __repr__(self):
+ return 'stackable:%r' % self.stack[-1]
+
+ def __reduce_ex__(self, protocol):
+ return (self.__class__, (), dict(stack=self.stack))
+
+ @classmethod
+ def delegate(cls, name):
+ def inner(self, *args, **kw):
+ return getattr(self.stack[-1], name)(*args, **kw)
+ return inner
+
+ @classmethod
+ def create_for(cls, type_):
+ exclude_methods = ['__getattribute__', '__setattr__']
+ overridden_methods = dict(
+ inspect.getmembers(cls, predicate=inspect.ismethod)).keys()
+ exclude_methods.extend(overridden_methods)
+
+ copied_methods = {}
+ # XXX ismethoddescriptor is correct for type_ in [dict, list], but
+ # probably not in general
for name in dict(
inspect.getmembers(type_, predicate=inspect.ismethoddescriptor)):
- if name in ['__getattribute__', '__setattr__']:
+ if name in exclude_methods:
continue
- locals()[name] = delegate(name)
+ copied_methods[name] = cls.delegate(name)
- def __init__(self, original):
- self.stack = [original]
+ return type(
+ 'Stackable%s' % type_.__name__.title(), (cls,), copied_methods)
- def push(self):
- self.stack.append(copy.copy(self.stack[-1]))
- def pop(self):
- self.stack.pop()
+SUPPORTED_TYPES = dict(
+ (type_, StackableBase.create_for(type_)) for type_ in [dict, list])
- def can_pop(self):
- return len(self.stack) > 1
+for type_ in SUPPORTED_TYPES.values():
+ locals()[type_.__name__] = type_
- def reset(self):
- del self.stack[1:]
- def __repr__(self):
- return 'stackable:%r' % self.stack[-1]
+def stackable(original):
+ type_ = type(original)
- stack = inner(original)
+ try:
+ factory = SUPPORTED_TYPES[type_]
+ except KeyError:
+ raise TypeError('%r is not stackable' % type_)
+
+ stack = factory(original)
REGISTRY.register(stack)
return stack
Modified: zope.component/branches/wosc-test-stacking/src/zope/component/tests.py
===================================================================
--- zope.component/branches/wosc-test-stacking/src/zope/component/tests.py 2011-06-08 18:09:31 UTC (rev 121897)
+++ zope.component/branches/wosc-test-stacking/src/zope/component/tests.py 2011-06-09 11:02:51 UTC (rev 121898)
@@ -1722,7 +1722,23 @@
zope.component.stackable.reset()
self.assertEqual([1], stack)
+ def test_is_persistable(self):
+ import tempfile
+ import ZODB
+ tmpfile = tempfile.NamedTemporaryFile(delete=True)
+ root = ZODB.DB(tmpfile.name).open().root()
+ orig = [1]
+ stack = zope.component.stackable.stackable(orig)
+ root['stack'] = stack
+ zope.component.stackable.push()
+ stack.append(2)
+ transaction.commit()
+ stack = root['stack']
+ self.assertEqual([1, 2], stack)
+ zope.component.stackable.pop()
+ self.assertEqual([1], stack)
+
from zope.interface import Interface
More information about the checkins
mailing list