创建自定义Zope源的简单方法。
项目描述
源工厂
源工厂用于简化某些标准情况下的源创建。
源将向用户提供具有选择项的输入字段的过程分割成几个组件:上下文绑定器、源类、术语类和术语类。
这是正确的抽象,非常适合许多复杂情况。为了减少某些标准情况下的工作量,源工厂允许用户只定义获取值列表、获取要显示的标记和标题的业务相关代码。
简单情况
在最简单的情况下,您只需提供一个返回值列表的方法,并从BasicSourceFactory派生
>>> import zc.sourcefactory.basic >>> class MyStaticSource(zc.sourcefactory.basic.BasicSourceFactory): ... def getValues(self): ... return ['a', 'b', 'c']
调用源工厂时,我们得到一个源
>>> source = MyStaticSource() >>> import zope.schema.interfaces >>> zope.schema.interfaces.ISource.providedBy(source) True
值匹配工厂的getValues-方法
>>> list(source) ['a', 'b', 'c'] >>> 'a' in source True >>> len(source) 3
上下文源
有时我们需要上下文来确定值。在这种情况下,getValues方法获取一个参数context。
假设我们有一个包含要由源使用的数据的小对象
>>> class Context(object): ... values = []>>> import zc.sourcefactory.contextual >>> class MyDynamicSource( ... zc.sourcefactory.contextual.BasicContextualSourceFactory): ... def getValues(self, context): ... return context.values
实例化时,我们得到一个ContextSourceBinder
>>> binder = MyDynamicSource() >>> zope.schema.interfaces.IContextSourceBinder.providedBy(binder) True
将其绑定到上下文中,我们得到一个源
>>> context = Context() >>> source = binder(context) >>> zope.schema.interfaces.ISource.providedBy(source) True>>> list(source) []
修改上下文也会修改源中的数据
>>> context.values = [1,2,3,4] >>> list(source) [1, 2, 3, 4] >>> 1 in source True >>> len(source) 4
通过在调用绑定器时提供source_class参数,可以实现默认机械返回不同的源。还可以向源提供参数。
>>> class MultiplierSource(zc.sourcefactory.source.FactoredContextualSource): ... def __init__(self, factory, context, multiplier): ... super(MultiplierSource, self).__init__(factory, context) ... self.multiplier = multiplier ... ... def _get_filtered_values(self): ... for value in self.factory.getValues(self.context): ... yield self.multiplier * value >>> class MultiplierSourceFactory(MyDynamicSource): ... source_class = MultiplierSource >>> binder = MultiplierSourceFactory() >>> source = binder(context, multiplier=5) >>> list(source) [5, 10, 15, 20] >>> 5 in source True >>> len(source) 4
过滤
除了提供getValues方法外,您还可以提供一个filterValue方法,这将允许您逐步减少列表中的项。
如果您想拥有更具体的源(通过子类化),这些源具有相同的基本数据来源但应用了不同的过滤器,这非常有用。
>>> class FilteringSource(zc.sourcefactory.basic.BasicSourceFactory): ... def getValues(self): ... return iter(range(1,20)) ... def filterValue(self, value): ... return value % 2 >>> source = FilteringSource() >>> list(source) [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
子类化修改了过滤器,而不是原始数据
>>> class OtherFilteringSource(FilteringSource): ... def filterValue(self, value): ... return not value % 2 >>> source = OtherFilteringSource() >>> list(source) [2, 4, 6, 8, 10, 12, 14, 16, 18]
“in”运算符也应用于过滤值
>>> 2 in source True >>> 3 in source False
“len”也应用于过滤值
>>> len(source) 9
扩展
有时通过源可用的项的数量非常大。所以大,以至于您只有在绝对必要时才想要访问它们。这种情况之一是与源的真值测试。默认情况下,Python会调用__nonzero__来获取对象的布尔值,但如果该值不可用,则调用__len__来查看其返回值。这可能非常昂贵,因此我们想要确保它不会被调用。
>>> class MyExpensiveSource(zc.sourcefactory.basic.BasicSourceFactory): ... def getValues(self): ... yield 'a' ... raise RuntimeError('oops, iterated too far')>>> source = MyExpensiveSource()>>> bool(source) True
简单情况
在最简单的情况下,您只需提供一个返回值列表的方法,并从BasicSourceFactory派生
>>> import zc.sourcefactory.basic >>> class MyStaticSource(zc.sourcefactory.basic.BasicSourceFactory): ... def getValues(self): ... return ['a', 'b', 'c']
调用源工厂时,我们得到一个源
>>> source = MyStaticSource() >>> import zope.schema.interfaces >>> zope.schema.interfaces.ISource.providedBy(source) True
值匹配工厂的getValues-方法
>>> list(source) ['a', 'b', 'c'] >>> 'a' in source True >>> len(source) 3
关于ITerms标准适配器的警告
ITerms的标准适配器仅适用于您的getValues函数返回的值类型是同质的。在单个源中混合整数、持久性对象、字符串和unicode可能会创建非唯一的标记。在这种情况下,您必须提供一个自定义的getToken方法来提供唯一且无歧义的标记。
映射源值
有时源提供正确的对象选择,但我们想要讨论的实际值是那些对象的属性或计算视图。映射代理源帮助我们将源映射到不同的值空间。
我们从一个源开始
>>> source = [1,2,3,4,5]
我们提供了一个方法,将原始源中的值映射到我们想要的值(我们将数字映射到英文字母中的字符)
>>> map = lambda x: chr(x+96)
现在我们可以创建一个映射源
>>> from zc.sourcefactory.mapping import ValueMappingSource >>> mapped_source = ValueMappingSource(source, map) >>> list(mapped_source) ['a', 'b', 'c', 'd', 'e'] >>> len(mapped_source) 5 >>> 'a' in mapped_source True >>> 1 in mapped_source False
您还可以使用上下文相关的源
>>> def bindSource(context): ... return [1,2,3,4,5] >>> from zc.sourcefactory.mapping import ValueMappingSourceContextBinder >>> binder = ValueMappingSourceContextBinder(bindSource, map) >>> bound_source = binder(object()) >>> list(bound_source) ['a', 'b', 'c', 'd', 'e'] >>> len(bound_source) 5 >>> 'a' in bound_source True >>> 1 in bound_source False
扩展
有时通过源可用的项的数量非常大。所以大,以至于您只有在绝对必要时才想要访问它们。这种情况之一是与源的真值测试。默认情况下,Python会调用__nonzero__来获取对象的布尔值,但如果该值不可用,则调用__len__来查看其返回值。这可能非常昂贵,因此我们想要确保它不会被调用。
>>> class ExpensiveSource(object): ... def __len__(self): ... raise RuntimeError("oops, don't want to call __len__") ... ... def __iter__(self): ... return iter(range(999999))>>> expensive_source = ExpensiveSource() >>> mapped_source = ValueMappingSource(expensive_source, map) >>> bool(mapped_source) True
自定义构造函数
源工厂旨在尽可能自然地工作。在基类上使用自定义工厂方法(__new__)的一个副作用是,如果子类的构造函数(__init__)有不同的签名,子类可能会遇到困难。
zc.sourcefactory采取了额外措施,允许使用具有不同签名的自定义构造函数。
>>> import zc.sourcefactory.basic
>>> class Source(zc.sourcefactory.basic.BasicSourceFactory): ... ... def __init__(self, values): ... super(Source, self).__init__() ... self.values = values ... ... def getValues(self): ... return self.values
>>> source = Source([1, 2, 3]) >>> list(source) [1, 2, 3]
这对于上下文相关的源也是如此。这个例子有点愚蠢,但它表明它原则上是可以工作的
>>> import zc.sourcefactory.contextual >>> default_values = (4, 5, 6) >>> context_values = (6, 7, 8) >>> class ContextualSource( ... zc.sourcefactory.contextual.BasicContextualSourceFactory): ... ... def __init__(self, defaults): ... super(ContextualSource, self).__init__() ... self.defaults = defaults ... ... def getValues(self, context): ... return self.defaults + context
>>> contextual_source = ContextualSource(default_values)(context_values) >>> list(contextual_source) [4, 5, 6, 6, 7, 8]
源常见适配器
为了允许根据工厂特定地调整生成的源,一些可以作为适配器使用的标准接口被重新调整为使用(FactoredSource,SourceFactory)的多适配器。
ISourceQueriables
>>> from zc.sourcefactory.basic import BasicSourceFactory >>> class Factory(BasicSourceFactory): ... def getValues(self): ... return [1,2,3] >>> source = Factory()>>> from zope.schema.interfaces import ISourceQueriables >>> import zope.interface >>> @zope.interface.implementer(ISourceQueriables) ... class SourceQueriables(object): ... def __init__(self, source, factory): ... self.source = source ... self.factory = factory ... def getQueriables(self): ... return [('test', None)]>>> from zc.sourcefactory.source import FactoredSource >>> zope.component.provideAdapter(factory=SourceQueriables, ... provides=ISourceQueriables, ... adapts=(FactoredSource, Factory))>>> queriables = ISourceQueriables(source) >>> queriables.factory <Factory object at 0x...> >>> queriables.source <zc.sourcefactory.source.FactoredSource object at 0x...> >>> queriables.getQueriables() [('test', None)]
清理
>>> zope.component.getSiteManager().unregisterAdapter(factory=SourceQueriables, ... provided=ISourceQueriables, required=(FactoredSource, Factory)) True
由源工厂创建的源浏览器视图
使用源工厂创建的源已经包含了现成的术语和术语对象。
简单使用
让我们从一个简单的源工厂开始
>>> import zc.sourcefactory.basic >>> class DemoSource(zc.sourcefactory.basic.BasicSourceFactory): ... def getValues(self): ... return [b'a', b'b', b'c', b'd'] >>> source = DemoSource() >>> list(source) [b'a', b'b', b'c', b'd']
我们首先需要一个请求,然后我们可以将源适配到ITerms
>>> from zope.publisher.browser import TestRequest >>> import zope.browser.interfaces >>> import zope.component >>> request = TestRequest() >>> terms = zope.component.getMultiAdapter( ... (source, request), zope.browser.interfaces.ITerms) >>> terms <zc.sourcefactory.browser.source.FactoredTerms object at 0x...>
对于每个值,我们得到一个分解术语
>>> terms.getTerm(b'a') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> >>> terms.getTerm(b'b') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> >>> terms.getTerm(b'c') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> >>> terms.getTerm(b'd') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>
也允许使用Unicode值
>>> terms.getTerm('\xd3') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>
我们的术语与ITitledTokenizedTerm兼容
>>> import zope.schema.interfaces >>> zope.schema.interfaces.ITitledTokenizedTerm.providedBy( ... terms.getTerm('a')) True
在最简单的情况下,术语的标题是对象的字符串表示
>>> terms.getTerm('a').title 'a'
如果存在从值到IDCDescriptiveProperties的适配器,标题将从这个适配器检索
>>> import persistent >>> class MyObject(persistent.Persistent): ... custom_title = 'My custom title' ... _p_oid = 12 >>> class DCDescriptivePropertiesAdapter(object): ... def __init__(self, context): ... self.title = context.custom_title ... self.description = u"" >>> from zope.component import provideAdapter >>> from zope.dublincore.interfaces import IDCDescriptiveProperties >>> provideAdapter(DCDescriptivePropertiesAdapter, [MyObject], ... IDCDescriptiveProperties) >>> terms.getTerm(MyObject()).title 'My custom title'
扩展使用:提供自己的标题
您可以通过在源工厂上指定getTitle方法来确定值的标题,而不是依赖于字符串表示或IDCDescriptiveProperties适配器
>>> class DemoSourceWithTitles(DemoSource): ... def getTitle(self, value): ... return 'Custom title ' + value.custom_title >>> source2 = DemoSourceWithTitles() >>> terms2 = zope.component.getMultiAdapter( ... (source2, request), zope.browser.interfaces.ITerms) >>> o1 = MyObject() >>> o1.custom_title = u"Object one" >>> o2 = MyObject() >>> o2.custom_title = u"Object two" >>> terms2.getTerm(o1).title 'Custom title Object one' >>> terms2.getTerm(o2).title 'Custom title Object two'
扩展使用:提供自己的标记
您可以通过在源工厂上覆盖getToken方法来决定值的令牌,而不是依赖于默认适配器为您的值生成令牌
>>> class DemoObjectWithToken(object): ... token = None >>> o1 = DemoObjectWithToken() >>> o1.token = "one" >>> o2 = DemoObjectWithToken() >>> o2.token = "two">>> class DemoSourceWithTokens(DemoSource): ... values = [o1, o2] ... def getValues(self): ... return self.values ... def getToken(self, value): ... return value.token>>> source3 = DemoSourceWithTokens() >>> terms3 = zope.component.getMultiAdapter( ... (source3, request), zope.browser.interfaces.ITerms)>>> terms3.getTerm(o1).token 'one' >>> terms3.getTerm(o2).token 'two'
通过自定义令牌查找也有效
>>> terms3.getValue("one") is o1 True >>> terms3.getValue("two") is o2 True >>> terms3.getValue("three") Traceback (most recent call last): KeyError: "No value with token 'three'"
值映射源
待续
上下文源
让我们从一个可以用作上下文的对象开始
>>> zip_to_city = {'06112': 'Halle', ... '06844': 'Dessa'} >>> import zc.sourcefactory.contextual >>> class DemoContextualSource( ... zc.sourcefactory.contextual.BasicContextualSourceFactory): ... def getValues(self, context): ... return context.keys() ... def getTitle(self, context, value): ... return context[value] ... def getToken(self, context, value): ... return 'token-%s' % value >>> source = DemoContextualSource()(zip_to_city) >>> sorted(list(source)) ['06112', '06844']
让我们看看术语
>>> terms = zope.component.getMultiAdapter( ... (source, request), zope.browser.interfaces.ITerms) >>> terms <zc.sourcefactory.browser.source.FactoredContextualTerms object at 0x...>
对于每个值,我们得到一个具有正确标题的分解术语
>>> terms.getTerm('06112') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> >>> terms.getTerm('06112').title 'Halle' >>> terms.getTerm('06844') <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> >>> terms.getTerm('06844').title 'Dessa' >>> terms.getTerm('06844').token 'token-06844'
反之,我们也可以根据给定的令牌获取值
>>> terms.getValue('token-06844') '06844'
接口
FactoredSource和FactoredContextualSource都有相关的接口。
>>> from zc.sourcefactory import interfaces >>> from zc.sourcefactory import source >>> from zope import interface >>> interface.classImplements( ... source.FactoredSource, interfaces.IFactoredSource) >>> interface.classImplements( ... source.FactoredContextualSource, interfaces.IContextualSource)
标记
令牌是对象的识别表示,适用于在URL编码数据之间传输。
sourcefactory包提供了一些标准令牌生成器
>>> import zc.sourcefactory.browser.token
我们有字符串生成器
>>> zc.sourcefactory.browser.token.fromString('somestring') '1f129c42de5e4f043cbd88ff6360486f'
Unicode
啊,我必须用Unicode转义序列来写入元音,否则distutils将在准备上传到pypi时出现编码错误
>>> zc.sourcefactory.browser.token.fromUnicode( ... 'somestring with umlauts \u00F6\u00E4\u00FC') '45dadc304e0d6ae7f4864368bad74951'
整数
>>> zc.sourcefactory.browser.token.fromInteger(12) '12'
持久性
>>> import persistent >>> class PersistentDummy(persistent.Persistent): ... pass >>> p = PersistentDummy() >>> p._p_oid = 1234 >>> zc.sourcefactory.browser.token.fromPersistent(p) '1234'
如果对象是持久的但尚未添加到数据库中,它将被添加到其__parent__的数据库中
>>> root = rootFolder >>> p1 = PersistentDummy() >>> p1.__parent__ = root >>> zc.sourcefactory.browser.token.fromPersistent(p1) '0x01'
如果对象没有父对象,我们将失败
>>> p2 = PersistentDummy() >>> zc.sourcefactory.browser.token.fromPersistent(p2) Traceback (most recent call last): ... ValueError: Can not determine OID for <builtins.PersistentDummy object at 0x...>
安全代理对象将被解包以获取其oid或连接属性
>>> from zope.security.proxy import ProxyFactory >>> p3 = PersistentDummy() >>> root['p3'] = p3 >>> p3.__parent__ = root >>> p3p = ProxyFactory(p3) >>> p3p._p_jar Traceback (most recent call last): ... zope.security.interfaces.ForbiddenAttribute: ('_p_jar', <builtins.PersistentDummy object at 0x...>)>>> zc.sourcefactory.browser.token.fromPersistent(p3p) '0x02'
作为副作用,现在
>>> del p3.__parent__ >>> zc.sourcefactory.browser.token.fromPersistent(p3p) '0x02'
接口
>>> from zope.interface import Interface >>> class I(Interface): ... pass >>> zc.sourcefactory.browser.token.fromInterface(I) 'builtins.I'
更改
2.0 (2023-02-23)
添加对Python 3.8、3.9、3.10、3.11的支持。
放弃对Python 2.7、3.5、3.6的支持。
1.1 (2018-11-07)
添加对Python 3.6和3.7的支持。
放弃对Python 3.3和3.4的支持。
1.0.0 (2016-08-02)
声称支持Python 3.4和3.5。
放弃对Python 2.6的支持。
1.0.0a1 (2013-02-23)
添加了对Python 3.3的支持。
大幅减少测试依赖项,以使移植更容易。
用等效的zope.interface.implementer装饰器替换了已弃用的zope.interface.implements使用。
放弃对Python 2.4和2.5的支持。
0.8.0 (2013-10-04)
BasicSourceFactory 现在使用类变量来指定要创建的源类型。(与在 0.5.0 版本中为 ContextualSourceFactory 添加的机制相同)。
0.7.0 (2010-09-17)
使用 Python 的 doctest 而不是已弃用的 zope.testing.doctest。
使用 zope.keyreference 作为测试依赖项,而不是 zope.app.keyreference。
0.6.0 (2009-08-15)
将包主页更改为 PyPI 而不是 Subversion。
通过删除条件导入,移除了对 Zope 3.2 的支持。
使用 hashlib(Python 2.5 及以后版本)以避免弃用警告。
0.5.0 (2009-02-03)
FactoredContextualSourceBinder.__call__ 现在接受参数,这些参数指定传递给源类的参数。ContextualSourceFactory 现在使用类变量来指定要创建的 Source 类型。
使用 zope.intid 而不是 zope.app.intid。
已将电子邮件地址更正为 zope3-dev@zope.org 已弃用。
0.4.0 (2008-12-11)
移除了 zope.app.form 依赖项。将 ITerms 导入从 zope.app.form.browser.interfaces 更改为 zope.browser.interfaces。[projekt01]
0.3.5 (2008-12-08)
修复了 contexual 工厂 __new__ 中存在的错误,这将阻止子类使用具有不同签名的构造函数。[icemac]
0.3.4 (2008-08-27)
将包中的所有文档添加到长描述中,以便在 PyPI 中可读。[icemac]
0.3.3 (2008-06-10)
修复了 factories 的 __new__ 中存在的错误,这将阻止子类使用具有不同签名的构造函数。(感谢 Sebastian Wehrmann 提供补丁。)
0.3.2 (2008-04-09)
修复了由 ValueMappingSource 中缺少 __nonzero__ 引起的可扩展性错误。
0.3.1 (2008-02-12)
修复了由 BasicSourceFactory 中缺少 __nonzero__ 引起的可扩展性错误。
0.3.0 (??????????)
为接口中声明的属性添加了类级别默认值,以避免 Zope 2 安全机制对它们进行投诉。
0.2.1 (2007-07-10)
修复了处理特定令牌值解析的上下文令牌策略中的错误。
0.2.0 (2007-07-10)
添加了一个上下文令牌策略接口,允许 getToken 和 getValue 访问上下文以访问上下文源。
添加了一个上下文术语策略接口,允许 createTerm 和 getTitle 访问上下文以访问上下文源。
添加了对 Zope 3.2 和 Zope 2.9 的兼容性(通过 Five 1.3)。
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。