limscoder / amfast

An Adobe AMF serialization and RPC implementation for Python, written as a C extension for speed.
MIT License
5 stars 6 forks source link

The encoder doesn't like objects without a __dict__ attribute #78

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
PROBLEM:

When you try to encode an object that doesn't contain the __dict__ attribute 
you get an error.

ENVIRONMENT:

Server: Twisted
ORM: SQLAlchemy

If I try to do something within my controller method with the database that 
will result in an error, (Saving an object to the database when the id is 
already used.) SQLAlchemy will 'correctly' throw an error. (Integrity Error). 
This error is then passed through the encoder before the message is returned, 
but the encoder will not encode the Integrity Error from SQLAlchemy and will 
choke.

It seems that SQLAlchemy Integrity Errors override the __dict__ attribute. 
Because the 'get_dynamic_attr_vals' doesn't check if the __dict__ attribute 
exists before accessing it. The encoder fails.

SOLUTION:

Check to see if the object has a dictionary of attributes before trying to 
access them. In 'amfast/class_def/__init__.py' Line 294

def get_dynamic_attr_vals(obj, ignore_attrs=None, include_private=False):
    vals = {}

    if hasattr(obj, '__dict__'):
        for attr, val in obj.__dict__.iteritems():
            if ignore_attrs is not None:
                if attr in ignore_attrs:
                    continue

            if (include_private is False) and (attr.startswith('_')):
                continue

            vals[attr] = val

    return vals

Original issue reported on code.google.com by brett.la...@gtempaccount.com on 16 Jun 2011 at 8:53

GoogleCodeExporter commented 9 years ago
How would a object you encode have no '__dict__', you ask?

Well, this took a bit of investigation, but it seems that the exception I'm 
trying to throw, (SQLAlchemy's IntegrityError) contains the database cursor 
object as an attribute. (We use 'psycopg' http://initd.org/psycopg/). This 
cursor object is in C code.

Bottom line is, you can't assume that every object that is encoded has a 
'__dict__'.

If you find an object without a __dict__ it should be safe to return an empty 
__dict__.

Original comment by br...@vineyardnetworks.com on 16 Jun 2011 at 10:26

GoogleCodeExporter commented 9 years ago
If an object doesn't have a __dict__, it will need to use the static attribute 
feature to map it's attributes:

http://code.google.com/p/amfast/wiki/EncodeAndDecode#Custom_Type_Maps

I don't think encoding without any attributes is the correct solution, rather I 
think the code should check and raise a more informative error.

Original comment by dthomp...@gmail.com on 16 Jun 2011 at 11:20

GoogleCodeExporter commented 9 years ago
Ya your right. I should probably be catching and wrapping SQLAlchemy's 
exceptions into my own exceptions anyways.

But for me right away, adding the line:

if hasattr(obj, '__dict__'):

Before iterating the object's __dict__ solves the problem.

When the encoder encodes the SQLAlchemy IntegrityError Exception it looks 
through it's attributes and finds the Database Cursor Object (which is in C). 
It then tries to encode the Database Cursor Object and finds no __dict__ 
attribute. I don't really want or need the database cursor object so this is 
fine for me.

Original comment by br...@vineyardnetworks.com on 16 Jun 2011 at 11:51

GoogleCodeExporter commented 9 years ago
I came around to your way of thinking. This issue is fixed in trunk.

Original comment by dthomp...@gmail.com on 14 Aug 2011 at 11:32

GoogleCodeExporter commented 9 years ago
Thanks a lot. In our company's next release we'll update.

Original comment by br...@vineyardnetworks.com on 15 Aug 2011 at 3:34