Isnstance does not work for Decimal in AppEngine

I have an instance of decimal.Decimal that comes from a SQLAlchemy query. Since I need to serialize an object, I created a JSON serializer to work with Decimal :

 import decimal class AlchemyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, decimal.Decimal): return str(obj) return json.JSONEncoder.default(self, obj) 

It is unfortunate that isinstance(obj, decimal.Decimal) does not return True for the instance, though (using pdb in the default method above):

 obj.__class__ # => <class 'decimal.Decimal'> blah = decimal.Decimal() blah.__class__ # => <class 'decimal.Decimal'> isinstance(obj, decimal.Decimal) # => False isinstance(blah, decimal.Decimal) # => True isinstance(obj, obj.__class__) # => True 

I checked that the module referenced by both instances is the same module:

 import inspect inspect.getfile(obj.__class__) # => '/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.pyc' inspect.getfile(blah.__class__) # => '/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.pyc' 

I would love to understand why this does not work!

EDIT

It turns out that the problem only occurs when working in the AppEngine environment dev_appserver.py . Plain:

 isinstance(db.session.execute('SELECT amount FROM model LIMIT 1').fetchone()[0], decimal.Decimal) 

returns False when executing a request through AppEngine dev_appserver and True when starting from the console.

+5
source share
1 answer

Let's start on this today and stumbled upon an old post mail list that discussed this.

It turns out this question was also considered earlier by fooobar.com/questions/1261675 / .... Paste the answer here to simplify access / reduce stackoverflow server load:


It looks like the decimal.Decimal class is patched somewhere in the Google App Engine SDK (or the module is reloaded), and this is done between the MySQL conversion library that imports the decimal and you import it.

Fortunately, we can get around this by updating the MySQL conversion table:

 from MySQLdb.constants import FIELD_TYPE from MySQLdb.converters import conversions import decimal conversions[FIELD_TYPE.DECIMAL] = conversions[FIELD_TYPE.NEWDECIMAL] = decimal.Decimal 

What is it; the above code resets the MySQL class, and type checking your JSON encoder succeeds.

An alternative would be to look up the MySQLdb class with:

 class DecimalEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, MySQLdb.converters.conversions[MySQLdb.constants.FIELD_TYPE.DECIMAL]): return float(o) return super(DecimalEncoder, self).default(o) 

+2
source

Source: https://habr.com/ru/post/1261674/


All Articles