i’m having a problem very similar to this SO question, but my attempts to apply these previous answers isn’t going thru and it was suggested i start it as a new question:
in the code below i define a couple of getChoices() functions that i thought would defer the circular refs, but no!? what’s wrong here, please?
# 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
"""
You’re calling
getBarChoices()at definition time, when defining the classIFoo. Sofrom bar import IBarwill be executed while parsingfoo.pyleading to the circular import.As far as I see it, you have basically two choices:
1) Use a string as identifier for object_provides.
You’re doing that already anyway by using
IFoo.__identifier__, but if you make it static instead of dynamic that will eliminate your circular dependencies:No need to import
IBarinfoo.py. This has the obvious disadvantage that the location ofIBaris now hardcoded in your code, so whenever you change the name or location ofIBaryou’ll need to update its dotted name infoo.py.2) Marker interfaces
The other alternative would be to let
IFooandIBarimplement marker interfaces that you keep in a third file,ns/content/interfaces.pyfor example. That way you could do something along the lines ofinterfaces.py
foo.py
bar.py