zopefoundation / z3c.form

An advanced form and widget framework for Zope 3
Other
8 stars 39 forks source link

field.bind, even with ignoreContext #48

Closed thet closed 2 years ago

thet commented 8 years ago

I got an error with field.bind(self.context), where context was nothing the field could be bound to. the context was a plone.registry RecordProxy, which was lacking a __parent__ attribute (now fixed in a branch and submitted as PR). For reference, an excerpt of the traceback is copied further down.

But however, it appears to me wrong, that for forms where ignoreContext is set to True the field tries to bind itself to a context in this line: https://github.com/zopefoundation/z3c.form/blob/f1d702e948e709db8ba645e4bd6d741e49a48da8/src/z3c/form/widget.py#L112

I tried that to chang to:

            # We get a clone of the field with the context binded, if not
            # ignoreContext is set to True
            if self.ignoreContext:
                field = self.field
            else:
                field = self.field.bind(self.context)

And the error was gone.

Not sure, if it's intentional that the field is bound to the context, even for ignoreContext forms...

/cc @agroszer @icemac

  /home/thet-data/dotfiles-thet/home/.buildout/eggs/z3c.form-3.2.9-py2.7.egg/z3c/form/widget.py(118)update()
    116             #    field = self.field
    117             #else:
--> 118             field = self.field.bind(self.context)
    119 
    120             if value is field.missing_value or value is interfaces.NO_VALUE:

  /home/thet-data/dotfiles-thet/home/.buildout/eggs/zope.schema-4.4.2-py2.7.egg/zope/schema/_field.py(312)bind()
    310         elif clone.vocabulary is None and self.vocabularyName is not None:
    311             vr = getVocabularyRegistry()
--> 312             clone.vocabulary = vr.get(object, self.vocabularyName)
    313 
    314         if not ISource.providedBy(clone.vocabulary):

  /home/thet-data/dotfiles-thet/home/.buildout/eggs/Zope2-2.13.24-py2.7.egg/Zope2/App/schema.py(33)get()
     31         """
     32         factory = getUtility(IVocabularyFactory, name)
---> 33         return factory(context)
     34 
     35 

  /home/thet-data/dotfiles-thet/home/.buildout/eggs/plone.app.vocabularies-3.0-py2.7.egg/plone/app/vocabularies/catalog.py(605)__call__()
    603             site = getSite()
    604             nav_root = getNavigationRootObject(context, site)
--> 605             if nav_root and nav_root.getPhysicalPath() != site.getPhysicalPath():
    606                 parsed['path'] = {
    607                     'query': '/'.join(nav_root.getPhysicalPath()),

> /home/thet-data/dotfiles-thet/home/.buildout/eggs/plone.registry-1.0.4-py2.7.egg/plone/registry/recordsproxy.py(36)__getattr__()
     34     def __getattr__(self, name):
     35         if name not in self.__schema__:
---> 36             raise AttributeError(name)
     37         value = self.__registry__.get(self.__prefix__ + name, _marker)
     38         if value is _marker:

ipdb> context
*** NameError: name 'context' is not defined
ipdb> self.context
*** AttributeError: context
ipdb> u
> /home/thet-data/dotfiles-thet/home/.buildout/eggs/plone.app.vocabularies-3.0-py2.7.egg/plone/app/vocabularies/catalog.py(605)__call__()
    604             nav_root = getNavigationRootObject(context, site)
--> 605             if nav_root and nav_root.getPhysicalPath() != site.getPhysicalPath():
    606                 parsed['path'] = {

ipdb> context
<RecordsProxy for collective.venue.interfaces.IVenueSettings>
ipdb>   context.__module__
'plone.registry.recordsproxy'
ipdb> d
> /home/thet-data/dotfiles-thet/home/.buildout/eggs/plone.registry-1.0.4-py2.7.egg/plone/registry/recordsproxy.py(36)__getattr__()
     35         if name not in self.__schema__:
---> 36             raise AttributeError(name)
     37         value = self.__registry__.get(self.__prefix__ + name, _marker)

ipdb> l
     31 
     32         alsoProvides(self, schema)
     33 
     34     def __getattr__(self, name):
     35         if name not in self.__schema__:
---> 36             raise AttributeError(name)
     37         value = self.__registry__.get(self.__prefix__ + name, _marker)
     38         if value is _marker:
     39             value = self.__schema__[name].missing_value
     40         return value
     41 

ipdb> u
> /home/thet-data/dotfiles-thet/home/.buildout/eggs/plone.app.vocabularies-3.0-py2.7.egg/plone/app/vocabularies/catalog.py(605)__call__()
    604             nav_root = getNavigationRootObject(context, site)
--> 605             if nav_root and nav_root.getPhysicalPath() != site.getPhysicalPath():
    606                 parsed['path'] = {
agroszer commented 8 years ago

Determining the default value might need the context (we do have that in our project) and AFAIK ignoreContext is for determining widget values

        description=_('A flag, when set, forces the widget not to look at '
                      'the context for a value.'),

not sure we should take both under the same hat

icemac commented 8 years ago

@thet What kind of form are you using? Is it an AddForm or EditForm or something else?

thet commented 8 years ago

@icemac it's an edit form from https://github.com/plone/plone.app.registry/blob/master/plone/app/registry/browser/controlpanel.py#L19

@agroszer if I understand correctly from the description, a fix like shown above would be appropriate?

icemac commented 8 years ago

@thet If it es an edit form each field should be bindable to the context. How do you save the values if binding does not work when loading them?

agroszer commented 8 years ago

@thet re "if I understand correctly from the description, a fix like shown above would be appropriate?"

On the contrary, I'd rather do not mix the two.

Also, field.bind(None) should work without an exception, we use it to clone a field.

thet commented 2 years ago

Stale issue, cleaning up.