Kivy: Проблема с кодировкой файла kv 'utf-8' в Windows

Созданный на 16 февр. 2016  ·  24Комментарии  ·  Источник: kivy/kivy

Я разрабатываю многоплатформенное приложение для Linux и Windows 7. Все мои файлы сначала были написаны в Linux и закодированы как utf-8 , но когда я открываю этот же проект в Windows, файл kv читается с использованием кодировки cp1252 . То же самое, кажется, не происходит с моими файлами .py возможно, потому, что я использую python3.

Как следствие, символы Юникода, записанные в файле kv , некорректно отображаются в приложении Kivy. Строка 'Título' будет отображаться как TÃ-tulo .

Мои настройки: Kivy = 1.9.1, Python = 3.4.4, Windows 7 x64 Home Premium.

Также мой питон был установлен с использованием Anaconda, но это, вероятно, не связано.

Чтобы воспроизвести проблему:

Напишите файл kv закодированный с помощью utf-8 :

# test.kv
<myButton@Button>:
    text: 'Título'

В интерпретаторе python или .py script:

import kivy
from kivy.lang import Builder
from kivy.uix.button import Button

Builder.load_file('test.kv')
class myButton(Button):
    pass

print( myButton().text == 'Título' ) # False
print( myButton().text.encode('cp1252').decode() == 'Título' ) # True

Мультиплатформенный обходной путь, который я нашел, заключался в следующем:

# test.kv
<myButton@Button>:
    text: str(b'T\xc3\xadtulo'.decode())

Самый полезный комментарий

Да @ChristianTremblay , это только ошибка Windows. Фактически это связано с тем, что кодировка Windows по умолчанию - cp1252, в результате чего Kivy читает файл .kv, как если бы он был закодирован таким образом. Возможно, решение, предложенное @KeyWeeUsr, действительно помогает, я этого не пробовал, но может быть чище, чем другой предложенный обходной путь.

Я согласен, хорошим решением было бы разрешить кодирование спецификации в файле .kv, как это делается в python:

# -*- coding: utf-8 -*-
<MyWidget>:
    # ...

Все 24 Комментарий

К вашему сведению - немного более простой способ обойти это - использовать литералы Unicode:

<MyButton@Button>:
    text: u'T\u00edtulo'

Спасибо, воспользуюсь этим =)

Для кого-то еще, использующего эту работу, если вы хотите найти escape-последовательность Unicode для своего символа Unicode, вы можете найти ее так:

>> hex( ord('ã') )
0xe3
>> u'\u00e3'
'ã'

Вы не думаете, что должен быть способ лучше? (слышит, как Хеттингер говорит ...)

заголовок #, в котором рассказывается, как следует обрабатывать символ Юникода?

Даже если этот трюк сработает ... из-за этого текст становится очень трудно читать, когда много символов Юникода ...

Это только ошибка Windows?

Что ж, это не рекомендуемый способ обработки кодировок, но вы можете его использовать. Он работал у меня в py2.7 с kivy 1.8.0, но мог работать даже с py3. Файлы, сохраненные как символы utf-8 , \u... используются непосредственно как u'ä'

    import sys
    reload(sys)
    sys.setdefaultencoding("utf-8")

Да @ChristianTremblay , это только ошибка Windows. Фактически это связано с тем, что кодировка Windows по умолчанию - cp1252, в результате чего Kivy читает файл .kv, как если бы он был закодирован таким образом. Возможно, решение, предложенное @KeyWeeUsr, действительно помогает, я этого не пробовал, но может быть чище, чем другой предложенный обходной путь.

Я согласен, хорошим решением было бы разрешить кодирование спецификации в файле .kv, как это делается в python:

# -*- coding: utf-8 -*-
<MyWidget>:
    # ...

Что, если бы utf-8 был обязательным для файлов kv?

    def load_file(self, filename, **kwargs):
        '''Insert a file into the language builder and return the root widget
        (if defined) of the kv file.

        :parameters:
            `rulesonly`: bool, defaults to False
                If True, the Builder will raise an exception if you have a root
                widget inside the definition.
        '''
        filename = resource_find(filename) or filename
        if __debug__:
            trace('Builder: load file %s' % filename)
        with open(filename, 'r', encoding='utf-8') as fd:
            kwargs['filename'] = filename
            data = fd.read()

            # remove bom ?
            if PY2:
                if data.startswith((codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE)):
                    raise ValueError('Unsupported UTF16 for kv files.')
                if data.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)):
                    raise ValueError('Unsupported UTF32 for kv files.')
                if data.startswith(codecs.BOM_UTF8):
                    data = data[len(codecs.BOM_UTF8):]

            return self.load_string(data, **kwargs)

Это находится в строке 275 и выше kivy / lang / builder.py.

@ChristianTremblay , я думаю, это было бы не к лучшему. Некоторые пользователи могут по-прежнему использовать текстовые редакторы с кодировкой по умолчанию, отличной от utf-8, например кодировкой Windows по умолчанию cp1252. Мы должны найти решение для обоих.

Лучше всего было бы имитировать поведение Python:

  • Ожидайте, что программист укажет кодировку в первой строке.
  • Или используйте кодировку Python по умолчанию (на python3 это всегда будет «utf8», я думаю).

Возникла проблема на Android:

An unanticipated UnicodeDecodeError occurred: 'ascii' codec can't decode byte 0xef in position 564: ordinal not in range(128)
Traceback (most recent call last):  
  File "./pages.py", line 21, in <module>
    Builder.load_file('pages.kv')
  File "/data/data/.../files/app/crystax_python/site-packages/kivy/lang/builder.py", line 290, in load_file
    data = fd.read()
  File "/data/data/.../files/app/crystax_python/stdlib.zip/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 564: ordinal not in range(128)

((boggle)) Хотя, похоже, работает на моем Linux.

По умолчанию обязательно должен быть utf-8, хотя и не принудительно.

mixmastamyk У меня была точно такая же проблема.
Мое приложение работает нормально, но когда я создаю APK и запускаю его на своем телефоне Android, я получаю:
UnicodeDecodeError: кодек ascii не может декодировать байт 0xc3 в позиции 352: порядковый номер не в диапазоне (128)
Это потому, что в моем файле есть пара «É». Жаль, что я кодировал на python3, чтобы избежать подобных раздражающих вещей.

Верно. Похоже, что Builder.load_file() должен по умолчанию использовать utf8 и / или иметь параметр кодировки. А пока сделал вот что:

 with open(filename, encoding='utf8') as f:
     Builder.load_string(f.read())

Обязательно отключите автоматическую загрузку для файла kv, иначе ошибка все равно будет выдаваться, и все будет выглядеть так, как будто это не сработало. Форма '\ u2026' также может работать, если это всего лишь один или два символа.

Умная идея. Спасибо!
Я попробую это.

Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время не было активности. Он будет закрыт, если больше не будет активности. Спасибо за ваш вклад.

Как удобно, игнорируйте ошибки и позвольте им закрыться сами.

На самом деле мы выкапывали старые проблемы, чтобы отсортировать их, и никакая действительная проблема, требующая решения, не будет закрыта. Хотя такое отношение не помогает с мотивацией, необходимой для того, чтобы посвятить наши дни проекту.

Раздражает не отсутствие работы, а бот, который закрывает проигнорированные задачи. Возможно, потребуется одна или две строки кода для добавления параметра кодирования в load_file. Сам бы сделал это, но есть 70 невыполненных запросов на вытягивание.

В проекте с ограниченными кадрами не должно быть такого типа бота.

Я все еще рекомендую вам сделать этот запрос на перенос. Если это чистое и простое исправление, у него есть хорошие шансы на объединение.

У меня такая же проблема с kivy 1.10, мое приложение отлично работает на linux с python3 (python3 main.py), но когда я отлаживаю развертывание на моем телефоне Android, приложение вылетает: / очень раздражает, если вы хотите сделать что-то качественно

По-прежнему существует эта проблема с kivy 1.10.1 и python 3.6.6 в Windows 10. Текущий обходной путь не заключается в автоматической загрузке файла .kv. Переименуйте его во что-то, что не загружается по умолчанию, сохраните его в кодировке utf8 и сделайте, как показано в # 5154

from kivy.lang import Builder
with open('MyApp.renamed.kv', encoding='utf8') as f: 
    Builder.load_string(f.read())

Решение @carasuca у меня не работает

киви 1.10.1 питон 3.5.3 окна 7
такое же поведение в Windows 10 и Python 3.6.5

Тот же код отлично работает на osx и linux

РЕДАКТИРОВАТЬ: проблема в директиве языка #:include kv
Решение @carasuca работает тогда и только тогда, когда у вас есть один файл kv и вы загружаете его с помощью Builder.load_string (f.read ()). Если этот kv использует #: include anotherfile.kv, этот файл загружается с неправильной кодировкой.
Решение 1.Сместите весь код kv в один файл
Решение 2:

for kvfile in ['file1.kv', 'file2.kv']:
         with open(kvfile, encoding='utf8') as f:
             Builder.load_string(f.read())

Ну, у меня была такая же ошибка со словами вроде «Número» или «veículo». Я пробовал со следующим кодом:

from kivy.lang import Builder
with open('myApp.kv', encoding='utf8') as f: 
    Builder.load_string(f.read())

Но у меня возникла проблема с этим. Когда я запустил приложение, я увидел, что две разные метки перекрываются.
Решение заключалось в том, чтобы сохранить файл kv в подкаталоге, а затем вызвать его с помощью open следующим образом:

with open('./kvfile/myApp.kv', encoding='utf-8') as f:
            Builder.load_string(f.read())

Проблема была решена, потому что автозагрузка не находит файл kv в том же каталоге, что и main.py. Так что это не будет дублировать визуализацию.

@piontk Привет, я думал, что это будет мое спасение, но когда я попробую, он говорит, что «кодировка» не является допустимым параметром для «open». Почему? (Кроме того, извините, если это глупый вопрос, это мое первое приложение)

Хорошо, я знаю, что это не идеально, но если ни один из этих вариантов не работает для вас, вы можете установить желаемую строку в переменную в основном классе приложения в вашем файле .py, который имеет кодировку utf-8, а затем получить к ней доступ в вашем файле .kv.
#.py
class MainApp(App):
struser = ('Nome de usuário')

#.kv
Label:
text: app.struser

работал на меня

Была ли эта страница полезной?
0 / 5 - 0 рейтинги