patacrep/patanet

Problème d'encoding avec la locale C

Luthaf opened this issue · 21 comments

J'ai cette stacktrace sur l'instance que je tente de déployer :

[ERROR] -- 2015-04-29 21:48:13,759 -- base : Internal Server Error: /fr/songs/la-compagnie-creole/la-machine-a-danser/
Traceback (most recent call last):
  File "/home/patanet/pyvenv/lib/python3.4/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/patanet/pyvenv/lib/python3.4/site-packages/django/views/generic/base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/patanet/pyvenv/lib/python3.4/site-packages/django/views/generic/base.py", line 87, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/patanet/pyvenv/lib/python3.4/site-packages/django/views/generic/detail.py", line 115, in get
    context = self.get_context_data(object=self.object)
  File "./generator/views/songs.py", line 70, in get_context_data
    context['content'] = _read_song(context['song'])
  File "./generator/views/songs.py", line 55, in _read_song
    return parse_song(path)
  File "./generator/songs.py", line 25, in parse_song
    return fd.read()
  File "/usr/local/lib/python3.4/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 62: ordinal not in range(128)

Je vais regarder d'où ça peut venir, et si je la reproduis en local, mais si vous avez une idée je suis preneur. Ping @paternal pour les erreurs d'encoding =)

Non reproductible en local, la seule différence porte sur la locale du système : C sur le serveur, fr_FR.UTF-8 chez moi. En changeant la locale du serveur, tout refonctionne.

Ca correspond à cela vraisemblablement : https://bugs.python.org/issue19846

Youpi, un bug python ... Bon, je m'en vais documenter ça, étant donné qu'il s'agit d'une erreur peut courante et facile à corriger.

Est-il possible de détecter la locale lors du démarrage ? (et d'afficher un message d'erreur avec correction si la locale est "C").

Ça peut se faire aussi en effet.

Yo! J'ai essayé de jeter un œil à ça. J'ai suivi la doc (avec python 3.4.2) pour installer et lancer l'application, mais j'obtiens l'erreur suivante :

$ ./manage.py migrate
Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/django/core/management/__init__.py", line 312, in execute
    django.setup()
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/django/apps/registry.py", line 108, in populate
    app_config.import_models(all_models)
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/django/apps/config.py", line 198, in import_models
    self.models_module = import_module(models_module_name)
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/importlib/__init__.py", line 109, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "<frozen importlib._bootstrap>", line 1471, in exec_module
  File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
  File "/home/louis/projets/patacrep/virtualenv.net/lib/python3.4/site-packages/background_task/models.py", line 8, in <module>
    from StringIO import StringIO
ImportError: No module named 'StringIO'

Que faire (puisque StringIO ne fait pas partie de python 3.4) ?

Il faut se baser sur la branche python3, qui n'est pas encore mergée dans master.

Je suis bien dans cette branche, à jour, avec python 3. Pas le temps d'enquêter davantage ce soir. Je regarde plus tard dans un virtualenv neuf, avec un dépôt neuf.

Vous êtes sûrs que background task est compatible python 3 ? Rien n'est précisé sur le dépôt ou pypi, et le fichier models.py contient l'import à StringIO, qui n'existe plus sous Python3.

La question maintenant, c'est : Pourquoi ça marche chez vous et pas chez moi ? La suite au prochain épisode…

Cf: #100 (comment)
(apparemment, ça n'a pas encore été mergé...)

pip install git+https://github.com/Luthaf/django-background-task.git

La question maintenant, c'est : Pourquoi ça marche chez vous et pas chez moi ? La suite au prochain épisode…

My bad ... J'étais persuadé d'avoir mis à jour le Requirement.txt

Merci pour les réponses. Je ré-essaye tout ça à l'occasion.

Bon, j'ai un problème : chez moi ça marche.

$ LANG=C ./manage.py runserver                                                                               
/home/louis/projets/patacrep/virtualenv/lib/python3.4/importlib/_bootstrap.py:321: RemovedInDjango19Warning: django.contrib.contenttypes.generic is deprecated and will be removed in Django 1.9. Its contents have been moved to the fields, forms, and admin submodules of django.contrib.contenttypes.
  return f(*args, **kwds)

/home/louis/projets/patacrep/virtualenv/lib/python3.4/importlib/_bootstrap.py:321: RemovedInDjango19Warning: django.contrib.contenttypes.generic is deprecated and will be removed in Django 1.9. Its contents have been moved to the fields, forms, and admin submodules of django.contrib.contenttypes.
  return f(*args, **kwds)

Performing system checks...

System check identified no issues (0 silenced).
May 03, 2015 - 19:39:31
Django version 1.8.1, using settings 'patanet.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Et a priori, tous les paquets sont à jour.

$ python --version
Python 3.4.1

$ pip freeze
Babel==1.3
Django==1.8.1
Jinja2==2.7.3
MarkupSafe==0.23
Pillow==2.8.1
Pygments==2.0.2
Sphinx==1.3.1
Unidecode==0.04.17
alabaster==0.7.3
argparse==1.2.1
astroid==1.3.6
cffi==0.9.2
chardet==2.2.1
django-background-task==0.1.8
django-simple-captcha==0.4.5
docutils==0.12
ipdb==0.8
ipython==3.1.0
jsonfield==1.0.3
lesscpy==0.10.2
logilab-common==0.63.2
patacrep==4.0.0
ply==3.4
pycparser==2.12
pygit2==0.21.0
pylint==1.4.3
pytz==2015.2
six==1.9.0
snowballstemmer==1.2.0
sphinx-rtd-theme==0.1.7

Une idée ?

Le serveur se lance sans problème, mais c'est en accédant à une chanson que ça plante. Donc si tu as importé des chansons, va sur la page des paroles de cette chanson.

Je ne sais pas d'ou vient le problème, mais en diagnostiquant, j'ai l'impression d'avoir trouvé par hasard un moyen de contourner le problème.

diff --git a/generator/songs.py b/generator/songs.py
index 772a496..d89573e 100644
--- a/generator/songs.py
+++ b/generator/songs.py
@@ -18,8 +18,10 @@
 Functions for song file (.sg) rendering.
 """

+import codecs
+
 def parse_song(filename):
     """Parse song 'filename', and return the corresponding HTML code."""
     # TODO
-    with open(filename) as fd:
+    with codecs.open(filename) as fd:
         return fd.read()

Dites moi ce que vous en pensez…

Selon http://programmers.stackexchange.com/a/168645,
open(filename, encoding='utf-8') devrait aussi fonctionner.

L'une ou l'autre solution me convient totalement =)

Pendant le développement, je pense que c'est bien de cherche à corriger cela. En production, ça pourra être bien d'utiliser l'option errors="replace" de open(), pour que de telles erreurs, qu'elles viennent de l'utilisateur ou des développeurs, ne renvoient pas une erreur moche à l'utilisateur.
Le mauvais côté, c'est qu'on ignore les erreurs, et qu'on ne va plus les corriger…

Je pense qu'en production il faut éviter d'afficher les erreurs, mais les reporter aux dev (dans ce cas, afficher une page "Erreur 500" et avoir des logs quelque part qui indiquent le problème).
Sinon on risque des pertes de données (des caractères seront remplacés par '?' et le débogage deviendra impossible)

Cette issue semble résolue (au moins dans mon test avec #142). Vous confirmez ?

Je n'ai jamais eu ce problème, mais la lecture étant désormais effectuée par patacrep, je pense qu'on peut clore cette issue (mais j'ai quand même un problème d'encodage qui traîne)