RU | EN

От Perl-скрипта к Twisted-приложению: Переходим на Unicode

В случае, если предполагается, что приложение будет работать более чем с одной кодировкой, то оправдано использование unicode для внутреннего представления данных. При таком решении, перекодировка осуществляется только на входе/выходе данных и информация о кодировках "концентрируется" в этих местах, а не "таскается" по всему приложению.
Если говорить про демо-приложение TwistedPythy, то у транспорта и БД кодировки вполне могут быть различными (например, у меня вышло, что у транспорта cp866, а у БД - cp1251). Выделяю места, где будут происходить перекодировки из/в unicode:

  • вход транспорта (lineReceived), из строки в кодировке транспорта в unicode
  • выход транспорта (sendLine), из unicode в строку в кодировке транспорта
  • вход клиента (getClient), из unicode в строку в кодировке БД
  • выход клиента (getClient), из строки в кодировке в кодировке БД в unicode
Во всех остальных местах и вход и выход - unicode.
Переписываем клиента DummyClient, чтобы он возвращал unicode, а не str, называем его UnicodeDummyClient:

class UnicodeDummyClient(DummyClient): """Dummy client for testing purposes with I/O data in unicode""" def getClient(self, agreem_num): assert isinstance(agreem_num, unicode) res = u'Dummy_%s' % agreem_num if len(res) > 20: res = res[:20] # для имитации задержки выборки данных time.sleep(self.pause_time) return res

аналогичным образом изменяем и AsyncPythyProto:

class AsyncUnicodePythyProto(AsyncPythyProto): """ Simple text demo protocol with async method for fetching data and internal data in unicode """ def lineReceived(self, line): assert(line, str) log.msg("data received from %s: `%s'" % (str(self.transport.client), line)) if line == '': self.sendLine(u"Good bye") self.transport.loseConnection() return # str -> unicode line = line.decode(self.factory.encoding) agr = line[10:15] deferred = threads.deferToThread(self.factory.clients.getClient, agr) deferred.addCallback(self._cbGetClient) def sendAnswer(self, client): assert isinstance(client, unicode) packet = u'u0442u0435u0441u0442%s' % client self.sendLine(packet) def sendLine(self, line): assert isinstance(line, unicode) line = line.replace('r', '').replace('n', '') # unicode -> str line = line.encode(self.factory.encoding) log.msg("data send: %s" % line) line = line + "rn" self.transport.write(line)

Вроде все. Код, по обычаю, - на RapidShare.
P.S. В следующий раз будем писать юнит-тесты.

Источники:
gorod-omsk.ru/blog/pythy/

Комментарии: