Unicode
С ранних дней Python 2 юникод был частью всех стандартных сборок Python. Это позволяет разработчикам писать приложения, работающие с не-ASCII символами простым способом. Но работа с юникодом требует базовых знаний об этом вопросе, особенно при работе с библиотеками, которые его не поддерживают.
Werkzeug использует юникод везде внутри, где предполагаются текстовые данные, даже если стандарт HTTP не поддерживает юникод. В основном все входные данные декодируются из указанного набора символов (по умолчанию utf-8), чтобы вы больше не работали с байтовыми строками. Выходные данные в формате юникод затем кодируются обратно в целевой набор символов.
Юникод в Python
В Python 2 существуют два основных типа строк: str и unicode. str может содержать закодированные данные юникода, но они всегда представлены в байтах, тогда как тип unicode не содержит байтов, а содержит кодовые точки. Что это значит? Представьте немецкий диакритический знак ö. В ASCII этот символ нельзя представить, но в наборах символов latin-1 и utf-8 его можно представить, но они выглядят по-разному при кодировании:
>>> u'ö'.encode('latin1')
'\xf6'
>>> u'ö'.encode('utf-8')
'\xc3\xb6'
Таким образом, ö может выглядеть совершенно по-разному в зависимости от кодировки, что затрудняет его использование. Решением является использование типа unicode (как мы сделали выше, обратите внимание на префикс u перед строкой). Тип unicode не хранит байты для ö, а хранит информацию о том, что это LATIN SMALL LETTER O WITH DIAERESIS.
Выполнение len(u'ö') всегда даст нам ожидаемое значение «1», но len('ö') может давать разные результаты в зависимости от кодировки 'ö'.
Юникод в HTTP
Проблема с юникодом заключается в том, что HTTP не знает, что такое юникод. HTTP ограничен байтами, но это не большая проблема, так как Werkzeug автоматически декодирует и кодирует все входные и выходные данные. По сути, это означает, что данные, отправленные из браузера в веб-приложение, по умолчанию декодируются из байтовой строки utf-8 в строку unicode. Данные, отправленные из приложения обратно в браузер, которые еще не являются байтовой строкой, затем кодируются обратно в utf-8.
Обычно это «просто работает», и нам не нужно беспокоиться об этом, но есть ситуации, когда это поведение проблемно. Например, уровень ввода-вывода Python 2 не поддерживает юникод. Это означает, что всякий раз, когда вы работаете с данными из файловой системы, вы должны правильно их декодировать. Правильный способ загрузки текстового файла из файловой системы выглядит следующим образом:
f = file('/path/to/the_file.txt', 'r')
try:
text = f.decode('utf-8') # assuming the file is utf-8 encoded
finally:
f.close()
Также есть модуль codecs, который предоставляет функцию open, которая автоматически декодирует из заданной кодировки.
Обработка ошибок
Функции, которые выполняют внутреннюю кодировку или декодирование, принимают ключевой аргумент errors, который передается в str.decode() и str.encode(). Значение по умолчанию — 'replace', чтобы ошибки было легко обнаружить. Может быть полезно установить его в 'strict', чтобы перехватить ошибку и сообщить клиенту о некорректных данных.
Объекты запроса и ответа
Поскольку объекты запроса и ответа обычно являются центральными элементами приложений, работающих с Werkzeug, вы можете изменить кодировку по умолчанию, на которой работает Werkzeug, путем наследования этих двух классов. Например, вы можете легко установить для приложения кодировку utf-7 и строгую обработку ошибок:
from werkzeug.wrappers import BaseRequest, BaseResponse
class Request(BaseRequest):
charset = 'utf-7'
encoding_errors = 'strict'
class Response(BaseResponse):
charset = 'utf-7'
Обратите внимание, что обработка ошибок настраивается только для всех декодирований, но не для кодирования. Если Werkzeug обнаруживает ошибку кодирования, он вызовет UnicodeEncodeError. Вы несете ответственность за то, чтобы не создавать данных, которые отсутствуют в целевом наборе символов (это не проблема для всех кодировок юникода, таких как utf-8).
Файловая система
Изменено в версии 0.11.
До версии 0.11 Werkzeug использовал функциональность стандартной библиотеки Python для определения кодировки файловой системы. Однако несколько сообщений об ошибках для Werkzeug показали, что значение sys.getfilesystemencoding() нельзя доверять в традиционных системах UNIX. Обычно проблемы возникают из-за неправильно настроенных систем, где LANG и аналогичные переменные окружения не установлены. В таких случаях Python по умолчанию использует ASCII в качестве кодировки файловой системы, что является очень консервативным значением по умолчанию, которое обычно неправильно и вызывает больше проблем, чем предотвращает.
Поэтому Werkzeug принудительно установит кодировку файловой системы в UTF-8 и выведет предупреждение всякий раз, когда он обнаруживает, что работает под BSD или Linux, а sys.getfilesystemencoding() возвращает кодировку ASCII.
См. также werkzeug.filesystem.
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://werkzeug.palletsprojects.com/en/0.15.x/unicode/