Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1601 Le 29/07/2013, à 15:06

grim7reaper

Re : /* Topic des codeurs [8] */

tshirtman a écrit :

Bon, j'ai une galère relou, et j'ai pas trop d'idée de comment trouver la source du problème.

j'ai mis mon nexus 4 a jours d'android 4.3 ce weekend, et une chose que j'avais pas prévus, c'est que ça pête python-for-android. hmm

L'ors d'un import d'une lib dont je dépends, il se passe ça

I/python  ( 3368):   File "/home/gaby/lcs/kitch/.buildozer/android/platform/python-for-android/build/python-install/lib/python2.7/stringprep.py", line 8, in <module>
I/python  ( 3368): ImportError: dlopen failed: invalid flags to dlopen: 102

et apparement, ils ont en effet ajouté un check sur les valeurs de flags dans cette nouvelle version…
http://www.funkyandroid.com/aosp-JDQ39-JWR66V.html
on peut voir le changeset

-soinfo* do_dlopen(const char* name) {
+soinfo* do_dlopen(const char* name, int flags) {
+  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
+    DL_ERR("invalid flags to dlopen: %x", flags);
+    return NULL;
+  }

plusieurs fois…

le soucis maintenant, c'est de trouver *ou* est l'appel de dlopen qui fait crasher, sachant que ça se passe sur android, je pourrais me relancer dans le gdb distant mais c'est un peu relou à mettre en place, et le grep de dlopen dans la codebase renvois du monde… hmm

Et on le trouve où le fichier stringprep.py ?



Édit : Bon cela dit, je peux faire une hypothèse (mais sans voir les sources Python, c’est à prendre avec des pincettes).

ImportError: dlopen failed: invalid flags to dlopen: 102

102 c’est de l‘hexa’ (car %x dans le printf).
Donc 0x00100 | 0x00002, ce qui se traduit chez moi par RTLD_GLOBAL | RTLD_NOW.
Donc le if devrait renvoyer 0.
Or, si je compare les flags de dlopen entre la libc de mon système et la libc d’Android, je vois ça :
Mon système :

#define RTLD_LAZY	0x00001	/* Lazy function call binding.  */
#define RTLD_NOW	0x00002	/* Immediate function call binding.  */
#define RTLD_GLOBAL	0x00100
#define RTLD_LOCAL	0

Android :

enum {
  RTLD_NOW  = 0,
  RTLD_LAZY = 1,

  RTLD_LOCAL  = 0,
  RTLD_GLOBAL = 2,
};

Ça pourrait être la source du problème (si le code Python utilise les valeurs de flags standard au lieu de ceux d’Android), mais il faudrait que je vois le code Python pour en être sûr.

Édit 2 : petit exemple :

>>> SYS_LAZY = 0x00001
>>> SYS_NOW  = 0x00002
>>> SYS_GLOBAL = 0x00100
>>> SYS_LOCAL = 0
>>> flags = SYS_GLOBAL|SYS_NOW
>>> (flags & ~(SYS_NOW|SYS_GLOBAL|SYS_LAZY|SYS_LOCAL))
0
>>> ANDROID_NOW = 0
>>> ANDROID_LAZY = 1
>>> ANDROID_LOCAL = 0
>>> ANDROID_GLOBAL = 2
>>> (flags & ~(ANDROID_NOW|ANDROID_GLOBAL|ANDROID_LAZY|ANDROID_LOCAL))
256
>>> flags = ANDROID_GLOBAL|ANDROID_NOW
>>> (flags & ~(ANDROID_NOW|ANDROID_GLOBAL|ANDROID_LAZY|ANDROID_LOCAL))
0

Ça passe avec les valeurs systèmes, mais si le flag est défini en valeur système il ne passe pas le test sur Android.
Par contre, en utilisant les bonnes valeurs, ça passe.

Dernière modification par grim7reaper (Le 29/07/2013, à 15:32)

Hors ligne

#1602 Le 29/07/2013, à 17:12

tshirtman

Re : /* Topic des codeurs [8] */

yep, c'est bien un soucis avec les valeurs différentes, il y a des modules qui essayent de deviner les valeurs quand ils n'arrivent pas a faire certains imports, on a d'abords trouvé libxslt (https://github.com/twobob/buildroot-kin … libxsl.py/) mais apparement c'est pas lui, ensuite pyopenssl (https://github.com/msabramo/pyOpenSSL/b … _init__.py) qui a l'air coupable (on a wrappé sys.setdlopenflags pour tracer ce cas), là on regarde pour fixer ctypes ou DLFCN pour le target (on en a un pour linux2, mais sys.platform renvois maintenant linux3, forcément).

Hors ligne

#1603 Le 29/07/2013, à 17:28

grim7reaper

Re : /* Topic des codeurs [8] */

Ha, j’avais vu juste alors.
Question bête : comment vous avez fait pour wrapper sys.setdlopenflags et tracer ces appels ?

Hors ligne

#1604 Le 29/07/2013, à 17:48

tshirtman

Re : /* Topic des codeurs [8] */

monkey patching smile dans mon programme, avant les imports

http://paste.ubuntu.com/5925415/

Et oui, c'était bien vu de ta part smile

Edit: c'est réglé smile

Dernière modification par tshirtman (Le 29/07/2013, à 17:51)

Hors ligne

#1605 Le 29/07/2013, à 18:05

grim7reaper

Re : /* Topic des codeurs [8] */

tshirtman a écrit :

monkey patching smile dans mon programme, avant les imports

Ha OK, j’y avais pensé pour du Ruby, mais je ne savais pas qu’on pouvait le faire en Python aussi.

Hors ligne

#1606 Le 29/07/2013, à 19:05

ljere

Re : /* Topic des codeurs [8] */

merci grim ça fonctionne super j'ai juste du ajouter .title() sur le print car il n'était pas pris en compte dans la fonction pour zip et all si tu as plus de renseignement je suis preneur sinon je me documenterai

shanx j'avais essayé une méthode similaire mais seul le dernier titre est affiché


ancien PC Toshiba satellite_c670d-11 / Linux Mint 21 Vanessa
Nouveau PC ASUS TUF GAMING A17 GPU RTX 4070 CPU AMD Ryzen 9 7940HS w/ Radeon 780M Graphics / Linux Mint 21.2 Victoria / Kernel: 6.4.8-1-liquorix / Desktop: Cinnamon

Hors ligne

#1607 Le 29/07/2013, à 19:12

Shanx

Re : /* Topic des codeurs [8] */

ljere a écrit :

shanx j'avais essayé une méthode similaire mais seul le dernier titre est affiché

C’est marrant, parce que chez moi ça fonctionne très bien (il retourne les deux acronymes qu’il faut).

EDIT : après explications sur IRC, il s’avère qu’il manquait juste un title()…

Dernière modification par Shanx (Le 29/07/2013, à 19:23)


Mes randos : grande traversées des Alpes, de l'Islande, de la Corse, du Japon (en vélo), etc.
Traversée des États-Unis à pied

Hors ligne

#1608 Le 29/07/2013, à 19:31

grim7reaper

Re : /* Topic des codeurs [8] */

J’avais retiré le title du print car je pensais que tu voulais afficher le titre tel qu’il était donné en entrée wink

    for title in filter(match_acronyme, titles):
        print(title)

Bon là c’est la partie simple, je filtre la liste des titres en fonction d’un critère.
Le critère est une fonction, ici match_acronyme, qui doit renvoyer True ou False.
filter va appliquer cette fonction sur chaque élément de la liste, ici titles, et produire une nouvelle liste.
Si la fonction renvoie True, on ajoute l’élément dans la nouvelle liste, sinon on l’ignore.

def match_acronyme(title):
    title = title.title().split(' ')
    return (len(title) == len(acronyme) and
            all([word[0] == c for (word, c) in zip(title, acronyme)]))

Dans un premier temps, on découpe le titre en mots.
Ensuite, c’est là qu’on fait un peu de magie wink
Tout d’abord, la fonction zip : elle permet de fusionner des choses itérables (ici on utilise des listes), tu lui passes N-itérable et elle te renvoie un itérable de N-uplet. Je pense qu’un exemple sera plus parlant, voyons avec Peter Pan :

>>> titre = 'peter pan'.title().split(' ')
>>> titre
['Peter', 'Pan']
>>> acronyme = 'PP'
>>> list(zip(titre, acronyme))
[('Peter', 'P'), ('Pan', 'P')

On a titre, qui est une liste de deux éléments et on a acronyme qui est une liste de deux éléments aussi.
zip va les fusionner (l’élément 0 de titre avec l’élément 0 de acronyme, puis les éléments 1 ensemble et ainsi de suite).
Un autre exemple avec La condition humaine :

>>> titre = 'LA Condition HUMAINE'.title().split(' ')
>>> titre
['La', 'Condition', 'Humaine']
>>> list(zip(titre, acronyme))
[('La', 'P'), ('Condition', 'P')]

Ici on a une liste de 3 élément et acronyme qui fait que 2 élémént, donc le résultat ne fera que 2 éléménts.

Ensuite, la fonction all.
Elle renvoie True si une condition est vraie pour chaque élément de la liste (si un seul élément ne remplie pas la condition, alors all retourne False).
Ici, notre condition est que la première lettre du mot corresponde à l’acronyme, et ce pour chaque couple formé avec zip précédemment.
Donc, pour Peter Pan
('Peter', 'P') => P == P => True
('Pan', 'P') => P == P => True
Les deux élément de la liste sont True, all renvoie True
Et pour la chaîne "Pas Bien" :
('Pas', 'P') => P == P => True
('Bien', 'P') => B == P => False
Un des éléments est False, all renvoie False

Je ne sais pas si c’est plus clair hmm
Les fonctions sont documentés ici, et au pire.

Hors ligne

#1609 Le 29/07/2013, à 20:51

ljere

Re : /* Topic des codeurs [8] */

c'est super clair j'ai tout compris, j'avais cherché du coté de filter mais je n'avais pas bien compris son fonctionnement maintenant c'est clair aussi, merci smile .


ancien PC Toshiba satellite_c670d-11 / Linux Mint 21 Vanessa
Nouveau PC ASUS TUF GAMING A17 GPU RTX 4070 CPU AMD Ryzen 9 7940HS w/ Radeon 780M Graphics / Linux Mint 21.2 Victoria / Kernel: 6.4.8-1-liquorix / Desktop: Cinnamon

Hors ligne

#1610 Le 29/07/2013, à 21:31

cervo

Re : /* Topic des codeurs [8] */

Je viens de découvrir ça, alors je fais partager. Un petit lien sympa pour apprendre ruby en s'amusant : https://www.bloc.io/ruby-warrior/#/

Hors ligne

#1611 Le 30/07/2013, à 08:09

Mindiell

Re : /* Topic des codeurs [8] */

Marrant, juste la musique en on et forte par défaut qui est un peu surprenante au bureau avé les collègues wink

Hors ligne

#1612 Le 30/07/2013, à 11:28

Rolinh

Re : /* Topic des codeurs [8] */

@cervo: marrant tongue

Hors ligne

#1613 Le 30/07/2013, à 18:18

grim7reaper

Re : /* Topic des codeurs [8] */

@cervo : ouais, sympa smile
Du coup, j’ai récupéré le code sur lequel il se base, et je vais jouer en local avec mon bon vieux Vim.

Hors ligne

#1614 Le 31/07/2013, à 14:01

grim7reaper

Re : /* Topic des codeurs [8] */

GPG vient d’être mis à jour.
Récemment on parlait des side-channel attack, et bien la mise à jour contient un correctif contre une méthode sortie récemment : Flush+Reload.
En plus, c‘est assez sympa :

Abstract a écrit :

Flush+Reload is a cache side-channel attack that monitors access to data in shared pages. In this paper we demonstrate how to use the attack to extract private encryption keys from GnuPG. The high resolution and low noise of the Flush+Reload attack enables a spy program to recover over 98% of the bits of the private key in a single decryption or signing round. Unlike previous attacks, the attack targets the last level L3 cache. Consequently, the spy program and the victim do not need to share the execution core of the CPU. The attack is not limited to a traditional OS and can be used in a virtualised environment, where it can attack programs executing in a different VM.

(le gras est de moi)
La publication est accessible ici.

Hors ligne

#1615 Le 31/07/2013, à 18:21

Rolinh

Re : /* Topic des codeurs [8] */

@grim: intéressant

Question aux pythonneux:
J'aimerais serialiser un objet python en JSON (je suis en train de créer une API REST) mais je rencontre quelques problèmes. En fait, dans le cas d'une instance de mon objet, je pensais bêtement à json.dumps(obj.__dict__). Sauf que voilà, les type directement sérialisables sont dict, list, string, integer, float, boolean ou None. Un de mes objet possède un attribut datetime.datetime et n'est donc pas sérialisable. En cherchant un peu, je suis tombé sur plusieurs workarounds mais rien qui ne me satisfasse vraiment.
Quelqu'un aurait quelque chose de propre pour du Python 3 ou une lib qui fasse correctement la sérialisation d'un objet Python vers JSON à me proposer?

EDIT: mmm, peut-être un truc du genre?

class Foo(object):
    def __init__(self, name):
        self.name = name
        self.date = datetime.utcnow()
    def to_json(self):
        return dict(
            name=self.name,
            date=self.date.isoformat(),
            )

Et faire un json.dumps en utilisant ça?

Dernière modification par Rolinh (Le 31/07/2013, à 18:39)

Hors ligne

#1616 Le 31/07/2013, à 18:43

Shanx

Re : /* Topic des codeurs [8] */

Étant donné que je sais pas ce qu’est la sérialisation, je vais probablement dire une bêtise, mais tu peux pas transformer ton attribut datetime.datetime en string (avec strftime) ?


Mes randos : grande traversées des Alpes, de l'Islande, de la Corse, du Japon (en vélo), etc.
Traversée des États-Unis à pied

Hors ligne

#1617 Le 31/07/2013, à 18:53

grim7reaper

Re : /* Topic des codeurs [8] */

@Rolinh : Apparemment, la façon standard c’est de dériver JSONEncoder.
Et à première vue, je suis plutôt d’accord avec les arguments avancés :

Tyler Eaves a écrit :

JSON doesn't have a date-time type, period, so it is impossible to losslessly encode a date-time in JSON, without some sort of special logic on the receiving end.

Martijn Pieters a écrit :

JSON doesn't specify how to handle dates, so the python json library cannot make the decision on how to then represent these for you. That completely depends on how the other side (browser, script, whatever) handles dates in JSON as well.

Source.

Si tu veux un truc qui le fait tout sans écrire de code en plus (et donc prend des décisions à ta place, ça peut être bon ou pas selon lesdites décisions ^^), apparemment il y a le module jsonpickle, mais il semble pas dispo’ en Python 3 (peut-être y’a t-il un équivalent ?).

Hors ligne

#1618 Le 31/07/2013, à 18:55

Rolinh

Re : /* Topic des codeurs [8] */

@Shanx: Non, tu ne dis pas une bêtise. wink En fait c'est précisemment ce que fait isoformat() que j'appelle sur ma date dans ma méthode to_json

documentation Python a écrit :

Return a string representing the date and time in ISO 8601 format

Sinon: serialization wink

Mon but ici est de transformer des objets python en JSON pour mon API afin qu'ensuite je puisse les récupérer en javascript (ça pourrait être un autre langage) et en créer des objets js en les desérialisant afin de pouvoir les utiliser pour construire ma vue (en html + css + js).

@grim: ouais, ta réponse est le résultat de mes précédentes recherche mais ça ne m'avance pas. Et je n'ai pas trouvé d'alternative à jsonpickle pour python 3.
Du coup, je pense que je vais utiliser mon trick. En fait, c'est pour mon application bottle et il transforme automatiquement les dict en json donc faire un dict "json safe" comme je le proposais me semble être une solution plutôt propre finalement.

Dernière modification par Rolinh (Le 31/07/2013, à 18:59)

Hors ligne

#1619 Le 31/07/2013, à 19:03

grim7reaper

Re : /* Topic des codeurs [8] */

Bah tu demandes la méthode propre en Python 3, et apparemment la méthode propre c’est d’hériter de JSONEncoder, je ne fais que répondre à ta question justement tongue
Après que la méthode propre ne te satisfasse pas, why not, mais d’ailleurs c’est quoi le problème avec cette méthode ?

Hors ligne

#1620 Le 31/07/2013, à 19:12

Rolinh

Re : /* Topic des codeurs [8] */

Beuh, je sais pas, j'aime pas stout. tongue
Mon problème avec cette méthode c'est qu'elle suppose que tous les types sont sérialisables vers JSON sauf datetime (réponse de Vikas) ce qui est faux puisque les type binaires, par exemple, ne le sont pas non plus. Du coup, si je créé un nouvel objet avec, admettons, un attribut de type binaire ben je vais me taper une TypeError exception puisque la sérialisation sera impossible. Bon, tu me diras qu'à ce moment je n'aurais qu'à adapter ma classe et on n'en parle plus.

Mais bon, comme bottle sérialise automatiquement les dict vers json, autant que je retourne un dict contenant les attributs de mon objet en format sérialisable vers JSON, non?

Dernière modification par Rolinh (Le 31/07/2013, à 19:19)

Hors ligne

#1621 Le 31/07/2013, à 19:44

grim7reaper

Re : /* Topic des codeurs [8] */

Rolinh a écrit :

Mon problème avec cette méthode c'est qu'elle suppose que tous les types sont sérialisables vers JSON sauf datetime (réponse de Vikas)

Non, cette méthode suppose que tous les types que l’on peut mapper directement sur les types définis en JSON sont sérialisable automatiquement. Lesdits types étant :

https://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example a écrit :

JSON's basic types are:
    Number (double precision floating-point format in JavaScript, generally depends on implementation)
    String (double-quoted Unicode, with backslash escaping)
    Boolean (true or false)
    Array (an ordered sequence of values, comma-separated and enclosed in square brackets; the values do not need to be of the same type)
    Object (an unordered collection of key:value pairs with the ':' character separating the key and the value, comma-separated and enclosed in curly braces; the keys must be strings and should be distinct from each other)
    null (empty)

Donc dict est mappé sur Object, list sur Array, str sur String, float et int sur Number, bool sur Boolean et None sur null.
Pour le reste, dont datetime mais pas que, faut le définir soi-même ce que je trouve normal (vu que ça dépends de qui va relire les données après, y’a pas de solution universelle).
D’ailleurs, c’est la même en Javascript normalement :

https://en.wikipedia.org/wiki/JSON#Unsupported_native_data_types a écrit :

JavaScript syntax defines several native data types that are not included in the JSON standard: Date, Error, Regular Expression, and Function. These JavaScript data types must be represented as some other data format, with the programs on both ends agreeing on how to convert between the types.

L’encodeur par défaut encode les types existant en JSON, pour les types qui n’existent pas c’est à l’utilisateur de définir comment les encoder (vu la façon d’encoder n’est pas universelle ou standard) via son propre encodeur.



Rolinh a écrit :

Mais bon, comme bottle sérialise automatiquement les dict vers json, autant que je retourne un dict contenant les attributs de mon objet en format sérialisable vers JSON, non?

Je ne connais pas Bottle, donc ouais possible que ça soit mieux comme approche (mais ça reste toujours à toi définir comment sérialiser les types genre datetime à la main donc en fait je ne vois pas trop la différence)

Hors ligne

#1622 Le 31/07/2013, à 19:59

Rolinh

Re : /* Topic des codeurs [8] */

grim7reaper a écrit :

Non, cette méthode suppose que tous les types que l’on peut mapper directement sur les types définis en JSON sont sérialisable automatiquement.

Bah voui, bien ce que je dis. Mais la méthode default(self, obj) retourne bien json.JSONEncoder.default(self, obj) si l'objet n'est pas une instance de datetime.datetime => elle suppose que l'objet est sérialisable vers json si ce n'est pas un datetime.datetime.

grim7reaper a écrit :

L’encodeur par défaut encode les types existant en JSON, pour les types qui n’existent pas c’est à l’utilisateur de définir comment les encoder (vu la façon d’encoder n’est pas universelle ou standard) via son propre encodeur.

Oui, exactement. Pour ça que je proposais d'utiliser isoformat() sur mes attributs de type date puisque qu'ensuite, en js, il est facile de créer une objet date à partir d'une date au format ISO (et de même pour Python d'ailleurs) ce qui permet une sérialisation/desérialisation facilement.

grim7reaper a écrit :

Je ne connais pas Bottle, donc ouais possible que ça soit mieux comme approche (mais ça reste toujours à toi définir comment sérialiser les types genre datetime à la main donc en fait je ne vois pas trop la différence)

La différence c'est simplement que si je créé une méthode de classe pour chacun des mes objets à sérialiser, je sais qu'ils sont sérialisables. Point. Après, effectivement, ça me fera taper plus de code et en plus, il faut être sûr que je convertisse mes objets du style datetime de la même façon pour tous mes objets. Du coup, je ne sais pas trop. Vaut peut-être mieux me choper un type error de temps en temps et corriger la méthode qui hérite de JSONEncoder.

Hors ligne

#1623 Le 31/07/2013, à 20:09

grim7reaper

Re : /* Topic des codeurs [8] */

Rolinh a écrit :
grim7reaper a écrit :

Non, cette méthode suppose que tous les types que l’on peut mapper directement sur les types définis en JSON sont sérialisable automatiquement.

Bah voui, bien ce que je dis. Mais la méthode default(self, obj) retourne bien json.JSONEncoder.default(self, obj) si l'objet n'est pas une instance de datetime.datetime => elle suppose que l'objet est sérialisable vers json si ce n'est pas un datetime.datetime.

Ha ok, je viens de comprendre.
Tu parlais de l’exemple qu’il donne (MyEncoder), pas de l’encodeur par défaut.
Oui, je suis d’accord alors.

Rolinh a écrit :
grim7reaper a écrit :

Je ne connais pas Bottle, donc ouais possible que ça soit mieux comme approche (mais ça reste toujours à toi définir comment sérialiser les types genre datetime à la main donc en fait je ne vois pas trop la différence)

La différence c'est simplement que si je créé une méthode de classe pour chacun des mes objets à sérialiser, je sais qu'ils sont sérialisables. Point. Après, effectivement, ça me fera taper plus de code et en plus, il faut être sûr que je convertisse mes objets du style datetime de la même façon pour tous mes objets. Du coup, je ne sais pas trop. Vaut peut-être mieux me choper un type error de temps en temps et corriger la méthode qui hérite de JSONEncoder.

J’avais pas vu ton idée comme ça mais du coup là c’est clair : ton approche est foireuse. La duplication de code, c’est super mauvais.
Si on jour tu décides de changer le format de ta date (ou fixer un bug dans la sérialisation d’un type T d’attribut), va falloir aller modifier toutes les classes concernées, sans en oublier une (idem côté lecture). Si tu en oublies une, dans le meilleur des cas ça va planter, dans le pire des cas tu va faire des traitements foireux ou corrompre des données (ce que tu remarqueras peut-être après un temps plus ou moins long). C’est assez fâcheux hmm
Vaut clairement mieux se prendre un TypeError quand tu oublies de gérer un type (et aller l’ajouter dans la foulée) que de prendre le risque d’induire des bug cachés et difficile à trouver à chaque évolution de ton logiciel.

Hors ligne

#1624 Le 31/07/2013, à 22:16

Rolinh

Re : /* Topic des codeurs [8] */

grim7reaper a écrit :

J’avais pas vu ton idée comme ça mais du coup là c’est clair : ton approche est foireuse. La duplication de code, c’est super mauvais. (...)

Je suis bien d'accord, pour ça que je ne suis pas satisfait.
Bon, pour être plus clair: mon but est de sérialiser un objet que je récupère de ma db via une query sqlalchemy:

import json

from app.models import movie
from app.helpers import application_helper as ah
from lib.controllers import db_connector as db

class MoviesAPIController():

    def movie_test(self):
        sess = db.DbConnector.session
        movies = sess.query(movie.Movie).order_by(movie.Movie.title).first()
        return json.dumps(movies, cls=ah.AlchemyEncoder)

Et donc la solution que je pense finalement adopter, basée sur la réponse de Sasha B ici:

from sqlalchemy.ext.declarative import DeclarativeMeta
import json

class AlchemyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj.__class__, DeclarativeMeta):
            fields = {}
            attrs = [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']
            for field in attrs:
                data = obj.__getattribute__(field)
                if hasattr(data, 'isoformat'):
                    data = data.isoformat()
                json.dumps(data)
                fields[field] = data
            return fields

        return json.JSONEncoder.default(self, obj)

Ça fonctionne et si j'utilise une fois un attribut non sérialisable autre qu'un type date comme attribut d'un objet, je me taperais un TypeError mais au moins, ça me pétera à la gueule directement et je pourrais directement corriger le problème.

Hors ligne

#1625 Le 01/08/2013, à 07:33

grim7reaper

Re : /* Topic des codeurs [8] */

Ouais, ça semble au bien.
Au passage, je remplacerai bien ton :

attrs = [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']

par

[ x for x in obj.__dict__.keys() if x != 'metadata' ]

Ça semble équivalent :

>>> class Foo:
...     def __init__(self):
...         self.bar = None
...         self.baz = None
...         self.metadata = None
... 
>>> obj = Foo()
>>> [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']
['bar', 'baz']
>>> [ x for x in obj.__dict__.keys() if x != 'metadata' ]
['baz', 'bar']
>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne_
_', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'baz', 'metadata']
>>> obj.__dict__
{'baz': None, 'bar': None, 'metadata': None}
>>> 

Sauf que tu bosses directement sur la liste des attributs, pas sur attributs + méthodes (ce que te renvoie dir).
Sinon tu peux aussi redéfinir __dir__ pour ta classe. À toi de voir.

Hors ligne