Repository: kivy/kivy

Issue:
Settings panel is not accepting unicode characters
Hello, 

if you try to pass unicode characters (>128) tot he settings widget, using "add_json_panel", an error comes up:

```
Parser: File "C:\dev\Kivy\kivy\kivy\data\style.kv", line 543:
.
541:            id: labellayout
542:            markup: True
>>  543:            text: '{0}\n[size=13sp][color=999999]{1}[/color][/size]'.format(root.title or '', root.desc or '')
544:            font_size: '15sp'
545:            text_size: self.width - 32, None
.
'ascii' codec can't encode character u'\xe4' in position 9: ordinal not in range(128)
```

Looks like the kv file is ascii and not unicode



Discussion:
I started to look at the issue. It seems (again) more complex than usual.
Even after removing any str() manual conversion in our side, i'm hitting a bug into the Python ConfigParser object. They manually encode everything to ascii.

Right now, i'm learning how to be able to use an utf-8 config file by default (ref: http://bip.weizmann.ac.il/course/python/PyMOTW/PyMOTW/docs/ConfigParser/index.html)


Resolving patch:
diff --git a/kivy/config.py b/kivy/config.py
--- a/kivy/config.py
+++ b/kivy/config.py
@@ -17,9 +17,15 @@
 
 Change the configuration and save it::
 
-    >>> Config.set('kivy', 'retain_time', 50)
+    >>> Config.set('kivy', 'retain_time', '50')
     >>> Config.write()
 
+.. versionchanged:: 1.7.1
+
+    The ConfigParser should work correctly with utf-8 now. The values are
+    converted from ascii to unicode only when needed. The method get() returns
+    utf-8 strings.
+
 Available configuration tokens
 ------------------------------
 
@@ -240,16 +246,38 @@ def read(self, filename):
         if type(filename) not in (str, unicode):
             raise Exception('Only one filename is accepted (str or unicode)')
         self.filename = filename
+        # If we try to open directly the configuration file in utf-8,
+        # we correctly get the unicode value by default.
+        # But, when we try to save it again, all the values we didn't changed
+        # are still unicode, and then the PythonConfigParser internal do a str()
+        # conversion -> fail.
+        # Instead we currently to the conversion to utf-8 when value are
+        # "get()", but we internally store them in ascii.
+        #with codecs.open(filename, 'r', encoding='utf-8') as f:
+        #    self.readfp(f)
         PythonConfigParser.read(self, filename)
 
     def set(self, section, option, value):
         '''Functions similarly to PythonConfigParser's set method, except that
         the value is implicitly converted to a string.
         '''
-        ret = PythonConfigParser.set(self, section, option, str(value))
-        self._do_callbacks(section, option, str(value))
+        e_value = value
+        if not isinstance(value, basestring):
+            # might be boolean, int, etc.
+            e_value = str(value)
+        else:
+            if isinstance(value, unicode):
+                e_value = value.encode('utf-8')
+        ret = PythonConfigParser.set(self, section, option, e_value)
+        self._do_callbacks(section, option, value)
         return ret
 
+    def get(self, section, option):
+        value = PythonConfigParser.get(self, section, option)
+        if type(value) is str:
+            return value.decode('utf-8')
+        return value
+
     def setdefaults(self, section, keyvalues):
         '''Set a lot of keys/values in one section at the same time
         '''
diff --git a/kivy/core/window/__init__.py b/kivy/core/window/__init__.py
--- a/kivy/core/window/__init__.py
+++ b/kivy/core/window/__init__.py
@@ -427,7 +427,7 @@ def __init__(self, **kwargs):
         if 'rotation' not in kwargs:
             kwargs['rotation'] = Config.getint('graphics', 'rotation')
         if 'position' not in kwargs:
-            kwargs['position'] = Config.get('graphics', 'position', 'auto')
+            kwargs['position'] = Config.getdefault('graphics', 'position', 'auto')
         if 'top' in kwargs:
             kwargs['position'] = 'custom'
             kwargs['top'] = kwargs['top']
diff --git a/kivy/uix/settings.py b/kivy/uix/settings.py
--- a/kivy/uix/settings.py
+++ b/kivy/uix/settings.py
@@ -272,7 +272,9 @@ def on_value(self, instance, value):
             return
         # get current value in config
         panel = self.panel
-        panel.set_value(self.section, self.key, str(value))
+        if not isinstance(value, basestring):
+            value = str(value)
+        panel.set_value(self.section, self.key, value)
 
 
 class SettingBoolean(SettingItem):
@@ -344,7 +346,7 @@ def _create_popup(self, instance):
             content=content, size_hint=(None, None), size=('400dp', '250dp'))
 
         # create the textinput used for numeric input
-        self.textinput = textinput = TextInput(text=str(self.value),
+        self.textinput = textinput = TextInput(text=self.value,
             font_size=24, multiline=False, size_hint_y=None, height='50dp')
         textinput.bind(on_text_validate=self._validate)
         self.textinput = textinput
@@ -422,9 +424,8 @@ def _create_popup(self, instance):
             content=content, size_hint=(None, None), size=(400, 400))
 
         # create the filechooser
-        self.textinput = textinput = FileChooserListView(path=str(self.value),
-                                                         size_hint=(1, 1),
-                                                         dirselect=True)
+        self.textinput = textinput = FileChooserListView(
+                path=self.value, size_hint=(1, 1), dirselect=True)
         textinput.bind(on_path=self._validate)
         self.textinput = textinput
 


Test patch:
diff --git a/kivy/tests/test_issue_1084.py b/kivy/tests/test_issue_1084.py
new file mode 100644
--- /dev/null
+++ b/kivy/tests/test_issue_1084.py
@@ -0,0 +1,43 @@
+#
+# Bug fixed: 
+# - put utf-8 in string, and validate -> no more crash due to str() encoding
+# - put utf-8 in string, validate, close, open the app and edit the value -> no
+# more weird space due to ascii->utf8 encoding.
+# - create an unicode directory, and select it with Path. -> no more crash at
+# validation.
+# - create an unicode directory, and select it with Path and restart -> the path
+# is still correct.
+
+from kivy.app import App
+from kivy.uix.settings import Settings
+
+data = '''
+[
+    {
+        "type": "string",
+        "title": "String",
+        "desc": "-",
+        "section": "test",
+        "key": "string"
+    },
+    {
+        "type": "path",
+        "title": "Path",
+        "desc": "-",
+        "section": "test",
+        "key": "path"
+    }
+]
+'''
+
+class UnicodeIssueSetting(App):
+    def build_config(self, config):
+        config.add_section('test')
+        config.setdefault('test', 'string', 'Hello world')
+        config.setdefault('test', 'path', '/')
+    def build(self):
+        s = Settings()
+        s.add_json_panel('Test Panel', self.config, data=data)
+        return s
+
+UnicodeIssueSetting().run()