'If passed a non dictionary we assume we can pull attributes from it.
This will hard error in some situations if you\'re passing a bad type
(like an int).'

def extract(self, value):

    if (value is None):
        return value
    if (not isinstance(value, Mapping)):
        new_value = {}
        for attr in self.attributes:
            new_value[attr.name] = attr.extract(getattr(value, attr.name, None))
        items = new_value
    else:
        items = value.copy()
    data = {}
    for attr in self.attributes:
        nv = items.pop(attr.name, None)
        if (attr.required and (nv is None)):
            raise ValueError(u'{}    is    required    (cannot    be    None)'.format(attr.name))
        data[attr.name] = attr.extract(nv)
    if items:
        raise ValueError(u'Unknown    attributes:    {}'.format(',    '.join(map(six.text_type, six.iterkeys(items)))))
    return data
