Kivy: Problema de codificación en el archivo kv 'utf-8' en Windows

Creado en 16 feb. 2016  ·  24Comentarios  ·  Fuente: kivy/kivy

Estoy desarrollando una aplicación multiplataforma para Linux y Windows 7. Todos mis archivos se escribieron primero en Linux y se codificaron como utf-8 , pero cuando abro este mismo proyecto en Windows, el archivo kv se lee usando la codificación cp1252 . No parece que le suceda lo mismo a mis archivos .py tal vez porque estoy usando python3.

Como consecuencia, los caracteres Unicode escritos en el archivo kv no se mostrarán correctamente en la aplicación Kivy. La cadena 'Título' se mostrará como TÃ-tulo .

Mi configuración es: Kivy = 1.9.1, Python = 3.4.4, Windows 7 x64 Home Premium.

También mi Python se instaló usando Anaconda, pero probablemente esto no esté relacionado.

Para reproducir el problema:

Escriba un archivo kv codificado con utf-8 :

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

En el intérprete de Python o el 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

La solución multiplataforma que encontré fue la siguiente:

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

Comentario más útil

@ChristianTremblay , esto es solo un error de Windows. En realidad, esto se debe a que la codificación predeterminada de Windows es cp1252, lo que hace que Kivy lea el archivo .kv como si estuviera codificado de esa manera. Tal vez la solución propuesta por @KeyWeeUsr realmente ayude, no lo he probado, pero podría ser más limpia que la otra solución alternativa propuesta.

Estoy de acuerdo, una buena solución sería permitir la especificación de codificación en el archivo .kv como podemos hacer en Python:

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

Todos 24 comentarios

Para su información, una forma un poco más fácil de solucionar esto es usar literales Unicode:

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

Gracias, lo usaré =)

Para otra persona que utilice esta solución alternativa, si desea encontrar la secuencia de escape Unicode para su carácter Unicode, puede encontrarla así:

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

¿No crees que debería haber una mejor manera? (escuchando a Hettinger hablar ...)

un encabezado # que diría cómo se debe manejar el carácter Unicode?

Incluso si este truco funciona ... hace que el texto sea realmente difícil de leer cuando hay muchos caracteres Unicode ...

¿Es esto solo un error de Windows?

Bueno, esta no es una forma recomendada de cómo manejar codificaciones, pero puede usar esto. Me funcionó en py2.7 con kivy 1.8.0, pero podría funcionar incluso con py3. Archivos guardados como utf-8 , \u... símbolos usados ​​directamente como u'ä'

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

@ChristianTremblay , esto es solo un error de Windows. En realidad, esto se debe a que la codificación predeterminada de Windows es cp1252, lo que hace que Kivy lea el archivo .kv como si estuviera codificado de esa manera. Tal vez la solución propuesta por @KeyWeeUsr realmente ayude, no lo he probado, pero podría ser más limpia que la otra solución alternativa propuesta.

Estoy de acuerdo, una buena solución sería permitir la especificación de codificación en el archivo .kv como podemos hacer en Python:

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

¿Y si utf-8 fuera obligatorio para los archivos 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)

Esto se encuentra en kivy / lang / builder.py línea 275 y posteriores

@ChristianTremblay , creo que esto no sería lo mejor. Algunos usuarios aún pueden usar editores de texto con codificaciones predeterminadas diferentes de 'utf-8', por ejemplo, la codificación predeterminada de Windows 'cp1252'. Debemos brindar una solución para ambos.

Lo mejor probablemente sería imitar el comportamiento de Python:

  • Espere que el programador especifique la codificación en la primera línea.
  • O bien use la codificación predeterminada de Python (en python3 siempre sería 'utf8', creo).

Tener un problema en 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)) Sin embargo, parece funcionar en mi caja de Linux.

El valor predeterminado definitivamente debería ser utf-8, aunque no forzado como obligatorio.

mixmastamyk tuve exactamente el mismo problema.
Mi aplicación funciona bien, pero cuando construyo el APK y lo ejecuto en mi teléfono Android, obtengo:
UnicodeDecodeError: el códec 'ascii' no puede decodificar el byte 0xc3 en la posición 352: ordinal no está en el rango (128)
Esto se debe a que tengo un par de "É" en mi archivo. Lástima que estaba codificando en python3 para evitar este tipo de cosas molestas.

Derecha. Parece que Builder.load_file() debería ser utf8 por defecto y / o tener un parámetro de codificación. Mientras tanto, hice esto:

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

Asegúrese de deshabilitar la carga automática para el archivo kv, o el error seguirá apareciendo y parecerá que esto no funcionó. El formulario '\ u2026' también puede funcionar si es solo uno o dos caracteres.

Idea inteligente ¡Gracias!
Intentaré esto.

Este problema se ha marcado automáticamente como obsoleto porque no ha tenido actividad reciente. Se cerrará si no se produce más actividad. Gracias por sus aportaciones.

Qué conveniente, ignorar los errores y dejar que se cierren solos.

En realidad, hemos estado investigando problemas antiguos para clasificarlos, no se cerrará ningún problema válido y procesable. Aunque este tipo de actitud no ayuda con la motivación necesaria para dedicar nuestras tardes al proyecto.

No estaba irritado por la falta de trabajo, sino más bien por un bot que cierra los problemas ignorados. Este posiblemente necesite una o dos líneas de código para agregar un parámetro de codificación a load_file. Lo habría hecho yo mismo, pero hay 70 solicitudes de extracción pendientes.

Un proyecto con escasa mano de obra no debería tener este tipo de bot.

Aún así, te animo a que hagas esa solicitud de extracción. Si se trata de una solución limpia y sencilla, es muy probable que se fusione.

Tengo el mismo problema con kivy 1.10, mi aplicación funciona perfectamente en linux con python3 (python3 main.py) pero cuando depuro la implementación en mi teléfono Android, la aplicación se bloquea: / muy molesto si quieres hacer algo con calidad

Aún tengo este problema con kivy 1.10.1 y python 3.6.6 en Windows 10. La solución actual es no cargar automáticamente el archivo .kv. Cambie el nombre a algo que no se cargue por defecto, guárdelo con codificación utf8 y haga lo que se muestra en # 5154

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

La solución de

kivy 1.10.1 python 3.5.3 windows 7
mismo comportamiento en Windows 10 y Python 3.6.5

El mismo código funciona perfectamente en osx y linux

EDITAR: el problema está en la directiva de idioma #:include kv
La solución
Solución 1: ponga todo su código kv en un solo archivo
Solución 2:

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

Bueno, tuve el mismo error con palabras como "Número" o "veículo". Intenté con el siguiente código:

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

Pero tuve un problema al hacer esto. Cuando ejecuté la aplicación, pude ver dos etiquetas diferentes superpuestas.
La solución fue guardar el archivo kv en un subdirectorio y luego llamar al with open así:

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

El problema se resolvió porque la carga automática no encuentra el archivo kv en el mismo directorio que main.py. Entonces no duplicará la visualización.

@piontk Oye, pensé que esta sería mi salvación, pero cuando lo intento, dice que 'codificación' no es un parámetro válido para 'abrir'. ¿Por qué? (Además, lo siento si esta es una pregunta tonta, es mi primera aplicación)

Ok, sé que esto no es ideal, pero si ninguna de estas opciones funciona para usted, puede configurar la cadena deseada en una variable en la clase de aplicación principal en su archivo .py, que tiene codificación utf-8, y luego acceder a ella en su archivo .kv.
#.py
class MainApp(App):
struser = ('Nome de usuário')

#.kv
Label:
text: app.struser

trabajó para mi

¿Fue útil esta página
0 / 5 - 0 calificaciones