We have a Dexterity-based content type that must inherit a field's default value from its parent. We use the following:
In the model:
<model xmlns="http://namespaces.plone.org/supermodel/schema"
xmlns:indexer="http://namespaces.plone.org/supermodel/indexer"
xmlns:form="http://namespaces.plone.org/supermodel/form">
<schema>
...
<field name="subjects" type="zope.schema.Tuple" indexer:searchable="true">
...
<defaultFactory>my.package.content.default_subjects</defaultFactory>
...
</field>
</schema>
</model>
The factory is declared like this:
from zope.schema.interfaces import IContextAwareDefaultFactory
...
@provider(IContextAwareDefaultFactory)
def default_subjects(context):
return getattr(context, 'subjects', ())
This works fine when running an instance:
(Pdb) context
<MyType at /Plone/folder>
(Pdb) type(context)
<type 'Acquisition.ImplicitAcquisitionWrapper'>
But fails when running tests as context is not wrapped:
(Pdb) context
<MyType at test>
(Pdb) type(context)
<class 'my.package.content.MyType'>
How can I solve this?
You are doing everything correctly. When in code you try to access subjects like that:
When
subjects
has never been set, the__getattr__
implementation of Dexterity starts its work. This__getattr__
magic for missing attributes is implemented by Python. It somehow looses the acquisition wrapper. After loosing the acquisition wrapper, neither aq_parent nor parent continue to work. In my tests, I was able to circumvent this by callingBut this is not satisfactory.
In view code you do not have this problem, because the view does not access the attribute via
object.subjects
at all, so the acquisition context never gets lost.I'll finish my analysis here, but I noted my findings in a bugreport for plone.dexterity. Maybe you want to provide a minimal test there: https://github.com/plone/plone.dexterity/issues/53