Fork me on GitHub
29/7/2006

От 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'\u0442\u0435\u0441\u0442%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 + "\r\n"

        self.transport.write(line)

Вроде все. Код, по обычаю, - на RapidShare.

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

Комментарии

Все статьи