Kivy: Problema de codificação no arquivo kv 'utf-8' no Windows

Criado em 16 fev. 2016  ·  24Comentários  ·  Fonte: kivy/kivy

Estou desenvolvendo um aplicativo multiplataforma para Linux e Windows 7. Todos os meus arquivos foram escritos primeiro no Linux e codificados como utf-8 , mas quando abro esse mesmo projeto no Windows, o arquivo kv é lido usando a codificação cp1252 . A mesma coisa parece não acontecer com meus arquivos .py talvez porque estou usando o python3.

Como consequência, os caracteres Unicode escritos no arquivo kv não serão renderizados corretamente no aplicativo Kivy. A string 'Título' será exibida como TÃ-tulo .

Minhas configurações são: Kivy = 1.9.1, Python = 3.4.4, Windows 7 x64 Home Premium.

Além disso, meu python foi instalado usando o Anaconda, mas provavelmente não está relacionado.

Para reproduzir o problema:

Escreva um arquivo kv codificado com utf-8 :

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

No interpretador python ou script .py :

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

A solução alternativa multiplataforma que encontrei foi esta:

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

Comentários muito úteis

Sim, @ChristianTremblay , é apenas um bug do Windows. Na verdade, isso ocorre porque a codificação padrão do Windows é cp1252, fazendo com que o Kivy leia o arquivo .kv como se estivesse codificado dessa forma. Talvez a solução proposta por @KeyWeeUsr realmente ajude, eu não tentei isso, mas pode ser mais limpa do que a outra solução alternativa proposta.

Eu concordo, uma boa solução seria permitir a especificação de codificação no arquivo .kv da mesma forma que podemos fazer em python:

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

Todos 24 comentários

Para sua informação - uma maneira um pouco mais fácil de contornar isso é usar literais Unicode:

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

Obrigado, vou usar isso =)

Para alguém que está usando esta solução alternativa, se você deseja encontrar a sequência de escape Unicode para seu caractere Unicode, você pode encontrá-la assim:

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

Você não acha que deveria haver uma maneira melhor? (ouvindo Hettinger falando ...)

um cabeçalho # que diria como o caractere Unicode deve ser tratado?

Mesmo que esse truque funcione ... torna o texto realmente difícil de ler quando há muitos caracteres Unicode ...

Este é apenas um bug do Windows?

Bem, esta não é uma maneira recomendada de como lidar com codificações, mas você pode usar isso. Funcionou para mim em py2.7 com kivy 1.8.0, mas poderia funcionar até mesmo com py3. Arquivos salvos como utf-8 , \u... símbolos usados ​​diretamente como u'ä'

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

Sim, @ChristianTremblay , é apenas um bug do Windows. Na verdade, isso ocorre porque a codificação padrão do Windows é cp1252, fazendo com que o Kivy leia o arquivo .kv como se estivesse codificado dessa forma. Talvez a solução proposta por @KeyWeeUsr realmente ajude, eu não tentei isso, mas pode ser mais limpa do que a outra solução alternativa proposta.

Eu concordo, uma boa solução seria permitir a especificação de codificação no arquivo .kv da mesma forma que podemos fazer em python:

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

E se utf-8 fosse obrigatório para arquivos 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)

Isso é encontrado em kivy / lang / builder.py linha 275 e superior

@ChristianTremblay , acho que não seria o melhor. Alguns usuários ainda podem usar editores de texto com codificações padrão diferentes de 'utf-8', por exemplo, a codificação padrão do Windows 'cp1252'. Devemos fornecer uma solução para ambos.

O melhor provavelmente seria imitar o comportamento do python:

  • Espere que o programador especifique a codificação na primeira linha.
  • Ou então use a codificação padrão do python (em python3 seria sempre 'utf8', eu acho).

Tendo um problema no 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)) Mas parece funcionar na minha máquina Linux.

O padrão definitivamente deve ser utf-8, embora não forçado como obrigatório.

mixmastamyk eu tive exatamente o mesmo problema.
Meu aplicativo funciona bem, mas quando crio o APK e o executo em meu telefone Android, obtenho:
UnicodeDecodeError: o codec 'ascii' não pode decodificar o byte 0xc3 na posição 352: ordinal fora do intervalo (128)
Isso ocorre porque tenho alguns "É" em meu arquivo. Pena que eu estava programando em python3 para evitar esse tipo de coisa irritante.

Direito. Parece que Builder.load_file() deve usar como padrão utf8 e / ou ter um parâmetro de codificação. Nesse ínterim, eu fiz isso:

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

Certifique-se de desabilitar o carregamento automático do arquivo kv, ou o erro ainda será gerado e fará com que pareça que isso não funcionou. O formulário '\ u2026' também pode funcionar se for apenas um ou dois caracteres.

Idéia inteligente. Obrigado!
Eu vou tentar isso.

Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Obrigado por suas contribuições.

Que conveniente, ignore os bugs e deixe-os se fecharem.

Na verdade, estamos desenterrando problemas antigos para fazer a triagem, nenhum problema válido e acionável será encerrado. Porém, esse tipo de atitude não ajuda na motivação necessária para dedicar nossas tardes ao projeto.

Não se irritou com a falta de trabalho, mas sim com um bot que fecha problemas ignorados. Este pode possivelmente levar uma ou duas linhas de código para adicionar um parâmetro de codificação para load_file. Eu mesmo teria feito isso, mas há 70 solicitações de pull pendentes.

Um projeto com escassa mão de obra não deveria ter esse tipo de bot.

Ainda assim, encorajo você a fazer essa solicitação de pull. Se for uma solução simples e fácil, há uma boa chance de ser mesclado.

Eu tenho o mesmo problema com o kivy 1.10, meu aplicativo funciona perfeitamente no linux com python3 (python3 main.py), mas quando eu depuro o deploy no meu telefone Android, o aplicativo falha: / muito irritante se você quiser fazer algo com qualidade

Ainda tendo esse problema com kivy 1.10.1 e python 3.6.6 no Windows 10. A solução alternativa atual é não carregar o arquivo .kv automaticamente. Renomeie-o para algo que não carregue por padrão, salve-o com a codificação utf8 e faça como mostrado em # 5154

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

A solução

kivy 1.10.1 python 3.5.3 windows 7
mesmo comportamento no Windows 10 e Python 3.6.5

O mesmo código funciona perfeitamente no osx e linux

EDITAR: o problema está na diretiva de linguagem #:include kv
A solução
Solução 1: coloque todo o seu código kv em um único arquivo
Solução 2:

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

Pois é, tive o mesmo erro com palavras como "Número" ou "veículo". Tentei com o seguinte código:

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

Mas eu tive um problema ao fazer isso. Quando executei o aplicativo, pude ver dois rótulos diferentes sobrepostos.
A solução foi salvar o arquivo kv em um subdiretório e, em seguida, chamar o with open assim:

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

O problema foi resolvido porque o carregamento automático não encontrará o arquivo kv no mesmo diretório que main.py. Portanto, não duplicará a visualização.

@piontk Ei, pensei que seria minha salvação, mas quando tento, diz que 'codificação' não é um parâmetro válido para 'abrir'. Porque? (Além disso, desculpe se esta é uma pergunta idiota, é meu primeiro aplicativo)

Ok, eu sei que isso não é ideal, mas se nenhuma dessas opções estiver funcionando para você, você pode definir a string desejada como uma variável na classe do aplicativo principal em seu arquivo .py, que tem codificação utf-8, e então acessá-la em seu arquivo .kv.
#.py
class MainApp(App):
struser = ('Nome de usuário')

#.kv
Label:
text: app.struser

trabalhou para mim

Esta página foi útil?
0 / 5 - 0 avaliações