跳转到主要内容

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 (9.6 kB 查看哈希值)

上传时间

由以下组织支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面