Как обойти проблему, связанную с тем, что сообщения Python WindowsError неправильно закодированы?

Это проблема, когда Python вызывает WindowsError, кодировка сообщения об исключении всегда os-native-encoded. Например:

import os
os.remove('does_not_exist.file')

Ну, здесь мы получаем исключение:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 2] 系統找不到指定的檔案。: 'does_not_exist.file'

Поскольку языком моей Windows7 является традиционный китайский, сообщение об ошибке по умолчанию, которое я получаю, имеет кодировку big5 (известную как CP950).

>>> try:
...     os.remove('abc.file')
... except WindowsError, value:
...     print value.args
...
(2, '\xa8t\xb2\xce\xa7\xe4\xa4\xa3\xa8\xec\xab\xfc\xa9w\xaa\xba\xc0\xc9\xae\xd7\xa1C')
>>>

Как вы видите здесь, сообщение об ошибке не является Unicode, тогда я получу другое исключение кодировки, когда попытаюсь распечатать его. Вот проблема, ее можно найти в списке проблем Python: http://bugs.python.org/issue1754< /а>

Вопрос в том, как обойти это? Как получить родную кодировку WindowsError? Я использую версию Python 2.6.

Спасибо.


person Fang-Pen Lin    schedule 19.04.2010    source источник
comment
Если вы получаете исключение при печати, покажите исключение. Печать должна работать, см. мой ответ ниже.   -  person Mark Tolonen    schedule 20.04.2010


Ответы (3)


У нас такая же проблема в русской версии MS Windows: кодовая страница локали по умолчанию cp1251, но кодовая страница консоли Windows по умолчанию cp866:

>>> import sys
>>> print sys.stdout.encoding
cp866
>>> import locale
>>> print locale.getdefaultlocale()
('ru_RU', 'cp1251')

Решение должно состоять в том, чтобы декодировать сообщение Windows с кодировкой локали по умолчанию:

>>> try:
...     os.remove('abc.file')
... except WindowsError, err:
...     print err.args[1].decode(locale.getdefaultlocale()[1])
...

Плохая новость заключается в том, что вы все еще не можете использовать exc_info=True в logging.error().

person newtover    schedule 20.04.2010

sys.getfilesystemencoding() должно помочь.

import os, sys
try:
    os.delete('nosuchfile.txt')
except WindowsError, ex:
    enc = sys.getfilesystemencoding()
    print (u"%s: %s" % (ex.strerror, ex.filename.decode(enc))).encode(enc)

Для других целей, кроме печати на консоль, вы можете изменить окончательную кодировку на «utf-8».

person Alexander Lebedev    schedule 19.04.2010

Это просто строка repr() того же сообщения об ошибке. Поскольку ваша консоль уже поддерживает cp950, просто напечатайте нужный компонент. Это работает в моей системе после перенастройки для использования cp950 в моей консоли. Мне пришлось явно вызвать сообщение об ошибке, так как моя система английская, а не китайская:

>>> try:
...     raise WindowsError(2,'系統找不到指定的檔案。')
... except WindowsError, value:
...     print value.args
...
(2, '\xa8t\xb2\xce\xa7\xe4\xa4\xa3\xa8\xec\xab\xfc\xa9w\xaa\xba\xc0\xc9\xae\xd7\xa1C')
>>> try:
...     raise WindowsError(2,'系統找不到指定的檔案。')
... except WindowsError, value:
...     print value.args[1]
...
系統找不到指定的檔案。

В качестве альтернативы используйте Python 3.X. Он печатает repr(), используя кодировку консоли. Вот пример:

Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> '系統找不到指定的檔案。'
'\xa8t\xb2\xce\xa7\xe4\xa4\xa3\xa8\xec\xab\xfc\xa9w\xaa\xba\xc0\xc9\xae\xd7\xa1C'

Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> '系統找不到指定的檔案。'
'系統找不到指定的檔案。'
person Mark Tolonen    schedule 20.04.2010
comment
На самом деле, я получаю исключение, когда пытаюсь записать сообщение об ошибке в логгер, и поэтому мне приходится решать эту проблему. Обработчик регистратора может быть файлом, консолью и даже SMTP. Кроме того, консоль может быть не той кодировки, что и ОС Windows, например, запустить программу IDLE или Pydev, кажется, что кодировка utf8, а не CP950, только при запуске программы с CMD Windows, это будет локаль кодирование. - person Fang-Pen Lin; 22.04.2010