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.

RuntimeError, Python 3 et Click

+2 votes

J’ai un script Bottle qui est déclenché lors d’un hook Bitbucket, qui pull+update le repo local et lance un build MkDocs:

from bottle import post, run, redirect
import os

@post('/update/')
def update():
    os.system("hg pull -u")
    os.system("mkdocs build --clean")
    return redirect("/")

run(host='localhost', port=8020)

Après un update du système ou je ne sais quoi, ce script crash au niveau de MkDocs:

added 1 changesets with 1 changes to 1 files
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Traceback (most recent call last):
  File "/usr/bin/mkdocs", line 11, in <module>
    sys.exit(cli())
  File "/opt/python3.4/lib/python3.4/site-packages/click/core.py", line 700, in __call__
    return self.main(*args, **kwargs)
  File "/opt/python3.4/lib/python3.4/site-packages/click/core.py", line 655, in main
    raise RuntimeError('Click will abort further execution '
RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment. Either switch to Python 2 or consult http://click.pocoo.org/python3/ for mitigation steps.

Dans un terminal il n’y a pas de problème avec MkDocs.

Je ne sais pas quoi faire après avoir lu cette page: http://click.pocoo.org/5/python3/

L'affaire se passe sur un Raspberry Pi 2, Raspbian Wheezy.

demandé 12-Sep-2015 par batisteo (174 points)
reclassée 14-Sep-2015 par batisteo

3 Réponses

+3 votes
 
Meilleure réponse

Ca ressemble un problème dû a os.system qui n'utiliserait pas l'encoding de sys.stdin et sys.stdout ("Changes to sys.stdin, etc. are not reflected in the environment of the executed command.")

Ca marche dans ton shell parceque son encoding est connu (très certainement utf-8). La lib click est visiblement utilisé par mkdocs.

Tu peut peut-être t'en sortir en utilisant subprocess.Popen, avec quelque chose du genre :

import sys
import subprocess as sp
# pas sur de l'encoding utilisé pour stdin et stdout ici
process = sp.Popen(["mkdocs", "build", "--clean"], stdin=sp.PIPE, stdout=sp.PIPE)

Ou en adaptant l'exemple qu'ils donnent sur http://click.pocoo.org/5/python3/ , en utilisant des streams dont l'encoding est connu pour stdin/stdout:

import io
in_stream = io.BytesIO(input.encode('utf-8'))
sp_stdin = io.TextIOWrapper(in_stream, encoding='utf-8')
out_stream = io.BytesIO()
sp_stdout = io.TextIOWrapper(out_stream, encoding='utf-8')

process = sp.Popen(["mkdocs", "build", "--clean"], stdin=sp_stdin, stdout=sp_stdout)
répondu 13-Sep-2015 par jc (2,674 points)
sélectionné 14-Sep-2015 par batisteo

Le code précédent ne fonctionne pas car input n’est pas défini. La doc suggère input = 'Input here'.

Que devrais-je mettre ?

Effectivement, allé un peu vite.

Ca correspondrait a ce que tu voudrais écrire sur l'entrée standard de makedocs, donc dans ton cas, rien.

C'est a corriger en remplaçant

in_stream = io.BytesIO(input.encode('utf-8'))

Par

in_stream = io.BytesIO()

Merci, mais maintenant j’ai ça :

Traceback (most recent call last):   File "/opt/python3.4/lib/python3.4/site-packages/bottle.py", line 862, in
_handle
    return route.call(**args)   File "/opt/python3.4/lib/python3.4/site-packages/bottle.py", line 1732, in wrapper
    rv = callback(*a, **ka)   File "./update.py", line 16, in update
    process = sp.Popen(["mkdocs", "build"], stdin=sp_stdin, stdout=sp_stdout)   File "/opt/python3.4/lib/python3.4/subprocess.py", line 823, in
__init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)   File "/opt/python3.4/lib/python3.4/subprocess.py", line 1290, in
_get_handles
    p2cread = stdin.fileno() io.UnsupportedOperation: fileno

Erf

Effectivement, ce n'est pas possible de filer du StringIO ou TextIOWrapper directement a subprocess.Popen. Ca m'apprendra a ouvrir un shell avant de poster ;)

Si la solution utilisant subprocess.PIPE ne donne rien, il va falloir feinter autrement :/

D'apres la doc : http://click.pocoo.org/5/python3/#python-3-surrogate-handling

The biggest source of frustration is that Click scripts invoked by init systems (sysvinit, upstart, systemd, etc.), deployment tools (salt, puppet), or cron jobs (cron) will refuse to work unless a Unicode locale is exported.

If Click encounters such an environment it will prevent further execution to force you to set a locale

Du coup, il faudrait que tu exporte

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

avant de lancer ton app bottle.

+2 votes

Je ferai un virtualenv python2 pour conserver les outils de prod intact
Puis un virtualenv python3 pour voir en détails ce que Click recommande, parce-que click "avoue" qu'avec python3 , des fois, ça crash
Par contre je n'ai pas vu où Click était utilisé dans le script bottle. Peut-être un test avec fabric (fabfile.org) ferait l'affaire

répondu 13-Sep-2015 par foxmask (2,842 points)
edité 13-Sep-2015 par foxmask

J’utilise MkDocs avec des lettres accentuées donc Python 2 n’est pas une option pour moi.

Bottle est utilisé juste pour récupérer une requête POST lancé par un webhook. Comme ça la doc se regénère toute seule sur le serveur après un changement en ligne sur Bitbucket. Comment pourrais-je remplacer ceci par Fabric ?

Click est utilisé par MkDocs seulement, pas Bottle.

j'avais compris que la maj systeme avait eu pour consequence le passage de python 2 à 3 .
Si ca marchait avant en python 3, pourquoi ca ne marcherait plus d'un coup ?

Sinon je rejoins JC sur l'encoding défini dans ton shell au lancement de mkdocs. Encoding qui n'est pas défini avec bottle au lancement de mkdocs.

du coup j'aurai plutot fait :

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

avant le lancement de mkdocs

+2 votes

Il semblerait que ça soit supervisord qui n’aie pas été lancé avec les bonnes variables d’environnement. Ce n’est pas l’update du système qui a causé le problème, mais ma configuration hésitante.

Subprocesses will inherit the environment of the shell used to start the supervisord program. Several environment variables will be set by supervisord itself in the child’s environment also […]
-- http://supervisord.org/subprocess.html#subprocess-environment

Je l’ai tué, bien défini mes LC_ALL et LANG dans mon .bashrc puis ai relancé supervisord.

Merci à foxmask et surtout à jc !!

répondu 14-Sep-2015 par batisteo (174 points)

Effectivement ; avec supervisor j'ai eu le meme probleme avec mes logs qui partaient en sucette comme ca :

  "J\u2019ai test\xe9"

Avec environnement defini dans la conf ce fut rectifié :)

...