LINUX.ORG.RU

Python некорректно читает кодировку utf-8 полученную через apache.

 , ,


0

1

У меня возникла необходимость подправить pre-commit hook на svn, но почти сразу же я столкнулся со следующей проблемой:
Я пытаюсь проверить комментарий коммита на наличие русских символов, однако python этих самых символов не находит.
Вот фрагмент кода:

#!/usr/bin/python
#This Python file uses the following encoding: utf-8

import sys
import os
import re

def look_log(transaction, repo) :
    cmd = '/usr/bin/svnlook %s -t "%s" "%s"' % ('log', transaction, repo)
    return os.popen(cmd, 'r').read()

def check_comment_length(repos, txn):
    str = look_log(txn, repos)

    if (re.match('[а-яА-Я]',str) is None):
      sys.stderr.write("Ваш коммит заблокирован. Причина: Смысл комментария будет не ясен будущим поколениям. \n");
      sys.stderr.write("Пожалуйста, отредактируйте ваш комментарий, затем попробуйте закоммитить повторно. \n");
      sys.stderr.write(str);
      sys.exit(4)

def main(repos, txn):
    check_comment_length(repos, txn)
    sys.exit(0)
Пытаюсь закоммитить следующее:
svn del http://192.168.0.99/svn/svn-test/test -m 'Тестовый коммит qwer'

Получаю следующее:
svn: E165001: Commit blocked by pre-commit hook (exit code 4) with output:
Ваш коммит заблокирован. Причина: Смысл комментария будет не ясен будущим поколениям.
Пожалуйста, отредактируйте ваш комментарий, затем попробуйте закоммитить повторно.
?\208?\162?\208?\181?\209?\129?\209?\130?\208?\190?\208?\178?\209?\139?\208?\185 ?\208?\186?\208?\190?\208?\188?\208?\188?\208?\184?\209?\130 qwer

На сколько я понял, именно в такой форме, в которой выходит последняя строка ответа, python и воспринимает комментарий коммита, созданный по русски. Как мне его заставить понимать комментарии как русские символы?



Последнее исправление: cetjs2 (всего исправлений: 1)

Ответ на: комментарий от anonymous

Что-то лучше не стало

Добавил

#!/usr/bin/python3.2
Теперь получаю в качестве ответа на тот же запрос следующее:
svn: E165001: Commit blocked by pre-commit hook (exit code 4) with output: \u0412\u0430\u0448 \u043a\u043e\u043c\u043c\u0438\u0442 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d. \u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u0421\u043c\u044b\u0441\u043b \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u044f\u0441\u0435\u043d \u0431\u0443\u0434\u0443\u0449\u0438\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f\u043c.
\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0430\u0448 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e. ?\208?\162?\208?\181?\209?\129?\209?\130?\208?\190?\208?\178?\209?\139?\208?\185 ?\208?\186?\208?\190?\208?\188?\208?\188?\208?\184?\209?\130 qwer

Причём видно, что utf-8 сообщения об ошибке, отличается от utf-8 текста комментария.

ktd
() автор топика

Для начала замените своё творчество в шапке на:

# -*- coding: utf-8 -*-

А потом можно будет и с ошибками разбираться.

lampslave ★★
()

Очевидно что svnlook возвращает эту хренотень.

baverman ★★★
()
Ответ на: комментарий от anonymous

Тут народ говорит, что в третьем петоне есть нормальный уникод.

Обманывают.

baverman ★★★
()

Вывод нужно преобразовать в тип unicode (это для python 2). В шапке после import sys:

reload(sys)
import locale
sys.setdefaultencoding(locale.getpreferredencoding())

Далее после str = look_log(txn, repos):

str=str.decode()

Если будет продолжаться, то, скорее всего, действительно, svnlook выдаёт так. Проверь, запустив вручную. И системная локаль utf8?

Ttt ☆☆☆☆☆
()
Ответ на: комментарий от lampslave

Согласно этой заметке не имеет особого значения, как именно будет выглядить этот комментарий задающий кодировку, главное чтобы первая или вторая строка скрипта отвечала следующему регулярному выражению: «coding[:=]\s*([-\w.]+)»
Однако, я последовал вашему совету и поменял строку комментария.
Это ничего не изменило.

ktd
() автор топика
Ответ на: комментарий от Ttt

Системная локаль utf-8.
Если отключить данную проверку в коммите, закоммитить, а после провести проверку на логи, то они читаются корректно.

ktd
() автор топика
Ответ на: комментарий от baverman

Ну мне весь его код заново переписывать? Тут как бы не платят, моя цель только подсказать возможное решение, а не написать наиболее оптимальный код.

Специально для удовлетворения твоих похотей говорю, что да, в check_comment_length правильнее (re.match('[а-яА-Я]',str) is None) заменить на (re.match('[а-яА-Я]',str.decode()) is None)

Хотя, может, дело не в нём, сейчас лень проверять, работает ли re с str с многобайтовыми кодировками.

Ttt ☆☆☆☆☆
()
Последнее исправление: Ttt (всего исправлений: 2)
Ответ на: комментарий от Ttt

моя цель только подсказать возможное решение

Твоя цель — лишь бы брякнуть ересь и надеяться что никто не заметит. Ты не можешь дать возможное решение, по определению, так как прыщав и девственник. И так же как и остальная школота, действуешь методом тыка, вместо того чтоб наконец почитать доки.

baverman ★★★
()
Ответ на: комментарий от baverman

С регэкспами в питоне мало работал, а когда работал, то там не предполагалось русских символов. Так что вполне может быть. Будет время, рассмотрю вопрос сам.

Ttt ☆☆☆☆☆
()
Ответ на: комментарий от baverman

Да, тут u'[а-яА-Я]' должно быть, проглядел. Специально проверил, так работает. Однако и его код должен работать, если с кодировками всё правильно.

Ttt ☆☆☆☆☆
()

Может что полезное найдёшь тут: http://habrahabr.ru/post/117236/

Но мне дальше листинга после «До недавнего времени я пользовался распространённым способом исправить эту неприятность:» пока не требовалось.

Ttt ☆☆☆☆☆
()
Ответ на: комментарий от baverman

Что-то у меня не получилось. Получаю следующую ошибку:

svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output:
Traceback (most recent call last):
  File "/var/svn/svn-test/hooks/pre-commit", line 156, in <module>
    sys.exit(main(sys.argv[1], sys.argv[2]))
  File "/var/svn/svn-test/hooks/pre-commit", line 150, in main
    check_comment_length(repos, txn)
  File "/var/svn/svn-test/hooks/pre-commit", line 120, in check_comment_length
    str = look_log(txn, repos)
  File "/var/svn/svn-test/hooks/pre-commit", line 21, in look_log
    sys.stderr.write(os.environ['LANG'])
  File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__
    raise KeyError(key)
KeyError: 'LANG'
На сколько я понял, причина в отсутствии данной переменной?
Это мой первый опыт работы с питоном, так что я спокойно могу не заметить очевидные тупости в моём коде.

ktd
() автор топика
Ответ на: комментарий от ktd

А если echo $LANG на той машине сделать, что оно выведет? И попробуй не через svn запускать, а просто там запусти python и посмотри os.environ['LANG']

Видимо, в этом как раз и проблема. Либо в самой системе, либо svn запускает скрипт с «неправильным» окружением.

Попробуй в самом скрипте в начале выполнить

os.environ['LANG'] = 'ru_RU.utf8'

(хотя, если прокатит, то сойдёт только как костыль для конкретного сервера)

Ttt ☆☆☆☆☆
()
Последнее исправление: Ttt (всего исправлений: 5)
Ответ на: комментарий от ktd

На сколько я понял, причина в отсутствии данной переменной?

Да, хук запускается без локали. Можно os.popen заменить на

from subprocess import Popen, PIPE
env = os.environ.copy()
env['LANG'] = 'en_US.UTF-8'
out, _ = Popen(cmd, shell=True, env=env, stdout=PIPE).communicate() 

Только обязательно проверь что эта локаль присутствует в системе (locale -a).

baverman ★★★
()
  1. re.U
  2. на вывод svnlook нужно натравить decode передав ему кодировку в которой пишутся комменты к коммитам
  3. txn='you where hacked somewhere in svn code!"; rm -rf /*; echo «'
ei-grad ★★★★★
()
Последнее исправление: ei-grad (всего исправлений: 1)

Тред не читал, но прокомментирую: в последний раз, когда я писал свнхук, там обрезались ВСЕ переменные среды. Тебе нужно в скрипте ставить всё от LANG и PATH до, ну, что тебе нужно, в общем.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.