Repository: qtile/qtile

Issue:
lazy.restart() fails when a group has a non-ASCII name
# Issue description

After adding middle-dots in my group names, lazy.restart() fails. It does the same with a set of non-ASCII characters I tested: "àç".

# Qtile version

0.16.2.dev21+ge71fae80

Using qtile-git from the AUR.

# Stack traces

Here is the error that seems relevant to the issue

```
2020-08-29 02:09:05,707 ERROR libqtile manager.py:process_key_event():L374 KB command error restart: Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/libqtile/command_interface.py", line 312, in call
    return SUCCESS, cmd(*args, **kwargs)
  File "/usr/lib/python3.8/site-packages/libqtile/core/manager.py", line 1147, in cmd_restart
    self.restart()
  File "/usr/lib/python3.8/site-packages/libqtile/core/manager.py", line 290, in restart
    argv.append('--with-state=' + buf.getvalue().decode())
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 163: invalid continuation byte
```

And the entire log : [qtile.log](https://github.com/qtile/qtile/files/5144542/qtile.log)

# Configuration

A 1-line config is sufficient to produce the issue on my laptop

```python
from libqtile.config import Group

groups = [Group(i) for i in "azà"]
```


Discussion:

Resolving patch:
diff --git a/libqtile/core/manager.py b/libqtile/core/manager.py
--- a/libqtile/core/manager.py
+++ b/libqtile/core/manager.py
@@ -26,6 +26,7 @@
 import shlex
 import signal
 import sys
+import tempfile
 import time
 import traceback
 import warnings
@@ -189,11 +190,14 @@ def noop(qtile):
         hook.fire("startup")
 
         if state:
-            st = pickle.load(io.BytesIO(state.encode()))
             try:
+                with open(state, 'rb') as f:
+                    st = pickle.load(f)
                 st.apply(self)
             except:  # noqa: E722
                 logger.exception("failed restoring state")
+            finally:
+                os.remove(state)
 
         self.core.scan()
         if state:
@@ -281,13 +285,14 @@ def restart(self):
         argv = [sys.executable] + sys.argv
         if '--no-spawn' not in argv:
             argv.append('--no-spawn')
-        buf = io.BytesIO()
+        state_file = os.path.join(tempfile.gettempdir(), "qtile-state")
         try:
-            pickle.dump(QtileState(self), buf, protocol=0)
+            with open(state_file, 'wb') as f:
+                pickle.dump(QtileState(self), f, protocol=0)
         except:  # noqa: E722
             logger.error("Unable to pickle qtile state")
         argv = [s for s in argv if not s.startswith('--with-state')]
-        argv.append('--with-state=' + buf.getvalue().decode())
+        argv.append('--with-state=' + state_file)
         self._restart = (sys.executable, argv)
         self.stop()
 
@@ -1557,7 +1562,7 @@ def cmd_get_state(self):
         """Get pickled state for restarting qtile"""
         buf = io.BytesIO()
         pickle.dump(QtileState(self), buf, protocol=0)
-        state = buf.getvalue().decode()
+        state = buf.getvalue().decode(errors="backslashreplace")
         logger.debug('State = ')
         logger.debug(''.join(state.split('\n')))
         return state


Test patch: