从zope架构循环导入引用

时间:2012-09-05 17:24:13

标签: python schema plone zope circular-reference

我遇到的问题与this SO question非常相似,但我尝试应用这些先前的答案并没有通过,建议我将其作为一个新问题启动:

在下面的代码中,我定义了几个getChoices()函数,我认为这将推迟循环引用,但没有!?这有什么不对,好吗?

# ns.content/ns/content/foo.py
from zope import schema
from plone.directives import form
from z3c.relationfield.schema import Relation, RelationChoice
from plone.formwidget.contenttree import ObjPathSourceBinder

class IFoo(form.Schema):

    def getBarChoices():
        # avoiding circular refs...
        from bar import IBar
        return ObjPathSourceBinder(object_provides=IBar.__identifier__)

    barChoices = getBarChoices()
    form.widget(bar=AutocompleteFieldWidget)
    bar = Relation(source= barChoices,required=False)

# ns.content/ns/content/bar.py
from zope import schema
from plone.directives import form
from z3c.relationfield.schema import Relation, RelationChoice
from plone.formwidget.contenttree import ObjPathSourceBinder

class IBar(form.Schema):

    def getFooChoices():
        # avoiding circular refs...
        from foo import IFoo
        return ObjPathSourceBinder(object_provides=IFoo.__identifier__)

    fooChoices = getFooChoices()
    form.widget(foo=AutocompleteFieldWidget)
    foo = Relation(source= fooChoices,required=False)

resultingError = """
  File ".../buildout-cache/eggs/martian-0.11.3-py2.7.egg/martian/scan.py", line 217, in resolve
    __import__(used)
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 32, in <module>
    class IBar(form.Schema):
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 48, in IBar
    fooChoices = getFooChoices()
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 38, in getFooChoices
    from ns.content.foo import IFoo
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 33, in <module>
    class IFoo(form.Schema):
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 73, in IFoo
    barChoices = getBarChoices()
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 39, in getBarChoices
    from ns.content.bar import IBar
zope.configuration.xmlconfig.ZopeXMLConfigurationError: File ".../zeocluster/parts/client1/etc/site.zcml", line 16.2-16.23
    ZopeXMLConfigurationError: File ".../buildout-cache/eggs/Products.CMFPlone-4.2.0.1-py2.7.egg/Products/CMFPlone/configure.zcml", line 102.4-106.10
    ZopeXMLConfigurationError: File ".../zeocluster/src/ns.content/ns/content/configure.zcml", line 18.2-18.27
    ImportError: cannot import name IBar
"""

1 个答案:

答案 0 :(得分:4)

在定义班级getBarChoices()时,您在定义时调用IFoo。因此,在解析导致循环导入的from bar import IBar时将执行foo.py

据我所知,你基本上有两种选择:

1)使用字符串作为object_provides的标识符。

你使用IFoo.__identifier__已经做到了这一点,但是如果你把它设为静态而不是动态来消除你的循环依赖:

source = ObjPathSourceBinder(object_provides='ns.content.bar.IBar')
bar = Relation(source=source,required=False)

无需在IBar中导入foo.py。这有一个明显的缺点,即IBar的位置现在已在您的代码中进行了硬编码,因此每当您更改IBar的名称或位置时,您都需要在foo.py中更新其虚线名称

2)标记界面

另一种选择是让IFooIBar实现您保存在第三个文件中的标记接口,例如ns/content/interfaces.py。这样你就可以按照

的方式做点什么

<强> interfaces.py

from zope.interface import Interface

class IBarMarker(Interface):
    """Marker interface for IBar objects.
    """

class IFooMarker(Interface):
    """Marker interface for IFoo objects.
    """

<强> foo.py

from zope.interface import directlyProvides
from plone.directives import form
from plone.formwidget.contenttree import ObjPathSourceBinder
from plone.formwidget.autocomplete import AutocompleteFieldWidget
from z3c.relationfield.schema import RelationChoice

from ns.content.interfaces import IBarMarker
from ns.content.interfaces import IFooMarker


class IFoo(form.Schema):
    directlyProvides(IFooMarker)

    form.widget(bar=AutocompleteFieldWidget)
    bar = RelationChoice(source=ObjPathSourceBinder(
                            object_provides=IBarMarker.__identifier__),
                         required=False)

bar.py

class IBar(form.Schema):
    directlyProvides(IBarMarker)

    form.widget(foo=AutocompleteFieldWidget)
    foo = RelationChoice(source=ObjPathSourceBinder(
                            object_provides=IFooMarker.__identifier__),
                         required=False)