Repository: kivy/kivy

Issue:
Logger does not create log files when username contains non-ascii characters
This happens on Windows.

You need to create a user with a non-ascii name:

Control panel->Change keyboards->Add keyboard
Polish (programmers)

Change your locale (without this, nothing will work)
"Administrative" tab -> Change system locale -> Polish

Add user Łukasz (right Alt+L to get the Ł with polish keyboard selected)

Log in as Łukasz, install python, kivy (if you don't have polish locale, this will fail). Alternatively, you could package a python file with pyinstaller --onefile and then pass it to the non-ascii user. This will work the same but you won't be able to debug so easily.
Run python and do "import kivy".

You will get:

```
>>> import kivy
[ERROR             ] Error while activating FileHandler logger
Traceback (most recent call last):
  File "C:\Python27_Lukasz\lib\site-packages\kivy\logger.py", line 205, in emit
    self._configure()
  File "C:\Python27_Lukasz\lib\site-packages\kivy\logger.py", line 153, in _configure
    _dir = os.path.join(_dir, log_dir)
  File "C:\Python27_Lukasz\lib\ntpath.py", line 85, in join
    result_path = result_path + p_path
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa3 in position 7: ordinal not in range(128)
[INFO              ] [Kivy        ] v1.9.1
[INFO              ] [Python      ] v2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)]
>>>
```

Kivy works fine but the logger won't create any file and no logs will be saved to disk.
Decoding user_home_dir to an unicode string fixes the problem:

C:\Python27_Lukasz\Lib\site-packages\kivy>git diff

```
diff --git a/__init__.py b/__init__.py
index 0f9e128..af2b970 100644
--- a/__init__.py
+++ b/__init__.py
@@ -278,7 +278,7 @@ if not environ.get('KIVY_DOC_INCLUDE'):
     if 'KIVY_HOME' in environ:
         kivy_home_dir = expanduser(environ['KIVY_HOME'])
     else:
-        user_home_dir = expanduser('~')
+        user_home_dir = expanduser('~').decode(sys.getfilesystemencoding())
         if platform == 'android':
             user_home_dir = environ['ANDROID_APP_PATH']
         elif platform == 'ios':
```

My guess is the same thing should be done with the kivy_home_dir variable as it is also join()ed in the same way.



Discussion:
The problem is that the Config module seems to return strings in unicode, even on py2, while `kivy.kivy_home_dir` is a str object, i.e. bytes in py2. So they cannot be joined with `join` because they will have to decoded/encoded which doesn't work by default, hence this bug.

The question is, why does config return unicode strings? And I think the proper solution is not to decode the home dir pre-emptively to bytes in all cases, but to convert the config returned values to bytes on py2 (i.e. encode here: https://github.com/kivy/kivy/blob/master/kivy/logger.py#L146). Because we cannot encode the home directory and change it's type on py3.

You're right. That patch was from when I was just poking the code with a stick here and there, hoping to finally make it work :). And when I did, I stuck to the solution that worked for me.

I've quickly tested what you wrote and it seems that this does the job. The only nuisance is that the path to the log file that is shown in the console is garbled but the string that is dumped to the log file (which also contains the same path) is alright.
This was probably the reason I thought that encoding the string in logger.py:146 was not a solution, back then.

@matham I would like to get back to this topic, because it seems to be abandoned and I've spent some some more time battling unicode issues in my python 2 code.
Meanwhile, I'm still using the patch I've pasted above.

I believe the correct solution (as well as a good practice, in general) is to convert everything you can to unicode as soon as possible. Having the Config module return unicode strings is a good thing in this context.
If you do this, you can always assume your strings are in unicode and you can encode them to the required encoding when needed. Otherwise, you end up with variables that have an undefined encoding (figuratively speaking) and you never know if you should try to decode them and how.

I'm not sure I understand your last sentence. Did you mean `decode` instead of `encode`? Either way, I still think it should be fixed by adding a `if PY2:` clause and decoding the `expanduser(...)` string on python 2, while keeping it as is on python 3.
The `environ[]` dict (a few lines above) should be decoded as well in the same manner because its contents will also be encoded using the same encoding IIRC.

Is there some other way I could help in getting this issue fixed?


Resolving patch:
diff --git a/kivy/__init__.py b/kivy/__init__.py
--- a/kivy/__init__.py
+++ b/kivy/__init__.py
@@ -36,6 +36,7 @@
 from os import environ, mkdir
 from os.path import dirname, join, basename, exists, expanduser
 import pkgutil
+from kivy.compat import PY2
 from kivy.logger import Logger, LOG_LEVELS
 from kivy.utils import platform
 
@@ -284,6 +285,10 @@ def kivy_usage():
         elif platform == 'ios':
             user_home_dir = join(expanduser('~'), 'Documents')
         kivy_home_dir = join(user_home_dir, '.kivy')
+
+    if PY2:
+        kivy_home_dir = kivy_home_dir.decode(sys.getfilesystemencoding())
+
     kivy_config_fn = join(kivy_home_dir, 'config.ini')
     kivy_usermodules_dir = join(kivy_home_dir, 'mods')
     kivy_userexts_dir = join(kivy_home_dir, 'extensions')


Test patch: