kivy: Encoding problem on 'utf-8' kv file on Windows

I’m developing a multi-platform app for Linux and Windows 7. All my files were first written on Linux and encoded as utf-8, but when I open this same project on Windows the kv file is read using the cp1252 encoding. The same thing does not seems to happen to my .py files maybe because I’m using python3.

As a consequence the Unicode characters written on the kv file won’t render correctly on the Kivy app. The string 'Título' will show as TÃ-tulo.

My settings are: Kivy=1.9.1, Python=3.4.4, Windows 7 x64 Home Premium.

Also my python was installed using Anaconda, but this is probably unrelated.

To reproduce the problem:

Write a kv file encoded with utf-8:

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

On python interpreter or .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

The multi-platform workaround I found was this:

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

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 27 (5 by maintainers)

Most upvoted comments

Yes @ChristianTremblay, this is only a Windows bug. This is actually because windows default encoding is cp1252, causing Kivy to read the .kv file as if encoded that way. Maybe the solution proposed by @KeyWeeUsr really helps, I haven’t tried that, but might be cleaner than the other workaround proposed.

I agree, a good solution would be to to allow encode specification on the .kv file like the way we can do in python:

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

Ok, I know this is not ideal but if none of these options are working for you, you can set your desired string to a variable in the main app class in your .py file, which has utf-8 encoding, and then access it in your .kv file. #.py class MainApp(App): struser = ('Nome de usuário')

#.kv Label: text: app.struser

worked for me

@carasuca solution is not working to me

kivy 1.10.1 python 3.5.3 windows 7 same behaviour on windows 10 and python 3.6.5

Same code works perfectly on osx and linux

EDIT: the problem is in #:include kv language directive @carasuca solution works if and only if you have a single kv file and you load it using Builder.load_string(f.read()). If that kv uses #:include anotherfile.kv, that file gets loaded with the wrong charset. Solution 1: put all you kv code into a single file Solution 2:

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

Right. Looks like Builder.load_file() should default to utf8 and/or have an encoding parameter. In the meantime I did this:

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

Make sure to disable the auto load for the kv file, or the error will still be thrown and make it look like this didn’t work. ‘\u2026’ form can also work if it is only a character or two.

Don’t you think there should be a better way ? (earing Hettinger speaking…)

a # header that would tell how the unicode character should be handled ?

Even if this trick works… it makes text really hard to read when there’s a lot of unicode characters…

Is this only a windows bug ?

For someone else using this work around, if you want to find the Unicode escape sequence for your Unicode character you may find it like this:

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

I’d still encourage you to make that pull request. If it’s a clean and easy fix, it has a good chance of being merged.

What if utf-8 was mandatory for kv files ?

    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)

kived bro I tried but its showing this a blank symbol but im trying to use the wrong symbol that is in calculator to clear a element when clicked bro can you please tell me another method :

Still having this issue with kivy 1.10.1 and python 3.6.6 on Windows 10. Current workaround is not to auto load .kv file. Rename it to something that doesn’t load by default, save it with utf8 encoding and do as shown in #5154

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