Repository: spyder-ide/spyder

Issue:
UnicodeEncodeError in save_autosave_mapping
_Originally posted by @dn7 in https://github.com/spyder-ide/spyder/issues/11375#issuecomment-589196109_

Hi, I believe I have found the cause of the corrupt autosave files in my case. I had saved the scripts in a path that contained non-English characters. I get the error both with Arabic and with Hebrew characters separately. When the path does not contain such characters, the autosave folder does contain the temporary file and a pidNNN.txt file _with content_. Also, when the autosave happens in these situations, I get error messages in the software, as follows. I don't know if this is why @hmaarrfk got corrupt autosave files, too. By the way, the path did not contain spaces.
Since often a path, and even the base Windows username, contains foreign letters, I humbly suggest that it could be worth fixing, allowing the autosave to work in this situation (but even if you don't, to the very least, please inform the user when saving, like Matlab does with names that contain spaces). Are there other functions that do not work if the file path contains a foreign alphabet?
Thank you!
```  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 300, in get_autosave_filename
    autosave_filename = self.name_mapping[filename]
KeyError: 'C:\\Users\\USER1\\Documents\\USER1\\العربية\\hello_world.py'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 116, in do_autosave
    stack.autosave.autosave_all()
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 375, in autosave_all
    self.maybe_autosave(index)
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 347, in maybe_autosave
    self.autosave(finfo)
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 360, in autosave
    autosave_filename = self.get_autosave_filename(finfo.filename)
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 313, in get_autosave_filename
    self.save_autosave_mapping()
  File "C:\Users\USER1\Anaconda3\lib\site-packages\spyder\plugins\editor\utils\autosave.py", line 258, in save_autosave_mapping
    pidfile.write(pprint.pformat(self.name_mapping))
  File "C:\Users\USER1\Anaconda3\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 38-44: character maps to <undefined>```



Discussion:

Resolving patch:
diff --git a/spyder/plugins/editor/utils/autosave.py b/spyder/plugins/editor/utils/autosave.py
--- a/spyder/plugins/editor/utils/autosave.py
+++ b/spyder/plugins/editor/utils/autosave.py
@@ -11,7 +11,6 @@
 import logging
 import os
 import os.path as osp
-import pprint
 import re
 
 # Third party imports
@@ -21,6 +20,7 @@
 from spyder.config.base import _, get_conf_path, running_under_pytest
 from spyder.plugins.editor.widgets.autosaveerror import AutosaveErrorDialog
 from spyder.plugins.editor.widgets.recover import RecoveryDialog
+from spyder.py3compat import PY2
 from spyder.utils.programs import is_spyder_process
 
 
@@ -262,7 +262,10 @@ def save_autosave_mapping(self):
         pidfile_name = osp.join(autosave_dir, 'pid{}.txt'.format(my_pid))
         if self.name_mapping:
             with open(pidfile_name, 'w') as pidfile:
-                pidfile.write(pprint.pformat(self.name_mapping))
+                if PY2:
+                    pidfile.write(repr(self.name_mapping))
+                else:
+                    pidfile.write(ascii(self.name_mapping))
         else:
             try:
                 os.remove(pidfile_name)


Test patch:
diff --git a/spyder/plugins/editor/utils/tests/test_autosave.py b/spyder/plugins/editor/utils/tests/test_autosave.py
--- a/spyder/plugins/editor/utils/tests/test_autosave.py
+++ b/spyder/plugins/editor/utils/tests/test_autosave.py
@@ -167,14 +167,18 @@ def test_autosave(mocker):
     assert addon.file_hashes == {'orig': 1, 'autosave': 3}
 
 
-def test_save_autosave_mapping_with_nonempty_mapping(mocker, tmpdir):
+@pytest.mark.parametrize('latin', [True, False])
+def test_save_autosave_mapping_with_nonempty_mapping(mocker, tmpdir, latin):
     """Test that save_autosave_mapping() writes the current autosave mapping
     to the correct file if the mapping is not empty."""
     mocker.patch('os.getpid', return_value=42)
     mocker.patch('spyder.plugins.editor.utils.autosave.get_conf_path',
                  return_value=str(tmpdir))
     addon = AutosaveForStack(None)
-    addon.name_mapping = {'orig': 'autosave'}
+    if latin:
+        addon.name_mapping = {'orig': 'autosave'}
+    else:
+        addon.name_mapping = {'原件': 'autosave'}
 
     addon.save_autosave_mapping()