pyeve / eve-sqlalchemy

SQLAlchemy data layer for Eve-powered RESTful APIs
http://eve-sqlalchemy.readthedocs.io
Other
232 stars 70 forks source link

Error: datetime.timedelta is not JSON-serializable #37

Closed wil93 closed 9 years ago

wil93 commented 9 years ago

Hi, I just started using eve-sqlalchemy but I get an error when trying to access an object which has a timedelta field like this:

from sqlalchemy.types import Interval
...
token_gen_interval = Column(
    Interval,
    CheckConstraint("token_gen_interval > '0 seconds'"),
    nullable=False,
    default=timedelta(minutes=30))
...

The error I get is:

TypeError: datetime.timedelta(0, 1800) is not JSON serializable
amleczko commented 9 years ago

you need to provide a custom json encoder:

from eve.io.base import BaseJSONEncoder
from eve_sqlalchemy import SQL as SQLAlchemy
from datetime import timedelta

class SQLAJSONEncoder(BaseJSONEncoder):
    def default(self, obj):
        if isinstance(obj, timedelta):
            return int(obj)
        return super(SQLAJSONEncoder, self).default(obj)

class CustomEve(SQLAlchemy):
    json_encoder_class = SQLAJSONEncoder

app = Eve(data=CustomEve)
wil93 commented 9 years ago

Thank you, however I keep getting the same error... I modified the "simple example" from eve-sqlalchemy website in order to demonstrate the error: this is the version that does not include the custom JSON encoder, and this is the version that includes it. Both versions give the aforementioned TypeError.

amleczko commented 9 years ago

I will check it

wil93 commented 9 years ago

Hi, any news about this? :smile:

I was thinking that this is probably related to nicolaiarocci/eve#267

amleczko commented 9 years ago

It shouldn't be related - eve-sqlalchemy depends on eve>=0.5

kiniou commented 9 years ago

There might be an issue with eve.utils.document_etag() function. Debugging the execution of your script with pdb, I can see eve is trying to generate the etag by encoding attributes with a simple json.dumps() instead of json_encoder_class like in eve.render.render_json().

kiniou commented 9 years ago

:confused: After looking at imports in eve/utils.py, the dumps() function comes from bson and not from json so I'm not sure the custom json encoder class can be used here.

wil93 commented 9 years ago

Now that you mention it, I put a __import__("pdb").set_trace() in the default(self, obj) function to see if it was called, and that point was never reached. Now this bson thing could explain that.

kiniou commented 9 years ago

@wil93 you should also change int(obj) by obj.total_seconds() since int() can't take a timedelta object directly.

wil93 commented 9 years ago

Right, thanks :smile:

kiniou commented 9 years ago

This issue should be fixed in Eve 0.5.4 (cf. eve@72036276f2204d59e54a8a9fda5a6cc98f21143a).

amleczko commented 9 years ago

Confirmed - https://github.com/nicolaiarocci/eve/commit/72036276f2204d59e54a8a9fda5a6cc98f21143a fix the bug