From f95a848c820764aa2ffe896175c79715914ef984 Mon Sep 17 00:00:00 2001 From: Antonio Larrosa Date: Wed, 1 Aug 2018 19:36:56 +0200 Subject: [PATCH] PICARD-1207: Fix handling paths with unicode characters on python3 When moving additional files, the call to encode_filename encodes the path to the original filename converting the variable from str to bytes, provoking the next exception when calling shutil, which only accepts strings (the documentation don't specifically mention that for shutil.move, but it does for copy, copyfile, copymode, etc.) Traceback (most recent call last): File "./picard/util/thread.py", line 47, in run result = self.func() File "./picard/file.py", line 222, in _save_and_rename self._move_additional_files(old_filename, new_filename) File "./picard/file.py", line 435, in _move_additional_files shutil.move(old_file, new_file) File "/usr/x86_64-pc-linux-gnu/lib/python3.6/shutil.py", line 551, in move if _destinsrc(src, dst): File "/usr/x86_64-pc-linux-gnu/lib/python3.6/shutil.py", line 565, in _destinsrc if not src.endswith(os.path.sep): TypeError: endswith first arg must be bytes or a tuple of bytes, not str Also, other functions like os.path.dirname, os.path.isdir, os.stat, os.utime ... allow to be passed a string, instead of the encoded path in a bytes variable. So I removed the use of encode_filename for all cases that either require or allow a string to be passed so we don't do unnecessary processing neither. I checked this fixes PICARD-1207. --- picard/file.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/picard/file.py b/picard/file.py index a59d13434..410c630d3 100644 --- a/picard/file.py +++ b/picard/file.py @@ -206,12 +206,11 @@ class File(QtCore.QObject, Item): return None new_filename = old_filename if not config.setting["dont_write_tags"]: - encoded_old_filename = encode_filename(old_filename) - info = os.stat(encoded_old_filename) + info = os.stat(old_filename) self._save(old_filename, metadata) if config.setting["preserve_timestamps"]: try: - os.utime(encoded_old_filename, (info.st_atime, info.st_mtime)) + os.utime(old_filename, (info.st_atime, info.st_mtime)) except OSError: log.warning("Couldn't preserve timestamp for %r", old_filename) # Rename files @@ -222,7 +221,7 @@ class File(QtCore.QObject, Item): self._move_additional_files(old_filename, new_filename) # Delete empty directories if config.setting["delete_empty_dirs"]: - dirname = encode_filename(os.path.dirname(old_filename)) + dirname = os.path.dirname(old_filename) try: self._rmdir(dirname) head, tail = os.path.split(dirname) @@ -380,17 +379,17 @@ class File(QtCore.QObject, Item): return old_filename new_dirname = os.path.dirname(new_filename) - if not os.path.isdir(encode_filename(new_dirname)): + if not os.path.isdir(new_dirname): os.makedirs(new_dirname) tmp_filename = new_filename i = 1 while (not pathcmp(old_filename, new_filename + ext) and - os.path.exists(encode_filename(new_filename + ext))): + os.path.exists(new_filename + ext)): new_filename = "%s (%d)" % (tmp_filename, i) i += 1 new_filename = new_filename + ext log.debug("Moving file %r => %r", old_filename, new_filename) - shutil.move(encode_filename(old_filename), encode_filename(new_filename)) + shutil.move(old_filename, new_filename) return new_filename def _save_images(self, dirname, metadata): @@ -408,18 +407,18 @@ class File(QtCore.QObject, Item): def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" - old_path = encode_filename(os.path.dirname(old_filename)) - new_path = encode_filename(os.path.dirname(new_filename)) - patterns = encode_filename(config.setting["move_additional_files_pattern"]) + old_path = os.path.dirname(old_filename) + new_path = os.path.dirname(new_filename) + patterns = config.setting["move_additional_files_pattern"] patterns = [string_(p.strip()) for p in patterns.split() if p.strip()] try: - names = list(map(encode_filename, os.listdir(old_path))) + names = os.listdir(old_path) except os.error: log.error("Error: {} directory not found".naming_format(old_path)) return filtered_names = [name for name in names if name[0] != "."] for pattern in patterns: - pattern_regex = re.compile(encode_filename(fnmatch.translate(pattern)), re.IGNORECASE) + pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names