Zope3的容器代理实现
项目描述
此包为Zope3提供了一个代理容器实现。
z3c.proxy
例如,我们可以代理从zope的btree容器派生的常规容器
>>> from zope.container.interfaces import IContainer >>> from zope.container.btree import BTreeContainer >>> container = BTreeContainer() >>> container.__name__, container.__parent__ = u'c1', u'p1'>>> from z3c.proxy import interfaces >>> from z3c.proxy.container import LocationProxy >>> from z3c.proxy.container import ContainerLocationProxy >>> proxy = ContainerLocationProxy(container)
代理的名称和父级为None。代理提供IContainer
>>> proxy.__name__ is None True >>> proxy.__parent__ is None True >>> IContainer.providedBy(proxy) True >>> interfaces.IContainerLocationProxy.providedBy(proxy) True
首先我们检查空代理
>>> proxy['x'] Traceback (most recent call last): ... KeyError: 'x'>>> 'x' in proxy False>>> proxy.has_key('x') 0>>> [key for key in proxy.keys()] []>>> [item for item in proxy.items()] []>>> proxy.get('x') is None True>>> iterator = iter(proxy) >>> iterator.next() Traceback (most recent call last): ... StopIteration>>> proxy.values() []>>> len(proxy) 0>>> del proxy['x'] Traceback (most recent call last): ... KeyError: 'x'>>> from zope.container.contained import Contained >>> proxy['x'] = x = Contained()
现在我们添加了第一个项目。此项目应添加到容器中。其名称将为x,其父级是容器本身
>>> x is container['x'] True>>> x.__name__ u'x'>>> x.__parent__ is container True
如果我们通过代理查找‘x’,我们不会得到空白的‘x’,而是代理的‘x’。代理不是‘x’,而只是与‘x’相等
>>> x is proxy['x'] False>>> x == proxy['x'] True>>> x1 = proxy['x'] >>> from zope.proxy import isProxy >>> isProxy(x1) True>>> isinstance(x1, LocationProxy) True
代理的‘x’仍然具有相同的名称,但没有相同的父级
>>> x1.__name__ u'x'>>> x1.__parent__ is container False>>> x1.__parent__ is proxy True
如果我们向容器中添加第二个项目,它也应出现在代理中。但此项目作为容器位置代理进行代理
>>> container['y'] = y = BTreeContainer() >>> y1 = proxy['y'] >>> y1 is y False>>> y1 == y True>>> isinstance(y1, ContainerLocationProxy) True
容器位置代理能够代理嵌套对象的定位
>>> proxy['y']['z'] = z = Contained() >>> container['y']['z'] is z True>>> z1 = y1['z'] >>> z1 is z False>>> z1 == z True>>> isinstance(z1, LocationProxy) True>>> z1.__parent__ is y1 True
最后我们检查代理的所有其他方法
>>> 'x' in proxy True>>> proxy.has_key('x') 1>>> keys = [key for key in proxy.keys()]; keys.sort(); keys [u'x', u'y']>>> items = [item for item in proxy.items()]; items.sort() >>> items == [(u'x', x), (u'y', y)] True>>> proxy.get('x') == x True>>> iterator = iter(proxy) >>> iterator.next() in proxy True>>> iterator.next() in proxy True>>> iterator.next() Traceback (most recent call last): ... StopIteration>>> values = proxy.values(); values.sort(); >>> x in values, y in values (True, True)>>> len(proxy) 2>>> del proxy['x'] >>> 'x' in proxy False
ObjectMover
要使用对象移动器,将包含的 对象 传递给类。包含的 对象 应实现 IContained。它应包含在一个具有 INameChooser 适配器的容器中。
设置测试容器和代理
>>> from zope.interface import implements >>> from zope.container.interfaces import INameChooser >>> from zope.copypastemove import ExampleContainer >>> from z3c.proxy.container import ProxyAwareObjectMover>>> class ContainerLocationProxyStub(ContainerLocationProxy): ... ... implements(INameChooser) ... ... def chooseName(self, name, ob): ... while name in self: ... name += '_' ... return name>>> container = ExampleContainer() >>> container2 = ExampleContainer()>>> ob = Contained() >>> proxy = ContainerLocationProxyStub(container) >>> proxy[u'foo'] = ob >>> ob = proxy[u'foo'] >>> mover = ProxyAwareObjectMover(ob)
除了移动对象之外,对象移动器还可以告诉您对象是否可移动
>>> mover.moveable() 1
至少到目前为止,它们总是是这样的。一个更好的问题是,我们是否可以移动到特定的容器。目前,我们总是可以移动到同一类的容器
>>> proxy2 = ContainerLocationProxyStub(container2) >>> mover.moveableTo(proxy2) 1>>> mover.moveableTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container.
当然,一旦我们决定可以移动一个对象,我们就可以使用移动器来这样做
>>> mover.moveTo(proxy2) u'foo'>>> list(proxy) []>>> list(proxy2) [u'foo']>>> ob = proxy2[u'foo'] >>> ob.__parent__ is proxy2 True
我们还可以指定一个名称
>>> mover.moveTo(proxy2, u'bar') u'bar'>>> list(proxy2) [u'bar']>>> ob = proxy2[u'bar'] >>> ob.__parent__ is proxy2 True>>> ob.__name__ u'bar'
但如果该名称已被使用,我们可能不能使用给定的相同名称
>>> proxy2[u'splat'] = 1 >>> mover.moveTo(proxy2, u'splat') u'splat_'>>> l = list(proxy2) >>> l.sort() >>> l [u'splat', u'splat_']>>> ob = proxy2[u'splat_'] >>> ob.__name__ u'splat_'
如果我们尝试移动到无效的容器,我们将得到一个错误
>>> mover.moveTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container.
ObjectCopier
要使用对象复制器,将包含的 对象 传递给类。包含的 对象 应该实现 IContained。它应该包含在一个具有适配器到 INameChooser 的容器中。
设置测试容器和代理
>>> from z3c.proxy.container import ProxyAwareObjectCopier >>> class ContainerLocationProxyStub(ContainerLocationProxy): ... ... implements(INameChooser) ... ... def chooseName(self, name, ob): ... while name in self: ... name += '_' ... return name>>> container = ExampleContainer() >>> container2 = ExampleContainer()>>> proxy = ContainerLocationProxyStub(container) >>> proxy[u'foo'] = ob = Contained() >>> ob = proxy[u'foo'] >>> copier = ProxyAwareObjectCopier(ob)
除了移动对象,对象复制器还可以告诉你对象是否可以移动
>>> copier.copyable() 1
至少到目前为止,它们总是是这样的。一个更好的问题是,我们是否可以将对象复制到特定的容器。目前,我们总是可以将对象复制到同一类的容器
>>> proxy2 = ContainerLocationProxyStub(container2) >>> copier.copyableTo(proxy2) 1>>> copier.copyableTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container.
当然,一旦我们决定可以复制一个对象,我们就可以使用复制器来这样做
>>> copier.copyTo(proxy2) u'foo'>>> list(proxy) [u'foo']>>> list(proxy2) [u'foo']>>> ob.__parent__ is proxy 1>>> proxy2[u'foo'] is ob 0>>> proxy2[u'foo'].__parent__ is proxy2 1>>> proxy2[u'foo'].__name__ u'foo'
我们还可以指定一个名称
>>> copier.copyTo(proxy2, u'bar') u'bar'>>> l = list(proxy2) >>> l.sort() >>> l [u'bar', u'foo']>>> ob.__parent__ is proxy 1>>> proxy2[u'bar'] is ob 0>>> proxy2[u'bar'].__parent__ is proxy2 1>>> proxy2[u'bar'].__name__ u'bar'
但如果该名称已被使用,我们可能不能使用给定的相同名称
>>> copier.copyTo(proxy2, u'bar') u'bar_'>>> l = list(proxy2) >>> l.sort() >>> l [u'bar', u'bar_', u'foo']>>> proxy2[u'bar_'].__name__ u'bar_'
如果我们尝试复制到无效的容器,我们将得到一个错误
>>> copier.copyTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container.
ProxyAwareContainerItemRenamer
此适配器使用 IObjectMover 将同一容器内的项目移动到不同的名称。我们需要首先设置一个 IObjectMover 的适配器
设置测试容器和代理
>>> from zope.container.sample import SampleContainer >>> from zope.copypastemove import ContainerItemRenamer >>> from zope.copypastemove import IObjectMover >>> from z3c.proxy.container import ProxyAwareContainerItemRenamer>>> import zope.component >>> from zope.container.interfaces import IContained >>> zope.component.provideAdapter(ProxyAwareObjectMover, [IContained], ... IObjectMover)>>> class ContainerLocationProxyStub(ContainerLocationProxy): ... ... implements(INameChooser) ... ... def chooseName(self, name, ob): ... while name in self: ... name += '_' ... return name
要重命名容器中的项目,实例化一个带有容器的 ContainerItemRenamer
>>> container = SampleContainer() >>> proxy = ContainerLocationProxyStub(container) >>> renamer = ProxyAwareContainerItemRenamer(container)
在这个例子中,我们将项目“foo”重命名为“bar”
>>> from z3c.proxy.container import _unproxy >>> foo = Contained() >>> proxy['foo'] = foo >>> proxy['foo'] == _unproxy(foo) True
到“bar”
>>> renamer.renameItem('foo', 'bar') >>> proxy['foo'] is foo Traceback (most recent call last): KeyError: 'foo'>>> proxy['bar'] == _unproxy(foo) True
如果被重命名的项目不在容器中,将引发 NotFoundError
>>> renamer.renameItem('foo', 'bar') # doctest:+ELLIPSIS Traceback (most recent call last): ItemNotFoundError: (<...SampleContainer...>, 'foo')
如果新的项目名称已存在,将引发 DuplicationError
>>> renamer.renameItem('bar', 'bar') Traceback (most recent call last): DuplicationError: bar is already in use
CHANGES
0.6.1 (2010-08-23)
在 long_description 中添加了 doctest 以在 PyPI 上渲染。
0.6.0 (2010-08-23)
用 zope.container 替换了 zope.app.container。
使用 Python 的 doctest 模块代替已弃用的 zope.testing.doctestunit。
0.5.0 (2008-04-12)
初始发布
项目详情
z3c.proxy-0.6.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d8c8cb09747ace2c2634effcd7979f3f192c9f9a65bb4fd8baf24c103af94c7d |
|
MD5 | 84883a54f6377572b28aa0a0705240d1 |
|
BLAKE2b-256 | f0ad9493d5f4a7761f67349ffdd883a61c6f179d258f1a9d830fd444ff11a9e9 |