replace AttrDict with DataObject

Reviewer: @Sovietaced
CC @3mp4y5

DataObject uses the built-in __dict__ and attribute access rather than
wrapping a separate dict.
instead of forcing a specific class type, we could just check for a well-known encoding method.

``python
if callable(getattr(obj, '_get_serializable_form', None)):
    return obj._get_serializable_form()
...