Kivy: Problème d'encodage sur le fichier kv 'utf-8' sous Windows

Créé le 16 févr. 2016  ·  24Commentaires  ·  Source: kivy/kivy

Je développe une application multiplateforme pour Linux et Windows 7. Tous mes fichiers ont d'abord été écrits sous Linux et encodés en tant que utf-8 , mais lorsque j'ouvre ce même projet sous Windows, le fichier kv est lu en utilisant l'encodage cp1252 . La même chose ne semble pas arriver à mes fichiers .py peut-être parce que j'utilise python3.

En conséquence, les caractères Unicode écrits sur le fichier kv ne seront pas rendus correctement sur l'application Kivy. La chaîne 'Título' s'affichera sous la forme TÃ-tulo .

Mes paramètres sont : Kivy=1.9.1, Python=3.4.4, Windows 7 x64 Home Premium.

De plus, mon python a été installé à l'aide d'Anaconda, mais cela n'a probablement aucun rapport.

Pour reproduire le problème :

Ecrire un fichier kv encodé avec utf-8 :

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

Sur l'interpréteur python ou le 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 solution de contournement multiplateforme que j'ai trouvée était la suivante :

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

Commentaire le plus utile

Oui @ChristianTremblay , ce n'est qu'un bug de Windows. C'est en fait parce que l'encodage par défaut de Windows est cp1252, obligeant Kivy à lire le fichier .kv comme s'il était encodé de cette façon. Peut-être que la solution proposée par @KeyWeeUsr aide vraiment, je n'ai pas essayé cela, mais pourrait être plus propre que l'autre solution de contournement proposée.

Je suis d'accord, une bonne solution serait d'autoriser la spécification d'encodage sur le fichier .kv comme on peut le faire en python :

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

Tous les 24 commentaires

Pour info, un moyen un peu plus simple de contourner ce problème consiste à utiliser des littéraux Unicode :

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

Merci, je vais l'utiliser =)

Pour quelqu'un d'autre utilisant cette solution de contournement, si vous souhaitez trouver la séquence d'échappement Unicode pour votre caractère Unicode, vous pouvez la trouver comme ceci :

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

Ne pensez-vous pas qu'il devrait y avoir un meilleur moyen ? (en écoutant Hettinger parler...)

un en-tête # qui indiquerait comment le caractère unicode doit être géré ?

Même si cette astuce fonctionne... elle rend le texte très difficile à lire lorsqu'il y a beaucoup de caractères Unicode...

Est-ce seulement un bug de Windows ?

Eh bien, ce n'est pas une méthode recommandée pour gérer les encodages, mais vous pouvez l'utiliser. Cela a fonctionné pour moi dans py2.7 avec kivy 1.8.0, mais cela pourrait fonctionner même avec py3. Fichiers enregistrés en tant que utf-8 , symboles \u... utilisés directement en tant que u'ä'

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

Oui @ChristianTremblay , ce n'est qu'un bug de Windows. C'est en fait parce que l'encodage par défaut de Windows est cp1252, obligeant Kivy à lire le fichier .kv comme s'il était encodé de cette façon. Peut-être que la solution proposée par @KeyWeeUsr aide vraiment, je n'ai pas essayé cela, mais pourrait être plus propre que l'autre solution de contournement proposée.

Je suis d'accord, une bonne solution serait d'autoriser la spécification d'encodage sur le fichier .kv comme on peut le faire en python :

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

Et si utf-8 était obligatoire pour les fichiers 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)

Ceci se trouve dans kivy/lang/builder.py ligne 275 et plus

@ChristianTremblay , je pense que ce ne serait pas pour le mieux. Certains utilisateurs peuvent toujours utiliser des éditeurs de texte avec des encodages par défaut différents de « utf-8 », par exemple le codage Windows par défaut « cp1252 ». Nous devons fournir une solution pour les deux.

Le mieux serait probablement d'imiter le comportement de python :

  • Attendez-vous à ce que le programmeur spécifie l'encodage sur la première ligne.
  • Ou bien utilisez l'encodage par défaut de python (sur python3, ce serait toujours 'utf8' je pense).

Vous rencontrez un problème sur 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)) Semble fonctionner sur ma machine Linux cependant.

La valeur par défaut devrait certainement être utf-8, mais pas forcée comme obligatoire.

mixmastamyk j'ai eu exactement le même problème.
Mon application fonctionne bien, mais lorsque je crée l'APK et que je l'exécute sur mon téléphone Android, j'obtiens :
UnicodeDecodeError : le codec 'ascii' ne peut pas décoder l'octet 0xc3 en position 352 : l'ordinal n'est pas dans la plage (128)
C'est parce que j'ai quelques "É" dans mon fichier. Dommage que je code en python3 pour éviter ce genre de choses ennuyeuses.

Droit. On dirait que Builder.load_file() devrait par défaut être utf8 et/ou avoir un paramètre d'encodage. En attendant j'ai fait ça :

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

Assurez-vous de désactiver le chargement automatique du fichier kv, sinon l'erreur sera toujours renvoyée et donnera l'impression que cela n'a pas fonctionné. Le formulaire '\u2026' peut également fonctionner s'il ne s'agit que d'un ou deux caractères.

Idée intelligente.merci !
Je vais essayer ça.

Ce problème a été automatiquement marqué comme obsolète car il n'a pas eu d'activité récente. Il sera fermé si aucune autre activité ne se produit. Merci pour vos contributions.

Comme c'est pratique, ignorez les bugs et laissez-les se fermer.

En fait, nous avons déterré d'anciens problèmes pour les trier, aucun problème valide et exploitable ne sera fermé. Bien que ce genre d'attitude n'aide pas à la motivation nécessaire pour consacrer nos après-midi au projet.

N'était pas irrité par le manque de travail mais plutôt par un bot qui ferme les problèmes ignorés. Celui-ci peut éventuellement prendre une ou deux lignes de code pour ajouter un paramètre d'encodage à load_file. Je l'aurais fait moi-même, mais il y a 70 demandes de tirage en attente.

Un projet avec peu de main-d'œuvre ne devrait pas avoir ce type de bot.

Je vous encourage quand même à faire cette pull request. S'il s'agit d'une solution claire et facile, elle a de bonnes chances d'être fusionnée.

J'ai le même problème avec kivy 1.10, mon application fonctionne parfaitement sur Linux avec python3 ( python3 main.py) mais lorsque je débogue le déploiement sur mon téléphone Android, l'application plante :/ très ennuyeux si vous voulez faire quelque chose avec de la qualité

Vous avez toujours ce problème avec kivy 1.10.1 et python 3.6.6 sous Windows 10. La solution de contournement actuelle consiste à ne pas charger automatiquement le fichier .kv. Renommez-le en quelque chose qui ne se charge pas par défaut, enregistrez-le avec l'encodage utf8 et procédez comme indiqué dans #5154

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

La solution

kivy 1.10.1 python 3.5.3 windows 7
même comportement sur windows 10 et python 3.6.5

Le même code fonctionne parfaitement sur osx et linux

EDIT : le problème est dans la directive de langue #:include kv
La solution
Solution 1 : mettez tout votre code kv dans un seul fichier
Solution 2 :

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

Eh bien, j'ai eu la même erreur avec des mots comme "Número" ou "veículo". J'ai essayé avec le code suivant :

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

Mais j'ai eu un problème pour faire ça. Lorsque j'ai exécuté l'application, j'ai pu voir deux étiquettes différentes se chevaucher.
La solution consistait à enregistrer le fichier kv dans un sous-répertoire, puis à appeler le avec open comme ceci :

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

Le problème a été résolu car le chargement automatique ne trouvera pas le fichier kv dans le même répertoire que main.py. Cela ne dupliquera donc pas la visualisation.

@piontk Hé, je pensais que ce serait mon salut, mais quand je l'essaie, il dit que "l'encodage" n'est pas un paramètre valide pour "ouvrir". Pourquoi? (De plus, désolé si c'est une question stupide, c'est ma toute première application)

D'accord, je sais que ce n'est pas idéal, mais si aucune de ces options ne fonctionne pour vous, vous pouvez définir la chaîne souhaitée sur une variable dans la classe principale de l'application dans votre fichier .py, qui a un codage utf-8, puis y accéder dans votre fichier .kv.
#.py
class MainApp(App):
struser = ('Nome de usuário')

#.kv
Label:
text: app.struser

travaillé pour moi

Cette page vous a été utile?
0 / 5 - 0 notes