Bug #38706
py3: format des timestamps incorrects dans /api/forms/<slug>/list/
0%
Description
En python2 :
{ "id": 1, "url": "https://wcs.dev.publik.love/<slug>/22/", "last_update_time": "2019-12-12T13:20:24Z", "receipt_time": "2019-12-04T14:57:07Z", }
En python3 :
{ "id": 1, "url": "https://wcs.dev.publik.love/<slug>/22/", "last_update_time": [ 2019, 12, 12, ... ], "receipt_time": [ 2019, 12, 4, ... ], }
Dans backoffice/management.py :
1845 output = [{'id': filled.id, 1846 'url': filled.get_url(), 1847 'receipt_time': filled.receipt_time, 1848 'last_update_time': filled.last_update_time} for filled in items] 1849 return json.dumps(output, 1850 cls=misc.JSONEncoder)
receipt_time est un time.struct_time
. Or quand on va voir l'encodeur custom :
476 class JSONEncoder(json.JSONEncoder): 477 def default(self, obj): 478 if isinstance(obj, time.struct_time): 479 return datetime.datetime.utcfromtimestamp(time.mktime(obj)).isoformat() + 'Z'
La ligne avec datetime renvoie bien la même chose en py2 et 3.
Le problème c'est en fait que, en py2 :
>>> isinstance(time.gmtime(), tuple) False
Et en py3 :
>>> isinstance(time.gmtime(), tuple) True
Donc le json.dumps, qui sait encoder des tuples, ne fait plus appel au default et s'occupe de notre struct_time tout seul comme un grand, pour nous donner une liste à la place de la chaîne de caractères.
Parmi les choses que ça casse, wcs-olap.
Files
Associated revisions
History
Updated by Valentin Deniaud almost 5 years ago
- Subject changed from py3: format des timestamps incorrects dans /forms/<slug>/list/ to py3: format des timestamps incorrects dans /api/forms/<slug>/list/
Updated by Frédéric Péters almost 5 years ago
- Assignee set to Frédéric Péters
Yep, déjà rencontré à un autre endroit(mais je ne retrouve pas le commit précis dans w.c.s., peut-être était-ce un autre projet.
Ici a priori ce mini-patch devrait tourner. (alternativement faire le .strftime(...) directement) mais c'est quand même plutôt chiant que python 3 offre une sérialisation de base pour time.struct_time qui soit pourrie, et pas nécessairement évidente à changer (vu que ça en fait un type connu et que JSONEncoder::default n'est plus appelée).
- return datetime.datetime.utcfromtimestamp(time.mktime(obj)).isoformat() + 'Z' + obj = datetime.datetime.utcfromtimestamp(time.mktime(obj))
(édit: non ça ne suffit pas, le time.struct_time est attrapé avant).
Updated by Frédéric Péters almost 5 years ago
- File 0001-misc-convert-time.struct_time-to-datetime-objects-be.patch 0001-misc-convert-time.struct_time-to-datetime-objects-be.patch added
- Status changed from Nouveau to Solution proposée
- Patch proposed changed from No to Yes
Voilà avec des tests explicites sur le format des dates retournés par l'API et un assert pour assurer via les tests Python 2 que jamais time.struct_time n'est passé à la sérialisation json.
En passant je retire le "Z" final parce que nos heures ne sont pas UTC, et j'ai vérifié wcs-olap, ça utilise isodate.parse_datetime qui ne va pas s'offusquer de l'absence de timezone.
Updated by Valentin Deniaud almost 5 years ago
- Status changed from Solution proposée to Solution validée
Updated by Frédéric Péters almost 5 years ago
- Status changed from Solution validée to Résolu (à déployer)
commit 12bfec671f0b053b387a582a6d6762c57de1851e Author: Frédéric Péters <fpeters@entrouvert.com> Date: Wed Dec 25 10:46:13 2019 +0100 misc: convert time.struct_time to datetime objects before json dump (#38706)
Updated by Frédéric Péters almost 5 years ago
- Status changed from Résolu (à déployer) to Solution déployée
misc: convert time.struct_time to datetime objects before json dump (#38706)