Exemplo n.º 1
0
    def update(self):
        """\
        Customized update method.
        """

        # Since we are interested in acquring what the context had first
        # before we are interested in what was submitted in the request,
        # we forcibly set ignoreRequest on and continue as normal.  Once
        # that is done, process the request as normal.

        ignoreRequest = self.ignoreRequest
        self.ignoreRequest = True
        super(StorageFileSelectWidget, self).update()
        # Restore original value.
        self.ignoreRequest = ignoreRequest

        if not ignoreRequest:
            # Extract the request value like how the parent would have 
            # done
            widget_value = self.extract()

            if widget_value not in (NO_VALUE, INVALID_VALUE):
                # Only set the widget with the value from request that
                # is valid
                self.value = widget_value
                # As this deferred self.value assignment from request
                # is complete, with everything else done, return here.
                return

        # The follow are steps that should also have been done inside
        # step 1.2 in that method.  To begin validate that the
        # applicable conditions are available.
        if not IFieldWidget.providedBy(self):
            return

        # Always set errors, since context could provide an invalid
        # value due to changing conditions.
        self.setErrors = True

        # Now verify that the current widget value (which is extracted
        # by the data manager) is valid, attempt the conversion back to
        # the field value using toFieldValue as the reverse method
        # toWidgetValue does not and cannot raise exceptions due to
        # how and where it is used by the parent update method.

        converter = IDataConverter(self)
        try:
            converter.toFieldValue(self.value)
        except (zope.interface.Invalid, ValueError), error:
            # We have an exception, so we adapt and set the error view.
            view = zope.component.getMultiAdapter(
                (error, self.request, self, self.field,
                 self.form, self.context), IErrorViewSnippet)
            view.update()
            self.error = view
Exemplo n.º 2
0
    def extract(self, default=NO_VALUE):
        value = self.request.get(self.name, default)
        converter = IDataConverter(self)
        try:
            c_value = converter.toFieldValue(value)
        except:
            return value

        unit_name = self.request.get(self.name + '-unit')
        if unit_name and unit_name != self.base_unit:
            try:
                unit = getattr(ureg, unit_name)
                base_unit = getattr(ureg, self.base_unit)
            except UndefinedUnitError:
                c_value = self.field.get(self.context)

            # Do the conversion
            try:
                c_value = c_value * unit
            except TypeError:
                return value
            else:
                c_value = c_value.to(base_unit).magnitude
            if not self.ignoreContext:
                self._set_unit_annotation(unit_name)
            value = converter.toWidgetValue(c_value)

        return value
Exemplo n.º 3
0
    def get_data(self):
        """Return an iterable of HTML snippets representing the files already
        stored on the context and allowing to download it.
        If the widget is in input mode then removal is allowed too.
        """
        if self.value:
            # Depending on when this gets called we'll have INamedFile's,
            # strings ("index:N") or FileUpload's (on failed validations).
            # We have to filter out the FileUpload's since the uploads are gone
            # and we can do nothing about it.
            sub_values = [
                i for i in self.value
                if INamedFile.providedBy(i) or isinstance(i, basestring)
            ]

            converter = IDataConverter(self)
            converted_value = converter.toFieldValue(sub_values)

            if self.form is not None:
                view_name = self.name[len(self.form.prefix):]
                view_name = view_name[len(self.form.widgets.prefix):]
            else:
                view_name = ''

            for i, value in enumerate(converted_value):
                form_value = 'index:%s' % i
                download_url = '%s/++widget++%s/%i/@@download/%s' % (
                    self.request.getURL(),
                    view_name,
                    i,
                    value.filename,
                )

                yield self.render_file(form_value, value, download_url)
Exemplo n.º 4
0
 def getValue(self, language):
     self.value = removeSecurityProxy(self.value)
     if not isinstance(self.value, dict) and \
        not isinstance(self.value, PersistentDict):
         converter = IDataConverter(self)
         try:
             self.value = converter.toFieldValue(self.value)
         except Exception:
             self.value = {}
     if self.value is not None:
         return self.value.get(language)
Exemplo n.º 5
0
 def getValue(self, language):
     self.value = removeSecurityProxy(self.value)
     if not isinstance(self.value, dict) and \
        not isinstance(self.value, PersistentDict):
         converter = IDataConverter(self)
         try:
             self.value = converter.toFieldValue(self.value)
         except Exception:
             self.value = {}
     if self.value is not None:
         return self.value.get(language)
    def _setAsOwner(self, context, field, value):
        # Do some trivial transforms
        def transform(value, field):
            if isinstance(field, Set) and isinstance(value, unicode):
                value = set((value, ))
            elif isinstance(field, Set) and isinstance(value, tuple):
                value = set(value)
            elif isinstance(field, Set) and isinstance(value, list):
                value = set(value)
            elif isinstance(field, List) and isinstance(value, unicode):
                value = list((value, ))
            elif (isinstance(field, Choice) and isinstance(value, list)
                  and len(value) == 1):
                value = value[0]
            return value

        # Try to set the value on created object
        value = transform(value, field)
        try:
            # 2) Try your luck with z3c.form adapters
            widget = getMultiAdapter((field, getRequest()), IFieldWidget)
            converter = IDataConverter(widget)
            dm = getMultiAdapter((context, field), IDataManager)

            # Convert datetimes to collective.z3cform.datetimewidget-compatible
            if isinstance(field, Datetime) and isinstance(
                    widget, DatetimeWidget):  # noqa
                value = re.compile('\d+').findall(value)

            # Convert dates to collective.z3cform.datetimewidget-compatible
            if isinstance(field, Date) and isinstance(widget, DateWidget):
                value = re.compile('\d+').findall(value[:10])  # YYYY-MM-DD
            # Convert dates to plone.app.z3cform.widgets.datewidget-compatible
            elif isinstance(field, Date):
                value = value.split()[0]

            dm.set(converter.toFieldValue(value))
        except ConflictError:
            raise
        except Exception, e:
            try:
                # 1) Try to set it directly
                bound_field = field.bind(context)
                bound_field.validate(value)
                bound_field.set(context, value)
            except ConflictError:
                raise
            except Exception:
                LOG.error(e)
                return u'An unexpected error: {0:s} {1:s}'.format(
                    e.__class__, e)
    def _setAsOwner(self, context, field, value):
        # Do some trivial transforms
        def transform(value, field):
            if isinstance(field, Set) and isinstance(value, unicode):
                value = set((value,))
            elif isinstance(field, Set) and isinstance(value, tuple):
                value = set(value)
            elif isinstance(field, Set) and isinstance(value, list):
                value = set(value)
            elif isinstance(field, List) and isinstance(value, unicode):
                value = list((value,))
            elif (isinstance(field, Choice) and
                  isinstance(value, list) and len(value) == 1):
                value = value[0]
            return value

        # Try to set the value on created object
        value = transform(value, field)
        try:
            # 2) Try your luck with z3c.form adapters
            widget = getMultiAdapter((field, getRequest()), IFieldWidget)
            converter = IDataConverter(widget)
            dm = getMultiAdapter((context, field), IDataManager)

            # Convert datetimes to collective.z3cform.datetimewidget-compatible
            if isinstance(field, Datetime) and isinstance(widget, DatetimeWidget):  # noqa
                value = re.compile('\d+').findall(value)

            # Convert dates to collective.z3cform.datetimewidget-compatible
            if isinstance(field, Date) and isinstance(widget, DateWidget):
                value = re.compile('\d+').findall(value[:10])  # YYYY-MM-DD
            # Convert dates to plone.app.z3cform.widgets.datewidget-compatible
            elif isinstance(field, Date):
                value = value.split()[0]

            dm.set(converter.toFieldValue(value))
        except ConflictError:
            raise
        except Exception, e:
            try:
                # 1) Try to set it directly
                bound_field = field.bind(context)
                bound_field.validate(value)
                bound_field.set(context, value)
            except ConflictError:
                raise
            except Exception:
                LOG.error(e)
                return u'An unexpected error: {0:s} {1:s}'.format(
                    e.__class__, e)
Exemplo n.º 8
0
    def get_data(self):
        """
        """
        if self.value:
            # sometimes the value contains the strings from the form,
            # sometimes it's already converted by the converter. But
            # if we have errors and we are trying to add a new file
            # (thats when entry is a unicode string) we need to put
            # that string again in the form since we did not store the
            # file yet, but we can get the file from the converter..
            converter = IDataConverter(self)
            converted_value = converter.toFieldValue(self.value)
            for i, key_or_file in enumerate(self.value):
                if isinstance(key_or_file, unicode):
                    file_ = converted_value[i]
                    yield self.render_file(file_, value=key_or_file)

                else:
                    yield self.render_file(key_or_file, index=i)
Exemplo n.º 9
0
    def widget_value(self):
        """Return the converted value."""
        self.unit = self.request.get(self.name + '-unit', self.preferred_unit)
        if not self.value:
            return

        try:
            base_unit = getattr(ureg, self.base_unit)
        except UndefinedUnitError:
            value = self.value
        else:
            # Do the conversion
            converter = IDataConverter(self)
            try:
                value = converter.toFieldValue(self.value)
            except:
                return self.value
            system = None
            if not self.ignoreContext:
                system = self._get_unit_annotation()
            else:
                if self.unit in interfaces.METRICS:
                    system = interfaces.SYSTEM_METRIC
                elif self.unit in interfaces.IMPERIALS:
                    system = interfaces.SYSTEM_IMPERIAL
            if not system in self.unit_systems:
                system = self.preferred_system
            self.unit = utils.get_best_unit(
                value,
                system,
                self.unit_dimension,
                level_min=self.level_min,
                level_max=self.level_max,
            )[0]
            unit = getattr(ureg, self.unit)
            value = value * base_unit
            value = value.to(unit).magnitude
            if isinstance(value, Decimal):
                value = value.quantize(interfaces.TWOPLACES)
            value = converter.toWidgetValue(value)
        return value
 def _setAsOwner(self, context, field, value):
     # Try to set the value on creted object
     try:
         # 1) Try to set it directly
         bound_field = field.bind(context)
         bound_field.validate(value)
         bound_field.set(context, value)
     except ConflictError:
         raise
     except Exception, e:
         try:
             # 2) Try your luck with z3c.form adapters
             widget = getMultiAdapter((field, getRequest()), IFieldWidget)
             converter = IDataConverter(widget)
             dm = getMultiAdapter((context, field), IDataManager)
             dm.set(converter.toFieldValue(value))
         except ConflictError:
             raise
         except Exception:
             LOG.error(e)
             return u"An unexpected error: %s" % e
Exemplo n.º 11
0
    def _setAsOwner(self, context, field, value):
        # Do some trivial transforms
        def transform(value, field):
            if isinstance(field, Set) and isinstance(value, unicode):
                value = set((value,))
            elif isinstance(field, Set) and isinstance(value, tuple):
                value = set(value)
            elif isinstance(field, Set) and isinstance(value, list):
                value = set(value)
            elif isinstance(field, List) and isinstance(value, unicode):
                value = list((value,))
            elif (isinstance(field, Choice)
                  and isinstance(value, list) and len(value) == 1):
                value = value[0]
            return value

        # Try to set the value on created object
        value = transform(value, field)
        try:
            # 1) Try to set it directly
            bound_field = field.bind(context)
            bound_field.validate(value)
            bound_field.set(context, value)
        except ConflictError:
            raise
        except Exception, e:
            try:
                # 2) Try your luck with z3c.form adapters
                widget = getMultiAdapter((field, getRequest()), IFieldWidget)
                converter = IDataConverter(widget)
                dm = getMultiAdapter((context, field), IDataManager)
                dm.set(converter.toFieldValue(value))
            except ConflictError:
                raise
            except Exception:
                LOG.error(e)
                return u"An unexpected error: %s %s" % (e.__class__, e)
Exemplo n.º 12
0
    def create_content(self, *args, **kwargs):
        """Create content and return its UID"""
        disableCSRFProtection()
        # XXX: Because kwargs are only supported with robotframework >= 2.8.3,
        # we must parse them here to support robotframework < 2.8.3.
        for arg in [x for x in args if '=' in x]:
            name, value = arg.split('=', 1)
            kwargs[name] = value

        assert 'type' in kwargs, u"Keyword arguments must include 'type'."
        portal_type = kwargs.get('type')
        portal = getSite()
        if 'container' in kwargs:
            pc = getToolByName(portal, 'portal_catalog')
            uid_or_path = kwargs.pop('container')
            uid_results =\
                pc.unrestrictedSearchResults(UID=uid_or_path)
            path_results = \
                pc.unrestrictedSearchResults(
                    path={'query': uid_or_path.rstrip('/'), 'depth': 0})
            container =\
                (uid_results or path_results)[0]._unrestrictedGetObject()
        else:
            container = portal

        # if we create 'file' and 'image' kwargs entries, they should not be
        # used to create the content but be set afterwards
        create_kwargs = {}
        create_kwargs.update(kwargs)

        if HAS_DEXTERITY:
            if portal_type in ('File', ) and 'file' not in kwargs:
                pdf_file = os.path.join(os.path.dirname(__file__), 'content',
                                        u'file.pdf')
                value = NamedBlobFile(data=open(pdf_file, 'r').read(),
                                      contentType='application/pdf',
                                      filename=u'file.pdf')
                kwargs['file'] = value

        if portal_type in ('Image', 'News Item') and 'image' not in kwargs:
            prefill_image_types(portal, kwargs)

        id_ = kwargs.pop('id', None)
        type_ = kwargs.pop('type')

        content = None
        if HAS_DEXTERITY:
            # The title attribute for Dexterity types needs to be unicode
            if 'title' in kwargs and isinstance(kwargs['title'], str):
                kwargs['title'] = kwargs['title'].decode('utf-8')
            from plone.dexterity.interfaces import IDexterityFTI
            from plone.dexterity.utils import createContentInContainer
            try:
                getUtility(IDexterityFTI, name=type_)
                content = createContentInContainer(container, type_,
                                                   **create_kwargs)
                if id_ is not None and content.id != id_:
                    container.manage_renameObject(content.id, id_)
            except ComponentLookupError:
                pass

        if HAS_DEXTERITY and content:
            # For dexterity-types, we need a second pass to fill all fields
            # using their widgets to get e.g. RichText-values created
            # correctly.
            fti = getUtility(IDexterityFTI, name=type_)
            schema = fti.lookupSchema()
            fields = {}
            for name in schema:
                fields[name] = schema[name]
            for schema in getAdditionalSchemata(portal_type=type_):
                for name in schema:
                    fields[name] = schema[name]
            for name, field in fields.items():
                widget = queryMultiAdapter((field, getRequest()), IFieldWidget)
                if widget and name in kwargs:
                    if not IFromUnicode.providedBy(field):
                        value = kwargs[name]
                    elif isinstance(kwargs[name], unicode):
                        value = kwargs[name]
                    else:
                        value = unicode(str(kwargs[name]),
                                        'utf-8',
                                        errors='ignore')
                    converter = IDataConverter(widget)
                    dm = queryMultiAdapter((content, field), IDataManager)
                    if dm:
                        dm.set(converter.toFieldValue(value))

        if content is None:
            if id_ is None:
                normalizer = queryUtility(IURLNormalizer)
                id_ = normalizer.normalize(kwargs['title'])

            # It must be Archetypes based content:
            content = container[container.invokeFactory(type_, id_, **kwargs)]
            content.processForm()

        return IUUID(content)
Exemplo n.º 13
0
    def create_content(self, *args, **kwargs):
        """Create content and return its UID"""
        disableCSRFProtection()
        # XXX: Because kwargs are only supported with robotframework >= 2.8.3,
        # we must parse them here to support robotframework < 2.8.3.
        for arg in [x for x in args if '=' in x]:
            name, value = arg.split('=', 1)
            kwargs[name] = value

        assert 'type' in kwargs, u"Keyword arguments must include 'type'."
        portal_type = kwargs.get('type')
        portal = getSite()
        if 'container' in kwargs:
            pc = getToolByName(portal, 'portal_catalog')
            uid_or_path = kwargs.pop('container')
            uid_results =\
                pc.unrestrictedSearchResults(UID=uid_or_path)
            path_results = \
                pc.unrestrictedSearchResults(
                    path={'query': uid_or_path.rstrip('/'), 'depth': 0})
            container =\
                (uid_results or path_results)[0]._unrestrictedGetObject()
        else:
            container = portal

        # if we create 'file' and 'image' kwargs entries, they should not be
        # used to create the content but be set afterwards
        create_kwargs = {}
        create_kwargs.update(kwargs)

        if HAS_DEXTERITY:
            if portal_type in ('File', ) and 'file' not in kwargs:
                pdf_file = os.path.join(
                    os.path.dirname(__file__), 'content', u'file.pdf')
                value = NamedBlobFile(
                    data=open(pdf_file, 'r').read(),
                    contentType='application/pdf',
                    filename=u'file.pdf'
                )
                kwargs['file'] = value

        if portal_type in ('Image', 'News Item') and 'image' not in kwargs:
            prefill_image_types(portal, kwargs)

        id_ = kwargs.pop('id', None)
        type_ = kwargs.pop('type')

        content = None
        if HAS_DEXTERITY:
            # The title attribute for Dexterity types needs to be unicode
            if 'title' in kwargs and isinstance(kwargs['title'], str):
                kwargs['title'] = kwargs['title'].decode('utf-8')
            from plone.dexterity.interfaces import IDexterityFTI
            from plone.dexterity.utils import createContentInContainer
            try:
                getUtility(IDexterityFTI, name=type_)
                content = createContentInContainer(
                    container, type_, **create_kwargs)
                if id_ is not None and content.id != id_:
                    container.manage_renameObject(content.id, id_)
            except ComponentLookupError:
                pass

        if HAS_DEXTERITY and content:
            # For dexterity-types, we need a second pass to fill all fields
            # using their widgets to get e.g. RichText-values created
            # correctly.
            fti = getUtility(IDexterityFTI, name=type_)
            schema = fti.lookupSchema()
            fields = {}
            for name in schema:
                fields[name] = schema[name]
            for schema in getAdditionalSchemata(portal_type=type_):
                for name in schema:
                    fields[name] = schema[name]
            for name, field in fields.items():
                widget = queryMultiAdapter((field, getRequest()), IFieldWidget)
                if widget and name in kwargs:
                    if not IFromUnicode.providedBy(field):
                        value = kwargs[name]
                    elif isinstance(kwargs[name], unicode):
                        value = kwargs[name]
                    else:
                        value = unicode(str(kwargs[name]), 'utf-8',
                                        errors='ignore')
                    converter = IDataConverter(widget)
                    dm = queryMultiAdapter((content, field), IDataManager)
                    if dm:
                        dm.set(converter.toFieldValue(value))

        if content is None:
            if id_ is None:
                normalizer = queryUtility(IURLNormalizer)
                id_ = normalizer.normalize(kwargs['title'])

            # It must be Archetypes based content:
            content = container[container.invokeFactory(type_, id_, **kwargs)]
            content.processForm()

        return IUUID(content)
    def test_widgets_render_missing_values(self):
        """Test that gets run for each of the portal type specific subclasses,
        and asserts that a rendered z3c.form widget correctly returns the
        missing value if that's what's currently persisted on the object.
        """
        if self.portal_type is None:
            # Don't attempt to run this test for the abstract base class
            return

        self.login(self.manager)

        obj = self.get_obj_of_own_type()
        form = DefaultEditForm(obj, self.request)

        # Populate the form with fields according to the object's portal type
        with fake_interaction():
            # We need a fake IInteraction context because otherwise
            # z3c.formwidget.query.widget fails with its checkPermission()
            form.update()

        for widget in self.iter_widgets(form):
            field = widget.field

            if field.required:
                # Required fields shouldn't have missing values
                return

            if field.readonly:
                return

            # Determine what this field's missing value would be
            missing_value = field.missing_value

            # Manipulate fixture obj to have missing value for this field
            field.set(field.interface(obj), missing_value)

            # Update the widget to reflect that changed value on the obj
            with fake_interaction():
                widget.update()

            # Use the widget to retrieve the value - but turn it into a
            # field value using the field's DataConverter, in order to
            # compare it to missing value.
            dc = IDataConverter(widget)
            field_value_from_widget = dc.toFieldValue(widget.value)

            if isinstance(widget, SingleCheckBoxWidget):
                # Boolean fields handled by SingleCheckBoxWidgets are funny:
                # Their fields' missing value is None, which ends up
                # as a widget.value of empty list [], which
                # IDataConverter.toFieldValue() then turns into False.
                #
                # In other words, there isn't really a concept of missing
                # values for booleans - MV will always end up being
                # considered the same as False.
                if field_value_from_widget is False:
                    field_value_from_widget = None

            if isinstance(field, List) and isinstance(widget, CheckBoxWidget):
                # zope.schema.List is weird too - it gets rendered using
                # a CheckBoxWidget.
                missing_value = []

            self.assertEqual(
                missing_value, field_value_from_widget,
                'Unexpectedly got %r instead of missing value %r '
                'from widget %r (for an %r object) ' % (
                    field_value_from_widget, missing_value,
                    widget, obj.portal_type))
Exemplo n.º 15
0
    def create_content(self, *args, **kwargs):
        """Create content and return its UID"""
        # XXX: Because kwargs are only supported with robotframework >= 2.8.3,
        # we must parse them here to support robotframework < 2.8.3.
        for arg in [x for x in args if '=' in x]:
            name, value = arg.split('=', 1)
            kwargs[name] = value

        assert 'type' in kwargs, u"Keyword arguments must include 'type'."
        portal = getSite()
        if 'container' in kwargs:
            pc = getToolByName(portal, 'portal_catalog')
            uid_or_path = kwargs.pop('container')
            uid_results =\
                pc.unrestrictedSearchResults(UID=uid_or_path)
            path_results = \
                pc.unrestrictedSearchResults(
                    path={'query': uid_or_path.rstrip('/'), 'depth': 0})
            container =\
                (uid_results or path_results)[0]._unrestrictedGetObject()
        else:
            container = portal

        # Pre-fill Image-types with random content
        if kwargs.get('type') == 'Image' and not 'image' in kwargs:
            import random
            import StringIO
            from PIL import (
                Image,
                ImageDraw
            )
            img = Image.new('RGB', (random.randint(320, 640),
                                    random.randint(320, 640)))
            draw = ImageDraw.Draw(img)
            draw.rectangle(((0, 0), img.size), fill=(random.randint(0, 255),
                                                     random.randint(0, 255),
                                                     random.randint(0, 255)))
            del draw

            kwargs['image'] = StringIO.StringIO()
            img.save(kwargs['image'], 'PNG')
            kwargs['image'].seek(0)

        id_ = kwargs.pop('id', None)
        type_ = kwargs.pop('type')

        content = None
        if HAS_DEXTERITY:
            # The title attribute for Dexterity types needs to be unicode
            if 'title' in kwargs and isinstance(kwargs['title'], str):
                kwargs['title'] = kwargs['title'].decode('utf-8')
            from plone.dexterity.interfaces import IDexterityFTI
            from plone.dexterity.utils import createContentInContainer
            try:
                getUtility(IDexterityFTI, name=type_)
                content = createContentInContainer(container, type_, **kwargs)
                if id_ is not None and content.id != id_:
                    container.manage_renameObject(content.id, id_)
            except ComponentLookupError:
                pass

        if HAS_DEXTERITY and content:
            # For dexterity-types, we need a second pass to fill all fields
            # using their widgets to get e.g. RichText-values created
            # correctly.
            fti = getUtility(IDexterityFTI, name=type_)
            schema = fti.lookupSchema()
            fields = {}
            for name in schema:
                fields[name] = schema[name]
            for schema in getAdditionalSchemata(portal_type=type_):
                for name in schema:
                    fields[name] = schema[name]
            for name, field in fields.items():
                widget = queryMultiAdapter((field, getRequest()), IFieldWidget)
                if widget and name in kwargs:
                    if not IFromUnicode.providedBy(field):
                        value = kwargs[name]
                    elif isinstance(kwargs[name], unicode):
                        value = kwargs[name]
                    else:
                        value = unicode(str(kwargs[name]), 'utf-8',
                                        errors='ignore')
                    converter = IDataConverter(widget)
                    dm = queryMultiAdapter((content, field), IDataManager)
                    if dm:
                        dm.set(converter.toFieldValue(value))

        if content is None:
            if id_ is None:
                normalizer = queryUtility(IURLNormalizer)
                id_ = normalizer.normalize(kwargs['title'])

            # It must be Archetypes based content:
            content = container[container.invokeFactory(type_, id_, **kwargs)]
            content.processForm()

        return IUUID(content)
    def test_widgets_render_missing_values(self):
        """Test that gets run for each of the portal type specific subclasses,
        and asserts that a rendered z3c.form widget correctly returns the
        missing value if that's what's currently persisted on the object.
        """
        if self.portal_type is None:
            # Don't attempt to run this test for the abstract base class
            return

        self.login(self.manager)

        obj = self.get_obj_of_own_type()
        form = DefaultEditForm(obj, self.request)

        # Populate the form with fields according to the object's portal type
        with fake_interaction():
            # We need a fake IInteraction context because otherwise
            # z3c.formwidget.query.widget fails with its checkPermission()
            form.update()

        for widget in self.iter_widgets(form):
            field = widget.field

            if field.required:
                # Required fields shouldn't have missing values
                return

            if field.readonly:
                return

            # Determine what this field's missing value would be
            missing_value = field.missing_value

            # Manipulate fixture obj to have missing value for this field
            field.set(field.interface(obj), missing_value)

            # Update the widget to reflect that changed value on the obj
            with fake_interaction():
                widget.update()

            # Use the widget to retrieve the value - but turn it into a
            # field value using the field's DataConverter, in order to
            # compare it to missing value.
            dc = IDataConverter(widget)
            field_value_from_widget = dc.toFieldValue(widget.value)

            if isinstance(widget, SingleCheckBoxWidget):
                # Boolean fields handled by SingleCheckBoxWidgets are funny:
                # Their fields' missing value is None, which ends up
                # as a widget.value of empty list [], which
                # IDataConverter.toFieldValue() then turns into False.
                #
                # In other words, there isn't really a concept of missing
                # values for booleans - MV will always end up being
                # considered the same as False.
                if field_value_from_widget is False:
                    field_value_from_widget = None

            if isinstance(field, List) and isinstance(widget, CheckBoxWidget):
                # zope.schema.List is weird too - it gets rendered using
                # a CheckBoxWidget.
                missing_value = []

            self.assertEqual(
                missing_value, field_value_from_widget,
                'Unexpectedly got %r instead of missing value %r '
                'from widget %r (for an %r object) ' % (
                    field_value_from_widget, missing_value,
                    widget, obj.portal_type))