Найти - Пользователи
Полная версия: Проблема с кодировкой
Начало » Python для новичков » Проблема с кодировкой
1 2 3 4 5 6 7
pyuser
Тут где-то человек употребляющий наркотики мелькал - честно, я наверно завидую ему - жизнь в розовом свете. К несчастью в реальной жизни есть кодировки… чего я уже только не читал…
Решил, по рекомендациям на сайте, использовать utf-8, блин, как бабушка пошептала, столько проблем исчезло…, и вот получил исключение в пакете logging…
уж казалось бы, библиотечный модуль и на тебе… может просто, чтобы жизнь медом не казалась….

проблема в следующем: win32, скрипт в utf-8, но логи (файл) должны писаться в windows-1251 (cp1251 по нашему), всякие там info, error, warning (стандартные функции logger'а) работают на ура, но вот exception…

ведь к тому, как exception (стандартная, опять же, функция logger'а) я не имею ни какого отношения….

уточню, лог выводится на консоль и в файл, файл - это FileHandler с параметром encoding=“cp1251” (повторюсь, скрипт coding: utf-8)… творится нечто непонятное, часть выводиводится на консоль, но возникает исключение при записи в файл, а периодически не выводмтся ни на консоль ни в файл….

ну и тут я почти как, Достоевский: кто виноват и что делать… ну достало уже….

PS: Python 2.4.x и Python 2.6.x
bw
Выложи работающий и не работающий примеры.

..bw
pyuser
bw
Выложи работающий и не работающий примеры.
..bw
Если это адресованно мне, то я, право, затрудняюсь с ответом… exception вещь не предсказуемая :(
код работает. проблема в том, что не все ошибки в лог попадают, и из-за того что не все попадает трудно понять что же происходит

исходники не проблема :)
bw
К тебе (вам).

..bw
pyuser
Вот банальный пример:
# -*- mode: python; coding: utf-8 -*-
from __future__ import print_function, division
"""
"""
#####################################################################################

import os, sys

import logutils
#####################################################################################

def main () :
log = logutils.getLogger()
try :
raise RuntimeError(u"Проверка связи")
except :
log.exception("")
#####################################################################################

if __name__ == "__main__" :
logutils.set_logger("test.log")
main()
#################################### End Of File ####################################

# logutils.py

# -*- mode: python; coding: utf-8 -*-
"""
по большей части автор модуля Андрей Светлов
"""
#####################################################################################

import os, sys
import logging, logging.handlers
#####################################################################################

for name in dir(logging) :
if not name.startswith('_') :
globals()[name] = getattr(logging, name)
#####################################################################################

def _get_instance_name (instance) :
return instance.__class__.__module__ + "." + instance.__class__.__name__ + ".0x.." + hex(id(instance))[-2:]

class class_logger (object) :
'''Class logger descriptor'''
def __init__ (self, name=None) :
self._logger = None
self._name = name

def __get__ (self, instance, owner) :
if self._logger is None:
if self._name is None:
self._name = owner.__module__ + "." + owner.__name__
self._logger = logging.getLogger(self._name)
return self._logger

class instance_logger (object) :
'''Instance logger descriptor'''
def __init__ (self, name=None) :
self._logger = None
self._name = name

def __get__ (self, instance, owner) :
assert instance is not None
if self._logger is None:
if self._name is None:
self._name = _get_instance_name(instance)
self._logger = logging.getLogger(self._name)
return self._logger

def set_logger (fname="", level=DEBUG, maxSize=5242880, viewName=True, backupCount=0) :
namestr = ""
if viewName :
if sys.version_info[:2] == (2, 4) :
namestr = "%(name)s#"
else :
namestr = "%(name)s.%(funcName)s#"

_console = logging.StreamHandler(sys.stdout)
_console.setLevel(level)
formatter = logging.Formatter(namestr + "%(message)s")
_console.setFormatter(formatter)

log = getLogger("")
log.addHandler(_console)

_file = None
if fname :
if maxSize > 0 :
_file = logging.handlers.RotatingFileHandler(fname, "ab", maxSize, backupCount, encoding="cp1251")
else :
_file = logging.FileHandler(fname, "ab", encoding="cp1251")
_file.setLevel(level)
formatter = logging.Formatter("%(asctime)s#" + namestr + "%(levelname)s#%(message)s")
_file.setFormatter(formatter)
log.addHandler(_file)

log.setLevel(level)
return (_console, _file)

def close_logger (handlers) :
log = getLogger("")
for handler in handlers :
if handler :
handler.flush()
handler.close()
log.removeHandler(handler)
#################################### End Of File ####################################
в приведенном примере ошибка выводится на консоль, а при записи в файл получаем исключение, если строку log.exception(“”) заменить на log.exception(u“”) то исключение возникает, как при выводе на консоль так и при выводе в файл

ЗЫ. если путь к тестовому модулю не содержит русских букв, то исключений не получится :)

widows xp, python 2.6
pyuser
В принципе, это конечно не критично, есть модуль traceback, на сайте activestate есть модуль safe_unicode (к своему стыду дорлжен признаться, что ссылку не помню, но там хорошо работает поиск :))
т.е. все можно обойти, правда потребуются лишние телодвижения…
pyuser
Доброго времени суток!
Что-то у меня вообще все сломалось :(
Python 2.6 (2.4), Windows XP SP3 локаль русская.
вот небольшой кусок кода:
# -*- mode: python; coding: utf-8 -*-
from __future__ import print_function, division

import codecs, os, sys
sys.stdout = codecs.getwriter('cp866')(sys.stdout, errors='replace')

import logging, logging.handlers

if "__main__" == __name__ :
log = logging.getLogger()

_console = logging.StreamHandler(sys.stdout)
_console.setLevel(logging.DEBUG)
log.addHandler(_console)

_file = logging.handlers.RotatingFileHandler("test.log", "ab", 5242880, 0, encoding="cp1251")
_file.setLevel(logging.DEBUG)
log.addHandler(_file)

log.setLevel(logging.DEBUG)

## пробуем, что получилось
log.info(u"Проба пера")

_file.flush()
_file.close()
log.removeHandler(_file)

_console.flush()
_console.close()
log.removeHandler(_console)
при выполнении получаю следующее:
Traceback (most recent call last):
File "C:\Python26\lib\logging\__init__.py", line 765, in emit
self.stream.write(fs % msg.encode("UTF-8"))
File "C:\Python26\lib\codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
File "C:\Python26\lib\encodings\cp866.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_map)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 14: ordinal
not in range(128)
Traceback (most recent call last):
File "C:\Python26\lib\logging\__init__.py", line 765, in emit
self.stream.write(fs % msg.encode("UTF-8"))
File "C:\Python26\lib\codecs.py", line 686, in write
return self.writer.write(data)
File "C:\Python26\lib\codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
File "C:\Python26\lib\encodings\cp1251.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 43: ordinal
not in range(128)
если в коде закоментировать строку sys.stdout = codecs.getwriter('cp866')(sys.stdout, errors='replace')
то получаю следующий вывод:
root.<module>#Проба пера!
Traceback (most recent call last):
File "C:\Python26\lib\logging\__init__.py", line 765, in emit
self.stream.write(fs % msg.encode("UTF-8"))
File "C:\Python26\lib\codecs.py", line 686, in write
return self.writer.write(data)
File "C:\Python26\lib\codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
File "C:\Python26\lib\encodings\cp1251.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 43: ordinal
not in range(128)
если же снова раскоментировать строку sys.stdout = codecs.getwriter('cp866')(sys.stdout, errors='replace')
и в файле C:\Python26\Lib\logging\__init__.py строки с 753 по 770 включительно заменить на
        try:
msg = self.format(record)
fs = "%s\n"
if isinstance(msg, unicode) :
self.stream.write(fs % msg)
else:
self.stream.write(fs % msg.decode(self.stream.encoding)) # здесь бы по идее подставить кодировку сообщения, но как ее угадаешь :)
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
то и в консоль и в файл все выводится без ошибок.
однако править родной модуль Python не есть правильная практика, отсюда вопрос - как быть?

PS. при указанной замене в файле C:\Python26\Lib\logging\__init__.py и закоментированной строке sys.stdout = codecs.getwriter('cp866')(sys.stdout, errors='replace')
получаем ошибку при выводе на консоль, но нормальный вывод в файл
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB