Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

[wamp] Unable to serialize WAMP application payload .... is not JSON serializable

+2 votes

Dans mon code, je recupere des données d'une table d'un schema de Postgresql et lors de :

data = yield self.call('foo.bar.rss')

ca me pete l'exception du sujet parce que les données retournées contiennent une date/datetime et là c'est le drame ...

autobahn.wamp.exception.SerializationError: Unable to serialize WAMP application 
payload (datetime.datetime(2015, 2, 19, 0, 0, 35, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=60, name=None)) 
is not JSON serializable)

Du coup c'est super handicapant.
Aurais je raté un truc ou j'ai levé un loup ?

demandé 20-Fev-2015 par foxmask (2,862 points)

3 Réponses

+1 vote
 
Meilleure réponse

Bon la solution est dans la doc ... comme d'habitude

J'ai comparé tous les modules installés entre serveur de prod et mon PC et j'ai vu que je n'avais pas un certain module nommé MsgPack.

Or en creusant la doc je me suis souvenu qu'on pouvait installer des "variants" supplémentaires .... donc celui nommé serialization

Donc un coup de

pip install autobahn[twisted,accelerate,compress,serialization]

Et hop tout est reparti au poil !!!

répondu 24-Fev-2015 par foxmask (2,862 points)
+1 vote

Si ton objet n'indique pas comment on peut le transformer en JSON, tu vas devoir le faire à la main, avec pickle par exemple :

import pickle

@wamp.register(u"sexy.topic")
@inlineCallbacks
def reg(self):
    data = yield db.query()
    data = pickle.dumps(data)
    returnValue(data)

def call(self):
    data = yield self.call("sexy.topic")
    data = pickle.loads(data)

Après, si tes données sont lues par un programme pas écrit en Python, tu vas devoir créer ta propre fonction de sérialisation.

répondu 20-Fev-2015 par Vayel (1,050 points)

la ligne que j'ai mise dans la question est dans le onJoin()

Si j'ajoute à la suite ton code ca me sort une erreur

File ... line ... , in onJoin
data = yield self.call('foo.bar.get_rss')
exceptions.TypeError: call() takes exactly 1 argument (2 given)

Donc je me suis dit que dans onJoin() je devais juste faire

data = self.call()

mais meme exception sauf qu'elle se décale sur l'appel de call

File ..., line 68, in call
data = yield self.call('foo.bar.get_rss')
exceptions.TypeError: call() takes exactly 1 argument (2 given)

alors me suis dit bon ben je fou le code de la fonction call() dans le onJoin() directement pour peupler data et je supprime la fonction call, mais là c'est 'core pire

autobahn.wamp.exception.SerializationError: Unable to serialize WAMP application payload ('ascii' codec can't decode byte 0xc3 in position 8: ordinal not in range(128))

Hé oui, dans mes données j'ai déjà des données avec des caractères accentués "echappées" avant d'être enregistrées dans la base, du coup le pickle.load() quand, j'itere sur les data, me met le souk au moment de me resortir mes données via pickle.loads() :/

pour résumer voici où j'en suis à présent avec cette dernière erreur :

@inlineCallbacks
def onJoin(self, details):
    while True:
        data = yield self.call('foo.bar.get_rss')
        data = pickle.loads(data)
        for feed in data:
            my_feed = {'trigger_id': feed[0],
                       'name': feed[1],
                       'url': feed[2]}
            self.publish('foo.bar.rss', my_feed)
        yield sleep(20)

@wamp.register(u'foo.bar.get_rss')
@inlineCallbacks
def get_rss_feeds(self):
    query = "SELECT * FROM ma_table_qui_contient_mes_flux_rss"
    rows = yield self.db.runQuery(query)
    rows = pickle.dumps(rows)
    returnValue(rows)

Le dernier code est bon. Maintenant, c'est un problème de sérialisation de rows. Peux-tu montrer ce que fait un print(rows) ?

oui c'est ce que j'ai pensé, l'ideal aurait été de serialisé que la date puisque c'est tout ce qui me posait probleme à priori

et du coup si ton code est correct (malgré l'erreur exceptions.TypeError: call() takes exactly 1 argument (2 given)) comment j'en fais l'appel ? via data = self.call() ?

print(rows)

[(11, 'Humeurs illustr\xc3\xa9s', 'http://www.luc-damas.fr/humeurs/feed/', datetime.datetime(2015, 2, 16, 9, 0, 43, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=60, name=None))), (33, 'La Hy\xc3\xa8ne', 'http://www.infographiste-prod.ch/la_hyene/?feed=rss2&cat=27"', datetime.datetime(2013, 12, 24, 18, 7, 44, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=60, name=None)))]

Me demande si l'ouverture de la connexion a la base se fait avec un encoding utf8 . je vais regarder ça.

Mon code n'est pas bon : les fonctions ne sont là qu'à titre d'exemple. Il faut l'adapter comme tu l'as fait. Essaye de sérialiser rows, mais sans passer par WAMP :

class Cls:

    def __init__(self):
        # ...
        self.get_rss_feeds()    

    @inlineCallbacks
    def get_rss_feeds(self):
        query = "SELECT * FROM ma_table_qui_contient_mes_flux_rss"
        rows = yield self.db.runQuery(query)
        rows = pickle.dumps(rows)

        rows = pickle.loads(rows)

désolé pour le dérangement et merci pour ton aide et ta patience.

+1 vote

bon en fait, au boulot ca passe pas alors qu'à la maison ca passe sans rien faire d'ésotérique... ca me rassure pas pour le coup de la mise en prod :(

from txpostgres import txpostgres
from twisted.internet.defer import inlineCallbacks, returnValue

from autobahn import wamp

from autobahn.twisted.util import sleep
from autobahn.twisted.wamp import ApplicationSession


class RssComponent(ApplicationSession):

    """
    An application component that publishes an event
    """

    @inlineCallbacks
    def onJoin(self, details):
        print("session attached")

        pool = txpostgres.ConnectionPool(None,
                                         port=5432,
                                         database='base',
                                         user='user',
                                         password='pass')

        yield pool.start()
        print('DB Connection pool started')
        self.db = pool

        # register all procedures on this class which have been
        # decorated to register them for remoting
        regs = yield self.register(self)
        print('registered {} procedures'.format(len(regs)))

        while True:
            rows = yield self.call('foo.bar.get_rss')
            for feed in rows:
                print (feed)
                self.publish('foo.bar.rss', feed)
            yield sleep(20)

    @wamp.register(u'foo.bar.get_rss')
    @inlineCallbacks
    def get_trigger_rss(self):
        query = "SELECT * FROM ma_table_qui_contient_mes_rss"
        rows = yield self.db.runQuery(query)
        returnValue(rows)


if __name__ == '__main__':
    from autobahn.twisted.wamp import ApplicationRunner
    runner = ApplicationRunner("ws://127.0.0.1:8090/ws", "realm1")
    runner.run(RssComponent)
répondu 20-Fev-2015 par foxmask (2,862 points)

Les variables rows ont le même contenu chez toi et au boulot ?

En tout cas, c'est probablement pas un problème avec WAMP du coup, mais avec tes données. Un coup il parvient à les sérialiser, un coup non.

Ca se tient comme explication, j'avais pas remonte le meme dump, ce que j'ai fait et malgré tout ca roule encore @ home.

je comparerai lundi avec les modules installés

Twisted==15.0.0
arrow==0.5.0
autobahn==0.9.6
distribute==0.6.24
feedparser==5.1.3
msgpack-python==0.4.5
psycopg2==2.6
python-dateutil==2.4.0
six==1.9.0
txpostgres==1.2.0
ujson==1.33
wsaccel==0.6.2
zope.interface==4.1.2

ahurissant ; le meme code ne fonctionne pas d'une machine à l'autre...

des virtualenv partout avec le meme python 2.7.3 ; les memes dépendances ; la meme version de serveur PostGreSql 9.1

le plus con c'est que la machine de prod ne veut pas non plus que ca marche comme sur la station @ work
je suis reparti pour faire de la spéléo...

La base de données (son contenu) est-elle identique ?

Avant d'utiliser WAMP, regarde si ta requête te retourne la même chose chez toi et au boulot. Appelle get_trigger_rss à la main et compare le contenu de rows chez toi et au travail.

le contenu est le même ; j'ai remonte un dump ; c'est kif-kif.
je vais comparer entre mon pc @ home et mon serveur de prod les versions & config de :

  • postresql
  • python
  • les modules installés dans le virtualenv
...