diff options
authorCalum Lind <>2019-11-09 10:42:33 +0000
committerCalum Lind <>2019-11-12 15:21:56 +0000
commit23b3f144fce3424ae874d54a659cb7b8dd624ade (patch)
parent89d62eb509d498becd83d8854d56e5d6581a7cbf (diff)
[#3298|Core] Fix pickle loading non-ascii state error
When trying to load a torrents.state from version 1.3 users were encountering the following error: UnicodeDecodeError: 'ascii' codec can't decode byte This was due to the way that Python 2 was pickling state with torrent filenames that contained non-ascii characters and Python 3 was unpickling the state using ascii encoding and failing. The fix is to specify utf-8 encoding when loading torrents.state.
3 files changed, 102 insertions, 3 deletions
diff --git a/deluge/core/ b/deluge/core/
index 752f93da0..b94868776 100644
--- a/deluge/core/
+++ b/deluge/core/
@@ -25,7 +25,7 @@ from twisted.internet.task import LoopingCall
import deluge.component as component
from deluge._libtorrent import lt
-from deluge.common import archive_files, decode_bytes, get_magnet_info, is_magnet
+from deluge.common import PY2, archive_files, decode_bytes, get_magnet_info, is_magnet
from deluge.configmanager import ConfigManager, get_config_dir
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath
@@ -809,7 +809,10 @@ class TorrentManager(component.Component):
with open(filepath, 'rb') as _file:
- state = pickle.load(_file)
+ if PY2:
+ state = pickle.load(_file)
+ else:
+ state = pickle.load(_file, encoding='utf8')
except (IOError, EOFError, pickle.UnpicklingError) as ex:
message = 'Unable to load {}: {}'.format(filepath, ex)
diff --git a/deluge/tests/data/utf8_filename_torrents.state b/deluge/tests/data/utf8_filename_torrents.state
new file mode 100644
index 000000000..0e9c33dae
--- /dev/null
+++ b/deluge/tests/data/utf8_filename_torrents.state
@@ -0,0 +1,85 @@
diff --git a/deluge/tests/ b/deluge/tests/
index bf84f451b..74d37bdeb 100644
--- a/deluge/tests/
+++ b/deluge/tests/
@@ -7,6 +7,8 @@
from __future__ import unicode_literals
+import os
+import shutil
import warnings
from base64 import b64encode
@@ -28,7 +30,7 @@ warnings.resetwarnings()
class TorrentmanagerTestCase(BaseTestCase):
def set_up(self):
- common.set_tmp_config_dir()
+ self.config_dir = common.set_tmp_config_dir()
self.rpcserver = RPCServer(listen=False)
self.core = Core()
self.core.config.config['lsd'] = False
@@ -118,3 +120,12 @@ class TorrentmanagerTestCase(BaseTestCase):
InvalidTorrentError,, 'torrentidthatdoesntexist'
+ def test_open_state_from_python2(self):
+ """Open a Python2 state with a UTF-8 encoded torrent filename."""
+ shutil.copy(
+ common.get_test_data_file('utf8_filename_torrents.state'),
+ os.path.join(self.config_dir, 'state', 'torrents.state'),
+ )
+ state =
+ self.assertEqual(len(state.torrents), 1)