From a0598bdc6fb85dd3ffd38f828ac059d6d90fc129 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 25 Dec 2013 02:46:05 +0100
Subject: [PATCH 01/59] Ignore hidden files and directories based on
`show_hidden_files` option.
http://tickets.musicbrainz.org/browse/PICARD-528
---
picard/tagger.py | 7 ++++++-
picard/util/__init__.py | 6 ++++++
test/test_utils.py | 16 ++++++++++++++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index b2d2208af..ac993ffae 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -70,7 +70,8 @@ from picard.util import (
thread,
mbid_validate,
check_io_encoding,
- uniqify
+ uniqify,
+ is_hidden_path,
)
from picard.webservice import XmlWebService
@@ -329,9 +330,13 @@ class Tagger(QtGui.QApplication):
def add_files(self, filenames, target=None):
"""Add files to the tagger."""
log.debug("Adding files %r", filenames)
+ ignore_hidden = not config.persist["show_hidden_files"]
new_files = []
for filename in filenames:
filename = os.path.normpath(os.path.realpath(filename))
+ if ignore_hidden and is_hidden_path(filename):
+ log.debug("File ignored (hidden): %s" % (filename))
+ continue
if filename not in self.files:
file = open_file(filename)
if file:
diff --git a/picard/util/__init__.py b/picard/util/__init__.py
index f4797fc79..03ea2dc5a 100644
--- a/picard/util/__init__.py
+++ b/picard/util/__init__.py
@@ -365,3 +365,9 @@ if sys.platform == 'win32':
return ap1 == ap2
else:
os_path_samefile = os.path.samefile
+
+
+def is_hidden_path(path):
+ """Returns true if at least one element of the path starts with a dot"""
+ path = os.path.normpath(path) # we need to ignore /./ and /a/../ cases
+ return any(s.startswith('.') for s in path.split(os.sep))
diff --git a/test/test_utils.py b/test/test_utils.py
index 12f863fe2..13462a7a0 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+import os.path
import unittest
from picard import util
@@ -119,3 +120,18 @@ class SaveReleaseTypeScoresTest(unittest.TestCase):
self.assertTrue("Single 0.50" in saved_scores)
self.assertTrue("Other 0.00" in saved_scores)
self.assertEqual(6, len(saved_scores.split()))
+
+
+class HiddenPathTest(unittest.TestCase):
+
+ def test(self):
+ self.assertEqual(util.is_hidden_path('/a/.b/c.mp3'), True)
+ self.assertEqual(util.is_hidden_path('/a/b/c.mp3'), False)
+ self.assertEqual(util.is_hidden_path('/a/.b/.c.mp3'), True)
+ self.assertEqual(util.is_hidden_path('/a/b/.c.mp3'), True)
+ self.assertEqual(util.is_hidden_path('c.mp3'), False)
+ self.assertEqual(util.is_hidden_path('.c.mp3'), True)
+ self.assertEqual(util.is_hidden_path('/a/./c.mp3'), False)
+ self.assertEqual(util.is_hidden_path('/a/./.c.mp3'), True)
+ self.assertEqual(util.is_hidden_path('/a/../c.mp3'), False)
+ self.assertEqual(util.is_hidden_path('/a/../.c.mp3'), True)
From 8cc0a5780305bb91d5e50fc54267fb09cb07ba47 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 11:10:30 +0100
Subject: [PATCH 02/59] Add "Ignore files according to show_hidden_files" to
NEWS.txt
---
NEWS.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/NEWS.txt b/NEWS.txt
index 7bd9ba336..f7c1c77b4 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -16,6 +16,7 @@
* Main window is now emitting a "selection_updated" signal, plugin api version bumps to 1.3.0
* Append system information to user-agent string
* Compilation tag/variable aligned with iTunes, set only for Various Artists type compilations.
+ * Ignore directories and files while indexing when show_hidden_files option is set to False (PICARD-528)
Version 1.2 - 2013-03-30
* Picard now requires at least Python 2.6
From 100cc348d4af93b30c6459dedb236ab959d961a5 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 25 Dec 2013 02:47:57 +0100
Subject: [PATCH 03/59] Move STYLESHEET_ERROR to parent class as it may be used
in any page
---
picard/ui/options/__init__.py | 1 +
picard/ui/options/renaming.py | 2 --
picard/ui/options/scripting.py | 2 --
3 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/picard/ui/options/__init__.py b/picard/ui/options/__init__.py
index da17d3b4b..b8cf15731 100644
--- a/picard/ui/options/__init__.py
+++ b/picard/ui/options/__init__.py
@@ -33,6 +33,7 @@ class OptionsPage(QtGui.QWidget):
PARENT = None
SORT_ORDER = 1000
ACTIVE = True
+ STYLESHEET_ERROR = "QWidget { background-color: #f55; color: white; font-weight:bold }"
def info(self):
raise NotImplementedError
diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py
index 67ec77001..a487376b7 100644
--- a/picard/ui/options/renaming.py
+++ b/picard/ui/options/renaming.py
@@ -270,8 +270,6 @@ class RenamingOptionsPage(OptionsPage):
file.metadata['musicbrainz_releasetrackid'] = 'eac99807-93d4-3668-9714-fa0c1b487ccf'
return file
- STYLESHEET_ERROR = "QWidget { background-color: #f55; color: white; font-weight:bold }"
-
def move_files_to_browse(self):
path = QtGui.QFileDialog.getExistingDirectory(self, "", self.ui.move_files_to.text())
if path:
diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py
index 6ec9d0e89..9df9c6e66 100644
--- a/picard/ui/options/scripting.py
+++ b/picard/ui/options/scripting.py
@@ -70,8 +70,6 @@ class ScriptingOptionsPage(OptionsPage):
config.TextOption("setting", "tagger_script", ""),
]
- STYLESHEET_ERROR = "QWidget { background-color: #f55; color: white; font-weight:bold }"
-
def __init__(self, parent=None):
super(ScriptingOptionsPage, self).__init__(parent)
self.ui = Ui_ScriptingOptionsPage()
From 8102061860e04588ef6f01ba8d22891199544efe Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 25 Dec 2013 02:51:04 +0100
Subject: [PATCH 04/59] Add ignore_regex option to Advanced options
Filepaths matching this regex will be ignored.
---
picard/tagger.py | 7 ++++
picard/ui/options/advanced.py | 41 ++++++++++++++++++++-
picard/ui/ui_options_advanced.py | 48 ++++++++++++++++++++++++
ui/options_advanced.ui | 63 ++++++++++++++++++++++++++++++++
4 files changed, 157 insertions(+), 2 deletions(-)
create mode 100644 picard/ui/ui_options_advanced.py
create mode 100644 ui/options_advanced.ui
diff --git a/picard/tagger.py b/picard/tagger.py
index ac993ffae..7a543e7a7 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -330,6 +330,10 @@ class Tagger(QtGui.QApplication):
def add_files(self, filenames, target=None):
"""Add files to the tagger."""
log.debug("Adding files %r", filenames)
+ ignoreregex = None
+ pattern = config.setting['ignore_regex']
+ if pattern:
+ ignoreregex = re.compile(pattern)
ignore_hidden = not config.persist["show_hidden_files"]
new_files = []
for filename in filenames:
@@ -337,6 +341,9 @@ class Tagger(QtGui.QApplication):
if ignore_hidden and is_hidden_path(filename):
log.debug("File ignored (hidden): %s" % (filename))
continue
+ if ignoreregex is not None and ignoreregex.search(filename):
+ log.info("File ignored (matching %s): %s" % (pattern, filename))
+ continue
if filename not in self.files:
file = open_file(filename)
if file:
diff --git a/picard/ui/options/advanced.py b/picard/ui/options/advanced.py
index 881312fa4..3f3593ed7 100644
--- a/picard/ui/options/advanced.py
+++ b/picard/ui/options/advanced.py
@@ -17,7 +17,12 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from picard.ui.options import OptionsPage, register_options_page
+from PyQt4.QtGui import QPalette, QColor
+import re
+
+from picard import config
+from picard.ui.options import OptionsPage, OptionsCheckError, register_options_page
+from picard.ui.ui_options_advanced import Ui_AdvancedOptionsPage
class AdvancedOptionsPage(OptionsPage):
@@ -26,7 +31,39 @@ class AdvancedOptionsPage(OptionsPage):
TITLE = N_("Advanced")
PARENT = None
SORT_ORDER = 90
- ACTIVE = False
+ ACTIVE = True
+
+ options = [
+ config.TextOption("setting", "ignore_regex", ""),
+ ]
+
+ def __init__(self, parent=None):
+ super(AdvancedOptionsPage, self).__init__(parent)
+ self.ui = Ui_AdvancedOptionsPage()
+ self.ui.setupUi(self)
+ self.ui.ignore_regex.textChanged.connect(self.live_checker)
+
+ def load(self):
+ self.ui.ignore_regex.setText(config.setting["ignore_regex"])
+
+ def save(self):
+ config.setting["ignore_regex"] = unicode(self.ui.ignore_regex.text())
+
+ def live_checker(self, text):
+ self.ui.regex_error.setStyleSheet("")
+ self.ui.regex_error.setText("")
+ try:
+ self.check()
+ except OptionsCheckError as e:
+ self.ui.regex_error.setStyleSheet(self.STYLESHEET_ERROR)
+ self.ui.regex_error.setText(e.info)
+ return
+
+ def check(self):
+ try:
+ re.compile(unicode(self.ui.ignore_regex.text()))
+ except re.error as e:
+ raise OptionsCheckError(_("Regex Error"), str(e))
register_options_page(AdvancedOptionsPage)
diff --git a/picard/ui/ui_options_advanced.py b/picard/ui/ui_options_advanced.py
new file mode 100644
index 000000000..8d3fb9c82
--- /dev/null
+++ b/picard/ui/ui_options_advanced.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'ui/options_advanced.ui'
+#
+# Created: Wed Dec 25 02:35:20 2013
+# by: PyQt4 UI code generator 4.9.3
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt4 import QtCore, QtGui
+
+try:
+ _fromUtf8 = QtCore.QString.fromUtf8
+except AttributeError:
+ _fromUtf8 = lambda s: s
+
+class Ui_AdvancedOptionsPage(object):
+ def setupUi(self, AdvancedOptionsPage):
+ AdvancedOptionsPage.setObjectName(_fromUtf8("AdvancedOptionsPage"))
+ AdvancedOptionsPage.resize(338, 435)
+ self.vboxlayout = QtGui.QVBoxLayout(AdvancedOptionsPage)
+ self.vboxlayout.setObjectName(_fromUtf8("vboxlayout"))
+ self.groupBox = QtGui.QGroupBox(AdvancedOptionsPage)
+ self.groupBox.setObjectName(_fromUtf8("groupBox"))
+ self.gridlayout = QtGui.QGridLayout(self.groupBox)
+ self.gridlayout.setSpacing(2)
+ self.gridlayout.setObjectName(_fromUtf8("gridlayout"))
+ self.label_ignore_regex = QtGui.QLabel(self.groupBox)
+ self.label_ignore_regex.setObjectName(_fromUtf8("label_ignore_regex"))
+ self.gridlayout.addWidget(self.label_ignore_regex, 1, 0, 1, 1)
+ self.ignore_regex = QtGui.QLineEdit(self.groupBox)
+ self.ignore_regex.setObjectName(_fromUtf8("ignore_regex"))
+ self.gridlayout.addWidget(self.ignore_regex, 2, 0, 1, 1)
+ self.regex_error = QtGui.QLabel(self.groupBox)
+ self.regex_error.setText(_fromUtf8(""))
+ self.regex_error.setObjectName(_fromUtf8("regex_error"))
+ self.gridlayout.addWidget(self.regex_error, 3, 0, 1, 1)
+ self.vboxlayout.addWidget(self.groupBox)
+ spacerItem = QtGui.QSpacerItem(181, 21, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
+ self.vboxlayout.addItem(spacerItem)
+
+ self.retranslateUi(AdvancedOptionsPage)
+ QtCore.QMetaObject.connectSlotsByName(AdvancedOptionsPage)
+
+ def retranslateUi(self, AdvancedOptionsPage):
+ self.groupBox.setTitle(_("Advanced options"))
+ self.label_ignore_regex.setText(_("Ignore file paths matching the following regular expression:"))
+
diff --git a/ui/options_advanced.ui b/ui/options_advanced.ui
new file mode 100644
index 000000000..0d8a399c5
--- /dev/null
+++ b/ui/options_advanced.ui
@@ -0,0 +1,63 @@
+
+
+ AdvancedOptionsPage
+
+
+
+ 0
+ 0
+ 338
+ 435
+
+
+
+ -
+
+
+ Advanced options
+
+
+
+ 2
+
+
-
+
+
+ Ignore file paths matching the following regular expression:
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 181
+ 21
+
+
+
+
+
+
+
+ ignore_regex
+
+
+
+
From faffa6db01bd3730d9ed7768de139c5c5fe4a8e6 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 11:10:55 +0100
Subject: [PATCH 05/59] Add "ignore_regex ..." to NEWS.txt
---
NEWS.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/NEWS.txt b/NEWS.txt
index f7c1c77b4..8babfed17 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -17,6 +17,7 @@
* Append system information to user-agent string
* Compilation tag/variable aligned with iTunes, set only for Various Artists type compilations.
* Ignore directories and files while indexing when show_hidden_files option is set to False (PICARD-528)
+ * Add ignore_regex option which allows one to ignore matching paths, can be set in Options > Advanced (PICARD-528)
Version 1.2 - 2013-03-30
* Picard now requires at least Python 2.6
From 30b166fba11870fff4eaa75651586e8dc79e7a90 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 21:57:29 +0100
Subject: [PATCH 06/59] Fix missing QtCore import
---
picard/ui/util.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/ui/util.py b/picard/ui/util.py
index d7b36d80c..d3056f8a5 100644
--- a/picard/ui/util.py
+++ b/picard/ui/util.py
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
-from PyQt4 import QtGui
+from PyQt4 import QtCore, QtGui
from picard import config
from picard.util import find_existing_path
From be75583546d9a941e99f84d1f8221403ab02b7c9 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 23:56:25 +0100
Subject: [PATCH 07/59] Remove unused imports
---
picard/acoustid.py | 2 +-
picard/cluster.py | 3 +--
picard/config.py | 2 +-
picard/const.py | 1 -
picard/coverart.py | 3 +--
picard/file.py | 2 --
picard/formats/mutagenext/compatid3.py | 2 +-
picard/releasegroup.py | 3 +--
picard/tagger.py | 2 --
picard/ui/infostatus.py | 1 -
picard/ui/mainwindow.py | 1 -
picard/ui/options/dialog.py | 1 -
picard/ui/options/fingerprinting.py | 2 +-
picard/ui/options/metadata.py | 1 -
picard/ui/passworddialog.py | 2 +-
picard/util/thread.py | 2 +-
16 files changed, 9 insertions(+), 21 deletions(-)
diff --git a/picard/acoustid.py b/picard/acoustid.py
index 2d7b526f1..c50c7e532 100644
--- a/picard/acoustid.py
+++ b/picard/acoustid.py
@@ -21,7 +21,7 @@ from collections import deque
from functools import partial
from PyQt4 import QtCore
from picard import config, log
-from picard.const import ACOUSTID_KEY, FPCALC_NAMES
+from picard.const import FPCALC_NAMES
from picard.util import find_executable
from picard.webservice import XmlNode
diff --git a/picard/cluster.py b/picard/cluster.py
index c14e47818..0977b6672 100644
--- a/picard/cluster.py
+++ b/picard/cluster.py
@@ -24,10 +24,9 @@ from heapq import heappush, heappop
from PyQt4 import QtCore
from picard import config
from picard.metadata import Metadata
-from picard.similarity import similarity2, similarity
+from picard.similarity import similarity
from picard.ui.item import Item
from picard.util import format_time
-from picard.mbxml import artist_credit_from_node
class Cluster(QtCore.QObject, Item):
diff --git a/picard/config.py b/picard/config.py
index 5a4f8c176..983091980 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -20,7 +20,7 @@
from operator import itemgetter
from PyQt4 import QtCore
from picard import (PICARD_APP_NAME, PICARD_ORG_NAME, PICARD_VERSION,
- version_to_string, version_from_string, log)
+ version_to_string, version_from_string)
from picard.util import LockableObject, rot13
diff --git a/picard/const.py b/picard/const.py
index 31152db57..68af4f98b 100644
--- a/picard/const.py
+++ b/picard/const.py
@@ -19,7 +19,6 @@
import os
import sys
-import re
# Install gettext "noop" function in case const.py gets imported directly.
import __builtin__
diff --git a/picard/coverart.py b/picard/coverart.py
index df5cac28d..a71264f0f 100644
--- a/picard/coverart.py
+++ b/picard/coverart.py
@@ -24,10 +24,9 @@
import json
import re
import traceback
-import picard.webservice
from functools import partial
from picard import config, log
-from picard.metadata import Metadata, is_front_image
+from picard.metadata import is_front_image
from picard.util import mimetype, parse_amazon_url
from picard.const import CAA_HOST, CAA_PORT
from PyQt4.QtCore import QUrl, QObject
diff --git a/picard/file.py b/picard/file.py
index 3536ddce6..a9c7f8cf3 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -29,11 +29,9 @@ from operator import itemgetter
from collections import defaultdict
from PyQt4 import QtCore
from picard import config, log
-from picard.track import Track
from picard.metadata import Metadata
from picard.ui.item import Item
from picard.script import ScriptParser
-from picard.similarity import similarity2
from picard.util import (
decode_filename,
encode_filename,
diff --git a/picard/formats/mutagenext/compatid3.py b/picard/formats/mutagenext/compatid3.py
index aa3612645..a3098c5eb 100644
--- a/picard/formats/mutagenext/compatid3.py
+++ b/picard/formats/mutagenext/compatid3.py
@@ -22,7 +22,7 @@ import struct
from struct import pack, unpack
import mutagen
from mutagen._util import insert_bytes
-from mutagen.id3 import ID3, Frame, Frames, Frames_2_2, TextFrame, TORY, \
+from mutagen.id3 import ID3, Frames, Frames_2_2, TextFrame, TORY, \
TYER, TIME, APIC, IPLS, TDAT, BitPaddedInt, MakeID3v1
diff --git a/picard/releasegroup.py b/picard/releasegroup.py
index 70d4bc031..274ecba28 100644
--- a/picard/releasegroup.py
+++ b/picard/releasegroup.py
@@ -21,8 +21,7 @@ import traceback
from collections import defaultdict
from functools import partial
from itertools import combinations
-from PyQt4 import QtCore
-from picard import config, log
+from picard import log
from picard.metadata import Metadata
from picard.dataobj import DataObject
from picard.mbxml import media_formats_from_node, label_info_from_node
diff --git a/picard/tagger.py b/picard/tagger.py
index b2d2208af..f5904fa51 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -26,7 +26,6 @@ import re
import shutil
import signal
import sys
-from collections import deque
from functools import partial
from itertools import chain
@@ -61,7 +60,6 @@ from picard.track import Track, NonAlbumTrack
from picard.releasegroup import ReleaseGroup
from picard.collection import load_user_collections
from picard.ui.mainwindow import MainWindow
-from picard.ui.itemviews import BaseTreeView
from picard.plugin import PluginManager
from picard.acoustidmanager import AcoustIDManager
from picard.util import (
diff --git a/picard/ui/infostatus.py b/picard/ui/infostatus.py
index 769a5b9db..bfb1c8dce 100644
--- a/picard/ui/infostatus.py
+++ b/picard/ui/infostatus.py
@@ -18,7 +18,6 @@
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QIcon
-from picard import config
from picard.util import icontheme
from picard.ui.ui_infostatus import Ui_InfoStatus
diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py
index 6d4ad1c2d..3e27eafc7 100644
--- a/picard/ui/mainwindow.py
+++ b/picard/ui/mainwindow.py
@@ -22,7 +22,6 @@ from PyQt4 import QtCore, QtGui
import sys
import os.path
-from functools import partial
from picard import config, log
from picard.file import File
from picard.track import Track
diff --git a/picard/ui/options/dialog.py b/picard/ui/options/dialog.py
index 6a27b107b..9c49cfeb7 100644
--- a/picard/ui/options/dialog.py
+++ b/picard/ui/options/dialog.py
@@ -19,7 +19,6 @@
from PyQt4 import QtCore, QtGui
from picard import config
-from picard.plugin import ExtensionPoint
from picard.util import webbrowser2
from picard.ui.util import StandardButton
from picard.ui.options import (
diff --git a/picard/ui/options/fingerprinting.py b/picard/ui/options/fingerprinting.py
index 52f0bc355..3a3e434ce 100644
--- a/picard/ui/options/fingerprinting.py
+++ b/picard/ui/options/fingerprinting.py
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtGui
from picard import config
from picard.util import webbrowser2, find_executable
from picard.const import FPCALC_NAMES
diff --git a/picard/ui/options/metadata.py b/picard/ui/options/metadata.py
index 6ee2eba21..410535844 100644
--- a/picard/ui/options/metadata.py
+++ b/picard/ui/options/metadata.py
@@ -17,7 +17,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from PyQt4 import QtCore
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_metadata import Ui_MetadataOptionsPage
diff --git a/picard/ui/passworddialog.py b/picard/ui/passworddialog.py
index 804e7e062..32335f519 100644
--- a/picard/ui/passworddialog.py
+++ b/picard/ui/passworddialog.py
@@ -17,7 +17,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtGui
from picard import config
from picard.ui.ui_passworddialog import Ui_PasswordDialog
from picard.util import rot13
diff --git a/picard/util/thread.py b/picard/util/thread.py
index 8c9b36fbf..095f8bbab 100644
--- a/picard/util/thread.py
+++ b/picard/util/thread.py
@@ -19,7 +19,7 @@
import sys
import traceback
-from PyQt4.QtCore import QThreadPool, QRunnable, QCoreApplication, QEvent
+from PyQt4.QtCore import QRunnable, QCoreApplication, QEvent
class ProxyToMainEvent(QEvent):
From 1b84102265937425c5a9476f1092d8b14de3a9cc Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 23:15:22 +0100
Subject: [PATCH 08/59] Remove unused code
---
picard/util/bytes2human.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/picard/util/bytes2human.py b/picard/util/bytes2human.py
index bfc7ceca7..34dc33459 100644
--- a/picard/util/bytes2human.py
+++ b/picard/util/bytes2human.py
@@ -18,8 +18,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import locale
-import picard.i18n
-
"""
Helper class to convert bytes to human-readable form
@@ -118,8 +116,3 @@ def calc_unit(number, multiple=1000):
return (sign * n, suffix)
else:
n /= multiple
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
From 7c6d3e9c3bfee7caf51c83e6acb28465ac0fc94f Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Fri, 27 Dec 2013 23:16:31 +0100
Subject: [PATCH 09/59] decimal(): fix missing parameter `prec` and update
tests
---
picard/util/bytes2human.py | 2 +-
test/test_bytes2human.py | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/picard/util/bytes2human.py b/picard/util/bytes2human.py
index 34dc33459..9b31c23b3 100644
--- a/picard/util/bytes2human.py
+++ b/picard/util/bytes2human.py
@@ -51,7 +51,7 @@ def decimal(number, prec=1):
>>> [decimal(n) for n in [1000, 1024, 15500]]
['1 kB', '1 kB', '15.5 kB']
"""
- return short_string(int(number), 1000)
+ return short_string(int(number), 1000, prec)
def binary(number, prec=1):
diff --git a/test/test_bytes2human.py b/test/test_bytes2human.py
index 7a37737c2..9f8d53305 100644
--- a/test/test_bytes2human.py
+++ b/test/test_bytes2human.py
@@ -30,8 +30,11 @@ class Testbytes2human(unittest.TestCase):
self.assertEqual(bytes2human.binary(45682), '44.6 KiB')
self.assertEqual(bytes2human.binary(-45682), '-44.6 KiB')
+ self.assertEqual(bytes2human.binary(-45682, 2), '-44.61 KiB')
self.assertEqual(bytes2human.decimal(45682), '45.7 kB')
+ self.assertEqual(bytes2human.decimal(45682, 2), '45.68 kB')
self.assertEqual(bytes2human.decimal(9223372036854775807), '9223.4 PB')
+ self.assertEqual(bytes2human.decimal(9223372036854775807, 3), '9223.372 PB')
self.assertEqual(bytes2human.decimal(123.6), '123 B')
self.assertRaises(ValueError, bytes2human.decimal, 'xxx')
self.assertRaises(ValueError, bytes2human.decimal, '123.6')
From 5a02f9d719c1a0588d5eff675371265682782e29 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 02:16:05 +0100
Subject: [PATCH 10/59] `prec` -> `scale`
---
picard/util/bytes2human.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/picard/util/bytes2human.py b/picard/util/bytes2human.py
index 9b31c23b3..ea8fb4eb2 100644
--- a/picard/util/bytes2human.py
+++ b/picard/util/bytes2human.py
@@ -44,26 +44,26 @@ _BYTES_STRINGS_I18N = (
)
-def decimal(number, prec=1):
+def decimal(number, scale=1):
"""
Convert bytes to short human-readable string, decimal mode
>>> [decimal(n) for n in [1000, 1024, 15500]]
['1 kB', '1 kB', '15.5 kB']
"""
- return short_string(int(number), 1000, prec)
+ return short_string(int(number), 1000, scale)
-def binary(number, prec=1):
+def binary(number, scale=1):
"""
Convert bytes to short human-readable string, binary mode
>>> [binary(n) for n in [1000, 1024, 15500]]
['1000 B', '1 KiB', '15.1 KiB']
"""
- return short_string(int(number), 1024, prec)
+ return short_string(int(number), 1024, scale)
-def short_string(number, multiple, prec=1):
+def short_string(number, multiple, scale=1):
"""
Returns short human-readable string for `number` bytes
>>> [short_string(n, 1024, 2) for n in [1000, 1100, 15500]]
@@ -73,12 +73,12 @@ def short_string(number, multiple, prec=1):
"""
num, unit = calc_unit(number, multiple)
n = int(num)
- nr = round(num, prec)
+ nr = round(num, scale)
if n == nr or unit == 'B':
fmt = '%d'
num = n
else:
- fmt = '%%0.%df' % prec
+ fmt = '%%0.%df' % scale
num = nr
fmtnum = locale.format(fmt, num)
return _("%s " + unit) % fmtnum
From ff0de4e38250487939789c538738f81ab3ec4778 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 10:52:34 +0100
Subject: [PATCH 11/59] ClusterEngine.cluster(): remove unused return value
---
picard/cluster.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/picard/cluster.py b/picard/cluster.py
index c14e47818..9ce6afac7 100644
--- a/picard/cluster.py
+++ b/picard/cluster.py
@@ -190,10 +190,10 @@ class Cluster(QtCore.QObject, Item):
albumDict.add(album)))
artist_cluster_engine = ClusterEngine(artistDict)
- artist_cluster = artist_cluster_engine.cluster(threshold)
+ artist_cluster_engine.cluster(threshold)
album_cluster_engine = ClusterEngine(albumDict)
- album_cluster = album_cluster_engine.cluster(threshold)
+ album_cluster_engine.cluster(threshold)
# Arrange tracks into albums
albums = {}
@@ -459,7 +459,5 @@ class ClusterEngine(object):
self.idClusterIndex[match] = match0
del self.clusterBins[match1]
- return self.clusterBins
-
def can_refresh(self):
return False
From 4b0239fc0c0e626a179fd93952538af9d074e36f Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 11:56:34 +0100
Subject: [PATCH 12/59] get_cdrom_drives(): code cleanup
---
picard/util/cdrom.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/picard/util/cdrom.py b/picard/util/cdrom.py
index 64ae157d3..4b0cef41b 100644
--- a/picard/util/cdrom.py
+++ b/picard/util/cdrom.py
@@ -79,10 +79,11 @@ elif sys.platform == 'linux2' and QFile.exists(LINUX_CDROM_INFO):
elif key == 'Can play audio':
drive_audio_caps = [v == '1' for v in
QString(values).trimmed().split(QRegExp("\\s+"), QString.SkipEmptyParts)]
+ break # no need to continue passed this line
line = cdinfo.readLine()
# Show only drives that are capable of playing audio
- for drive in drive_names:
- if drive_audio_caps[drive_names.indexOf(drive)]:
+ for index, drive in enumerate(drive_names):
+ if drive_audio_caps[index]:
device = u'/dev/%s' % drive
symlink_target = QFile.symLinkTarget(device)
if symlink_target != '':
From e4852cf0d4d5bf73ed99d0d6cc2d57f7c8039f4e Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:02:06 +0100
Subject: [PATCH 13/59] File._load(): makes proto matches subclass definitions,
add filename parameter
---
picard/file.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/file.py b/picard/file.py
index 3536ddce6..620bcfa59 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -144,7 +144,7 @@ class File(QtCore.QObject, Item):
def has_error(self):
return self.state == File.ERROR
- def _load(self):
+ def _load(self, filename):
"""Load metadata from the file."""
raise NotImplementedError
From 17bb6df137dcef73cdaaaf834ddbb4eee4a9b82d Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:36:41 +0100
Subject: [PATCH 14/59] Indentation fix
---
picard/file.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/picard/file.py b/picard/file.py
index 620bcfa59..041bc7621 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -359,8 +359,8 @@ class File(QtCore.QObject, Item):
# image multiple times
if (os.path.exists(new_filename) and
os.path.getsize(new_filename) == len(data)):
- log.debug("Identical file size, not saving %r", image_filename)
- continue
+ log.debug("Identical file size, not saving %r", image_filename)
+ continue
log.debug("Saving cover images to %r", image_filename)
new_dirname = os.path.dirname(image_filename)
if not os.path.isdir(new_dirname):
From cac1e3dd895858535872a288391db4bf78ea7d24 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:37:07 +0100
Subject: [PATCH 15/59] Unused variable `e` removed
---
picard/log.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/log.py b/picard/log.py
index d4faef298..1f4317f37 100644
--- a/picard/log.py
+++ b/picard/log.py
@@ -62,7 +62,7 @@ class Logger(object):
for func in self._receivers:
try:
thread.to_main(func, level, time, message)
- except Exception as e:
+ except:
import traceback
traceback.print_exc()
From b84380fd70ecc7a299509a7eaf1fb2fe396aa416 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:37:59 +0100
Subject: [PATCH 16/59] Rewrite loop as expression value is unused
---
picard/ui/cdlookup.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/picard/ui/cdlookup.py b/picard/ui/cdlookup.py
index cc5bd4810..cd9355590 100644
--- a/picard/ui/cdlookup.py
+++ b/picard/ui/cdlookup.py
@@ -50,7 +50,8 @@ class CDLookupDialog(QtGui.QDialog):
item.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(release.id))
self.ui.release_list.setCurrentItem(self.ui.release_list.topLevelItem(0))
self.ui.ok_button.setEnabled(True)
- [self.ui.release_list.resizeColumnToContents(i) for i in range(self.ui.release_list.columnCount() - 1)]
+ for i in range(self.ui.release_list.columnCount() - 1):
+ self.ui.release_list.resizeColumnToContents(i)
# Sort by descending date, then ascending country
self.ui.release_list.sortByColumn(3, QtCore.Qt.AscendingOrder)
self.ui.release_list.sortByColumn(2, QtCore.Qt.DescendingOrder)
From 60b6cbddab7725ba4cdbf4bfaf6977d9ac2c1141 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:38:28 +0100
Subject: [PATCH 17/59] Rewrite test as expression value is unused
---
picard/ui/itemviews.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/picard/ui/itemviews.py b/picard/ui/itemviews.py
index 1a6d759d7..9b5d52ec8 100644
--- a/picard/ui/itemviews.py
+++ b/picard/ui/itemviews.py
@@ -308,7 +308,9 @@ class BaseTreeView(QtGui.QTreeWidget):
action.setChecked(True)
action.triggered.connect(partial(obj.switch_release_version, version["id"]))
- _add_other_versions() if obj.release_group.loaded else \
+ if obj.release_group.loaded:
+ _add_other_versions()
+ else:
obj.release_group.load_versions(_add_other_versions)
releases_menu.setEnabled(True)
else:
From 88ae83de7891fc4349ff599a295e76b1809a1b23 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 12:38:34 +0100
Subject: [PATCH 18/59] Rewrite loop as expression value is unused
---
picard/ui/metadatabox.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/picard/ui/metadatabox.py b/picard/ui/metadatabox.py
index bec999ff0..94b7d08ba 100644
--- a/picard/ui/metadatabox.py
+++ b/picard/ui/metadatabox.py
@@ -290,7 +290,9 @@ class MetadataBox(QtGui.QTableWidget):
self.set_tag_values(tag, [""])
def remove_selected_tags(self):
- (self.remove_tag(tag) for tag in self.selected_tags() if self.tag_is_removable(tag))
+ for tag in self.selected_tags():
+ if self.tag_is_removable(tag):
+ self.remove_tag(tag)
def tag_is_removable(self, tag):
return self.tag_diff.status[tag] & TagStatus.NotRemovable == 0
From aed7091c3a762e867d00a2f04e5164143189cb6c Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 13:22:49 +0100
Subject: [PATCH 19/59] Add missing header
---
picard/i18n.py | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/picard/i18n.py b/picard/i18n.py
index 8520ee252..03b61850e 100644
--- a/picard/i18n.py
+++ b/picard/i18n.py
@@ -1,3 +1,22 @@
+# -*- coding: utf-8 -*-
+#
+# Picard, the next-generation MusicBrainz tagger
+# Copyright (C) 2013 Laurent Monin
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
import gettext
import locale
import os.path
From 220710b046039b24cdf553bb287f4eb55bd35a0b Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sat, 28 Dec 2013 13:23:47 +0100
Subject: [PATCH 20/59] coding: UTF-8 -> coding: utf-8, as all other files
---
picard/ui/filebrowser.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/ui/filebrowser.py b/picard/ui/filebrowser.py
index c469aaa67..310a2f567 100644
--- a/picard/ui/filebrowser.py
+++ b/picard/ui/filebrowser.py
@@ -1,4 +1,4 @@
-# -*- coding: UTF-8 -*-
+# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2006-2007 Lukáš Lalinský
From f79f981ac4d862e6897f73d8dfcda6920b235312 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sun, 29 Dec 2013 01:27:27 +0100
Subject: [PATCH 21/59] Fix encoding of limit parameter value in webservice
query (limit=%19)
This is a very old bug it seems, it was indirectly introduced by
commit 9092a7abcae5254e581497b346b2167a5e37cb26
The missing str() was causing integer value 25 to be encoded as
ascii char 25, then, after percent encoding, limit=%19 in the search url.
---
picard/webservice.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/webservice.py b/picard/webservice.py
index d9b17b8b8..721d34617 100644
--- a/picard/webservice.py
+++ b/picard/webservice.py
@@ -392,7 +392,7 @@ class XmlWebService(QtCore.QObject):
query = []
for name, value in kwargs.items():
if name == 'limit':
- filters.append((name, value))
+ filters.append((name, str(value)))
else:
value = _escape_lucene_query(value).strip().lower()
if value:
From fa11a96b410c64c7c096fee37a3da2f80d483ad1 Mon Sep 17 00:00:00 2001
From: Johannes Dewender
Date: Sun, 29 Dec 2013 19:46:11 +0100
Subject: [PATCH 22/59] PICARD-544: include socket module in exe
This is needed by urllib, which is imported since
26f20228eb95d4b55968e56796228bca7ebcffa7.
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 306869719..4873da869 100755
--- a/setup.py
+++ b/setup.py
@@ -405,7 +405,7 @@ try:
args['options'] = {
'bdist_nsis': {
'includes': ['json', 'sip'] + [e.name for e in ext_modules],
- 'excludes': ['ssl', 'socket', 'bz2'],
+ 'excludes': ['ssl', 'bz2'],
'optimize': 2,
},
}
From e633bcde115e4afccb1a98e322905054617eed9d Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sun, 29 Dec 2013 21:01:14 +0100
Subject: [PATCH 23/59] Drop urllib dependency, use QUrl.toPercentEncoding
instead of urllib.quote
---
picard/webservice.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/picard/webservice.py b/picard/webservice.py
index 721d34617..55442e2b9 100644
--- a/picard/webservice.py
+++ b/picard/webservice.py
@@ -28,7 +28,6 @@ import re
import time
import os.path
import platform
-import urllib
from collections import deque, defaultdict
from functools import partial
from PyQt4 import QtCore, QtNetwork
@@ -55,8 +54,9 @@ USER_AGENT_STRING = '%s-%s/%s (%s;%s-%s)' % (PICARD_ORG_NAME, PICARD_APP_NAME,
platform.platform(),
platform.python_implementation(),
platform.python_version())
-CLIENT_STRING = urllib.quote('%s %s-%s' % (PICARD_ORG_NAME, PICARD_APP_NAME,
- PICARD_VERSION_STR))
+CLIENT_STRING = str(QUrl.toPercentEncoding('%s %s-%s' % (PICARD_ORG_NAME,
+ PICARD_APP_NAME,
+ PICARD_VERSION_STR)))
def _escape_lucene_query(text):
From 13423436590dc6d598b92d8f896e54dcce11546a Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sun, 29 Dec 2013 21:01:43 +0100
Subject: [PATCH 24/59] Exclude socket module again, since it was only needed
by urllib
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 4873da869..306869719 100755
--- a/setup.py
+++ b/setup.py
@@ -405,7 +405,7 @@ try:
args['options'] = {
'bdist_nsis': {
'includes': ['json', 'sip'] + [e.name for e in ext_modules],
- 'excludes': ['ssl', 'bz2'],
+ 'excludes': ['ssl', 'socket', 'bz2'],
'optimize': 2,
},
}
From 5289f7b461014f3f16e139aca3bc5cabf4adad35 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Mon, 30 Dec 2013 12:08:57 +0100
Subject: [PATCH 25/59] transifex.net is deprecated, use transifex.com instead
http://support.transifex.com/customer/portal/questions/1160404-improve-ssl-security-for-transifex-net
tx client is giving a message about it too
Also add translation type 'PO'.
---
.tx/config | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.tx/config b/.tx/config
index ea944391c..9ada80424 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,8 +1,8 @@
[main]
-host = https://www.transifex.net
+host = https://www.transifex.com
[musicbrainz.picard]
file_filter = po/.po
source_file = po/picard.pot
source_lang = en
-
+type = PO
From e63bc3dab57f2595f362c247289268f8fabcfc07 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:07:19 +0100
Subject: [PATCH 26/59] Name upgrade functions after full version
---
picard/tagger.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index f5904fa51..b4064ca2e 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -165,7 +165,7 @@ class Tagger(QtGui.QApplication):
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
- def upgrade_to_v1_0():
+ def upgrade_to_v1_0_0_final_0():
def remove_va_file_naming_format(merge=True):
if merge:
config.setting["file_naming_format"] = (
@@ -197,7 +197,7 @@ class Tagger(QtGui.QApplication):
# default format, disabled
remove_va_file_naming_format(merge=False)
- def upgrade_to_v1_3():
+ def upgrade_to_v1_3_0_dev_2():
_s = config.setting
# the setting `windows_compatible_filenames` has been renamed
# to `windows_compatibility`
@@ -213,8 +213,8 @@ class Tagger(QtGui.QApplication):
log.debug("Config upgrade: convert preserved_tags separator "
"from spaces to comma")
- cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0)
- cfg.register_upgrade_hook("1.3.0dev2", upgrade_to_v1_3)
+ cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0_0_final_0)
+ cfg.register_upgrade_hook("1.3.0dev2", upgrade_to_v1_3_0_dev_2)
cfg.run_upgrade_hooks()
From 61900e1b80444e08efee75d8e2baafadc88e0f04 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 15:29:16 +0100
Subject: [PATCH 27/59] Ensure each upgrade function is run only once
---
picard/tagger.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index b4064ca2e..55c503aa6 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -197,7 +197,7 @@ class Tagger(QtGui.QApplication):
# default format, disabled
remove_va_file_naming_format(merge=False)
- def upgrade_to_v1_3_0_dev_2():
+ def upgrade_to_v1_3_0_dev_1():
_s = config.setting
# the setting `windows_compatible_filenames` has been renamed
# to `windows_compatibility`
@@ -207,6 +207,8 @@ class Tagger(QtGui.QApplication):
log.debug("Config upgrade: windows_compatible_filenames "
"renamed windows_compatibility")
+ def upgrade_to_v1_3_0_dev_2():
+ _s = config.setting
# preserved_tags spaces to comma separator, PICARD-536
if "preserved_tags" in _s:
_s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
@@ -214,6 +216,7 @@ class Tagger(QtGui.QApplication):
"from spaces to comma")
cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0_0_final_0)
+ cfg.register_upgrade_hook("1.3.0dev1", upgrade_to_v1_3_0_dev_1)
cfg.register_upgrade_hook("1.3.0dev2", upgrade_to_v1_3_0_dev_2)
cfg.run_upgrade_hooks()
From f8e85c3957231ef4e22dd16bb8496caadbe3e3f9 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:09:34 +0100
Subject: [PATCH 28/59] Move variable near where it is used
---
picard/tagger.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index 55c503aa6..c76d2fe6a 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -161,7 +161,6 @@ class Tagger(QtGui.QApplication):
self.window = MainWindow()
def _upgrade_config(self):
- cfg = config._config
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
@@ -215,6 +214,7 @@ class Tagger(QtGui.QApplication):
log.debug("Config upgrade: convert preserved_tags separator "
"from spaces to comma")
+ cfg = config._config
cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0_0_final_0)
cfg.register_upgrade_hook("1.3.0dev1", upgrade_to_v1_3_0_dev_1)
cfg.register_upgrade_hook("1.3.0dev2", upgrade_to_v1_3_0_dev_2)
From 672f47f72c76c78acfad82660fe18545511448f2 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 15:31:07 +0100
Subject: [PATCH 29/59] Define _s once in parent function
---
picard/tagger.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index c76d2fe6a..b94956213 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -161,6 +161,7 @@ class Tagger(QtGui.QApplication):
self.window = MainWindow()
def _upgrade_config(self):
+ _s = config.setting
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
@@ -197,7 +198,6 @@ class Tagger(QtGui.QApplication):
remove_va_file_naming_format(merge=False)
def upgrade_to_v1_3_0_dev_1():
- _s = config.setting
# the setting `windows_compatible_filenames` has been renamed
# to `windows_compatibility`
if "windows_compatible_filenames" in _s:
@@ -207,7 +207,6 @@ class Tagger(QtGui.QApplication):
"renamed windows_compatibility")
def upgrade_to_v1_3_0_dev_2():
- _s = config.setting
# preserved_tags spaces to comma separator, PICARD-536
if "preserved_tags" in _s:
_s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
From 6932ac0d1a008dfbb8c40a2b09214367a3ecd18a Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:11:09 +0100
Subject: [PATCH 30/59] config.setting -> _s in upgrade_to_v1_0_0_final_0() too
---
picard/tagger.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index b94956213..b0e005b49 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -168,23 +168,23 @@ class Tagger(QtGui.QApplication):
def upgrade_to_v1_0_0_final_0():
def remove_va_file_naming_format(merge=True):
if merge:
- config.setting["file_naming_format"] = (
+ _s["file_naming_format"] = (
"$if($eq(%compilation%,1),\n$noop(Various Artist "
"albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
- config.setting["va_file_naming_format"].toString(),
- config.setting["file_naming_format"]
+ _s["va_file_naming_format"].toString(),
+ _s["file_naming_format"]
))
- config.setting.remove("va_file_naming_format")
- config.setting.remove("use_va_format")
+ _s.remove("va_file_naming_format")
+ _s.remove("use_va_format")
- if ("va_file_naming_format" in config.setting and
- "use_va_format" in config.setting):
+ if ("va_file_naming_format" in _s and
+ "use_va_format" in _s):
- if config.setting["use_va_format"].toBool():
+ if _s["use_va_format"].toBool():
remove_va_file_naming_format()
self.window.show_va_removal_notice()
- elif (config.setting["va_file_naming_format"].toString() !=
+ elif (_s["va_file_naming_format"].toString() !=
r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
"cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
"%title%"):
From b93c4e37861816db1d251f418a03e2e7475c59f2 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:12:22 +0100
Subject: [PATCH 31/59] Add FIXME about broken upgrade hook
---
picard/tagger.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/picard/tagger.py b/picard/tagger.py
index b0e005b49..563a1c260 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -165,6 +165,8 @@ class Tagger(QtGui.QApplication):
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
+ # FIXME: this hook will not work as it is called before self.window
+ # instanciation
def upgrade_to_v1_0_0_final_0():
def remove_va_file_naming_format(merge=True):
if merge:
From 042b47db6a08806b7374ee9592da9008ed21e015 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:14:14 +0100
Subject: [PATCH 32/59] Make ConfigUpgradeError message more useful including
traceback
---
picard/config.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index 983091980..2ea475da1 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -124,13 +124,15 @@ class Config(QtCore.QSettings):
if self._version < hook['to']:
try:
hook['func'](*hook['args'])
- except Exception as e:
+ except:
+ import traceback
raise ConfigUpgradeError(
"Error during config upgrade from version %s to %s "
- "using %s(): %s" % (
+ "using %s():\n%s" % (
version_to_string(self._version),
version_to_string(hook['to']),
- hook['func'].__name__, e
+ hook['func'].__name__,
+ traceback.format_exc()
))
else:
hook['done'] = True
From 4554898e4288c4941d3a50e8fe3cbdc413058e2a Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 14:58:55 +0100
Subject: [PATCH 33/59] version_to_string(): be smarter and accept list with
strings
---
picard/__init__.py | 25 +++++++++++++++++--------
test/test_versions.py | 9 ++++++---
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/picard/__init__.py b/picard/__init__.py
index 22abb9e92..d0e324c66 100644
--- a/picard/__init__.py
+++ b/picard/__init__.py
@@ -25,16 +25,25 @@ PICARD_ORG_NAME = "MusicBrainz"
PICARD_VERSION = (1, 3, 0, 'dev', 2)
-def version_to_string(version_tuple, short=False):
- assert len(version_tuple) == 5
- assert version_tuple[3] in ('final', 'dev')
- if short and version_tuple[3] == 'final':
- if version_tuple[2] == 0:
- version_str = '%d.%d' % version_tuple[:2]
+def version_to_string(version, short=False):
+ assert len(version) == 5
+ assert version[3] in ('final', 'dev')
+ _version = []
+ for p in version:
+ try:
+ n = int(p)
+ except ValueError:
+ n = p
+ pass
+ _version.append(n)
+ version = tuple(_version)
+ if short and version[3] == 'final':
+ if version[2] == 0:
+ version_str = '%d.%d' % version[:2]
else:
- version_str = '%d.%d.%d' % version_tuple[:3]
+ version_str = '%d.%d.%d' % version[:3]
else:
- version_str = '%d.%d.%d%s%d' % version_tuple
+ version_str = '%d.%d.%d%s%d' % version
return version_str
diff --git a/test/test_versions.py b/test/test_versions.py
index 69d5a813a..d30832d3f 100644
--- a/test/test_versions.py
+++ b/test/test_versions.py
@@ -32,9 +32,8 @@ class VersionsTest(unittest.TestCase):
self.assertEqual(l, version_from_string(s))
def test_version_conv_6(self):
- self.assertRaises(TypeError, version_to_string, ('1', 0, 2, 'final', 0))
- self.assertRaises(AssertionError, version_to_string, (1, 0))
- self.assertRaises(TypeError, version_from_string, 1)
+ l = (1, 0, 2, 'xx', 0)
+ self.assertRaises(AssertionError, version_to_string, (l))
def test_version_conv_7(self):
l, s = (1, 1, 0, 'final', 0), '1.1'
@@ -51,3 +50,7 @@ class VersionsTest(unittest.TestCase):
def test_version_conv_10(self):
l, s = (1, 1, 0, 'dev', 0), '1.1.0dev0'
self.assertEqual(version_to_string(l, short=True), s)
+
+ def test_version_conv_11(self):
+ l, s = ('1', '1', '0', 'dev', '0'), '1.1.0dev0'
+ self.assertEqual(version_to_string(l), s)
From 5fc4129b32a252cd0fea9e2d49f2159dfbc87c14 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 15:26:22 +0100
Subject: [PATCH 34/59] Simplify hook registration by detecting upgrade hook
functions
---
picard/config.py | 21 ++++++++++++++++++++-
picard/tagger.py | 5 +----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index 2ea475da1..f0cf18a3f 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -17,6 +17,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import re
from operator import itemgetter
from PyQt4 import QtCore
from picard import (PICARD_APP_NAME, PICARD_ORG_NAME, PICARD_VERSION,
@@ -94,7 +95,25 @@ class Config(QtCore.QSettings):
else:
raise KeyError("Unknown profile '%s'" % (profilename,))
- def register_upgrade_hook(self, to_version_str, func, *args):
+ def _detect_upgrade_hooks(self, symbol_table):
+ """Detect upgrade functions based on their names"""
+ hooks = dict()
+ pattern = re.compile("^upgrade_to_v(\d+)_(\d+)_(\d+)_(dev|final)_(\d+)$")
+ for symbol in symbol_table:
+ match = re.search(pattern, symbol)
+ if not match:
+ continue
+ version = match.groups()
+ version_string = version_to_string(version)
+ hooks[version_string] = symbol_table[symbol]
+ return hooks
+
+ def register_upgrade_hooks(self, symbol_table):
+ hooks = self._detect_upgrade_hooks(symbol_table)
+ for version in sorted(hooks):
+ self._register_upgrade_hook(version, hooks[version])
+
+ def _register_upgrade_hook(self, to_version_str, func, *args):
"""Register a function to upgrade from one config version to another"""
to_version = version_from_string(to_version_str)
assert to_version <= PICARD_VERSION, "%r > %r !!!" % (to_version, PICARD_VERSION)
diff --git a/picard/tagger.py b/picard/tagger.py
index 563a1c260..e60aedf17 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -216,10 +216,7 @@ class Tagger(QtGui.QApplication):
"from spaces to comma")
cfg = config._config
- cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0_0_final_0)
- cfg.register_upgrade_hook("1.3.0dev1", upgrade_to_v1_3_0_dev_1)
- cfg.register_upgrade_hook("1.3.0dev2", upgrade_to_v1_3_0_dev_2)
-
+ cfg.register_upgrade_hooks(locals())
cfg.run_upgrade_hooks()
def move_files_to_album(self, files, albumid=None, album=None):
From 0b90379c71d15a2024a3882efcf12f0a4516d511 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Tue, 31 Dec 2013 15:26:41 +0100
Subject: [PATCH 35/59] Add a comment about adding an upgrade hook
---
picard/tagger.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/picard/tagger.py b/picard/tagger.py
index e60aedf17..c8216d99f 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -163,6 +163,13 @@ class Tagger(QtGui.QApplication):
def _upgrade_config(self):
_s = config.setting
+ # TO ADD AN UPGRADE HOOK:
+ # ----------------------
+ # add a function here, named after the version you want upgrade to
+ # ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
+ # and modify PICARD_VERSION to match it
+ #
+
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
# FIXME: this hook will not work as it is called before self.window
From 895fadf3c95aa6975dd6fef3ad722aa71a7bb623 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 1 Jan 2014 12:07:40 +0100
Subject: [PATCH 36/59] Add missing % character escaping
---
picard/tagger.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index c8216d99f..f413d545c 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -178,7 +178,7 @@ class Tagger(QtGui.QApplication):
def remove_va_file_naming_format(merge=True):
if merge:
_s["file_naming_format"] = (
- "$if($eq(%compilation%,1),\n$noop(Various Artist "
+ "$if($eq(%%compilation%%,1),\n$noop(Various Artist "
"albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
_s["va_file_naming_format"].toString(),
_s["file_naming_format"]
From c66c728c7913d042e39c5cd56578434facbb94a1 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 1 Jan 2014 12:53:15 +0100
Subject: [PATCH 37/59] Setup gettext before _upgrade_config() call
---
picard/tagger.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index f413d545c..06220b114 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -125,10 +125,12 @@ class Tagger(QtGui.QApplication):
check_io_encoding()
- self._upgrade_config()
-
+ # Must be before _upgrade_config() because upgrade dialogs need to be
+ # translated
setup_gettext(localedir, config.setting["ui_language"], log.debug)
+ self._upgrade_config()
+
self.xmlws = XmlWebService()
load_user_collections()
From ab1a827282f13e1574bf21efd5004e6730c4e174 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 1 Jan 2014 12:54:51 +0100
Subject: [PATCH 38/59] Move upgrade message boxes to _upgrade_config() instead
of MainWindow
Re-format messages so they wrap nicely.
Remove related FIXME
---
picard/tagger.py | 23 +++++++++++++++++++----
picard/ui/mainwindow.py | 17 -----------------
2 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/picard/tagger.py b/picard/tagger.py
index 06220b114..e640e8a6f 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -174,8 +174,6 @@ class Tagger(QtGui.QApplication):
# In version 1.0, the file naming formats for single and various
# artist releases were merged.
- # FIXME: this hook will not work as it is called before self.window
- # instanciation
def upgrade_to_v1_0_0_final_0():
def remove_va_file_naming_format(merge=True):
if merge:
@@ -191,16 +189,33 @@ class Tagger(QtGui.QApplication):
if ("va_file_naming_format" in _s and
"use_va_format" in _s):
+ msgbox = QtGui.QMessageBox()
if _s["use_va_format"].toBool():
remove_va_file_naming_format()
- self.window.show_va_removal_notice()
+ msgbox.information(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "Your file naming scheme has automatically been "
+ "merged with that of single artist albums."),
+ QtGui.QMessageBox.Ok)
elif (_s["va_file_naming_format"].toString() !=
r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
"cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
"%title%"):
- if self.window.confirm_va_removal():
+ answer = msgbox.question(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "You currently do not use this option, but have a "
+ "separate file naming scheme defined.\n"
+ "Do you want to remove it or merge it with your file "
+ "naming scheme for single artist albums?"),
+ _("Merge"), _("Remove"))
+
+ if answer:
remove_va_file_naming_format(merge=False)
else:
remove_va_file_naming_format()
diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py
index 3e27eafc7..d8e004d5f 100644
--- a/picard/ui/mainwindow.py
+++ b/picard/ui/mainwindow.py
@@ -668,23 +668,6 @@ class MainWindow(QtGui.QMainWindow):
from picard.ui.logview import HistoryView
HistoryView(self).show()
- def confirm_va_removal(self):
- return QtGui.QMessageBox.question(self,
- _("Various Artists file naming scheme removal"),
-_("""The separate file naming scheme for various artists albums has been
-removed in this version of Picard. You currently do not use the this option,
-but have a separate file naming scheme defined. Do you want to remove it or
-merge it with your file naming scheme for single artist albums?"""),
- _("Merge"), _("Remove"))
-
- def show_va_removal_notice(self):
- QtGui.QMessageBox.information(self,
- _("Various Artists file naming scheme removal"),
-_("""The separate file naming scheme for various artists albums has been
-removed in this version of Picard. Your file naming scheme has automatically
-been merged with that of single artist albums."""),
- QtGui.QMessageBox.Ok)
-
def open_bug_report(self):
webbrowser2.goto('troubleshooting')
From ef07fc2e900c2be5fce1aa383563f9d83977a99c Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 1 Jan 2014 16:25:19 +0100
Subject: [PATCH 39/59] Move upgrade code to its own file, no need to be a
Tagger method
---
picard/config_upgrade.py | 106 +++++++++++++++++++++++++++++++++++++++
picard/tagger.py | 87 ++------------------------------
2 files changed, 109 insertions(+), 84 deletions(-)
create mode 100644 picard/config_upgrade.py
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
new file mode 100644
index 000000000..4f4ab6021
--- /dev/null
+++ b/picard/config_upgrade.py
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+#
+# Picard, the next-generation MusicBrainz tagger
+# Copyright (C) 2013-2014 Laurent Monin
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+from PyQt4 import QtGui
+
+import re
+from picard import (log, config)
+
+
+def upgrade_config():
+ _s = config.setting
+
+ # TO ADD AN UPGRADE HOOK:
+ # ----------------------
+ # add a function here, named after the version you want upgrade to
+ # ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
+ # and modify PICARD_VERSION to match it
+ #
+
+ # In version 1.0, the file naming formats for single and various
+ # artist releases were merged.
+ def upgrade_to_v1_0_0_final_0():
+ def remove_va_file_naming_format(merge=True):
+ if merge:
+ _s["file_naming_format"] = (
+ "$if($eq(%%compilation%%,1),\n$noop(Various Artist "
+ "albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
+ _s["va_file_naming_format"].toString(),
+ _s["file_naming_format"]
+ ))
+ _s.remove("va_file_naming_format")
+ _s.remove("use_va_format")
+
+ if ("va_file_naming_format" in _s and
+ "use_va_format" in _s):
+
+ msgbox = QtGui.QMessageBox()
+ if _s["use_va_format"].toBool():
+ remove_va_file_naming_format()
+ msgbox.information(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "Your file naming scheme has automatically been "
+ "merged with that of single artist albums."),
+ QtGui.QMessageBox.Ok)
+
+ elif (_s["va_file_naming_format"].toString() !=
+ r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
+ "cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
+ "%title%"):
+
+ answer = msgbox.question(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "You currently do not use this option, but have a "
+ "separate file naming scheme defined.\n"
+ "Do you want to remove it or merge it with your file "
+ "naming scheme for single artist albums?"),
+ _("Merge"), _("Remove"))
+
+ if answer:
+ remove_va_file_naming_format(merge=False)
+ else:
+ remove_va_file_naming_format()
+ else:
+ # default format, disabled
+ remove_va_file_naming_format(merge=False)
+
+ def upgrade_to_v1_3_0_dev_1():
+ # the setting `windows_compatible_filenames` has been renamed
+ # to `windows_compatibility`
+ if "windows_compatible_filenames" in _s:
+ _s["windows_compatibility"] = _s["windows_compatible_filenames"]
+ _s.remove("windows_compatible_filenames")
+ log.debug("Config upgrade: windows_compatible_filenames "
+ "renamed windows_compatibility")
+
+ def upgrade_to_v1_3_0_dev_2():
+ # preserved_tags spaces to comma separator, PICARD-536
+ if "preserved_tags" in _s:
+ _s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
+ log.debug("Config upgrade: convert preserved_tags separator "
+ "from spaces to comma")
+
+ cfg = config._config
+ cfg.register_upgrade_hooks(locals())
+ cfg.run_upgrade_hooks()
diff --git a/picard/tagger.py b/picard/tagger.py
index e640e8a6f..52e5c42cf 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -22,7 +22,6 @@ from PyQt4 import QtGui, QtCore
import getopt
import os.path
-import re
import shutil
import signal
import sys
@@ -62,6 +61,7 @@ from picard.collection import load_user_collections
from picard.ui.mainwindow import MainWindow
from picard.plugin import PluginManager
from picard.acoustidmanager import AcoustIDManager
+from picard.config_upgrade import upgrade_config
from picard.util import (
decode_filename,
encode_filename,
@@ -125,11 +125,11 @@ class Tagger(QtGui.QApplication):
check_io_encoding()
- # Must be before _upgrade_config() because upgrade dialogs need to be
+ # Must be before config upgrade because upgrade dialogs need to be
# translated
setup_gettext(localedir, config.setting["ui_language"], log.debug)
- self._upgrade_config()
+ upgrade_config()
self.xmlws = XmlWebService()
@@ -162,87 +162,6 @@ class Tagger(QtGui.QApplication):
self.nats = None
self.window = MainWindow()
- def _upgrade_config(self):
- _s = config.setting
-
- # TO ADD AN UPGRADE HOOK:
- # ----------------------
- # add a function here, named after the version you want upgrade to
- # ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
- # and modify PICARD_VERSION to match it
- #
-
- # In version 1.0, the file naming formats for single and various
- # artist releases were merged.
- def upgrade_to_v1_0_0_final_0():
- def remove_va_file_naming_format(merge=True):
- if merge:
- _s["file_naming_format"] = (
- "$if($eq(%%compilation%%,1),\n$noop(Various Artist "
- "albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
- _s["va_file_naming_format"].toString(),
- _s["file_naming_format"]
- ))
- _s.remove("va_file_naming_format")
- _s.remove("use_va_format")
-
- if ("va_file_naming_format" in _s and
- "use_va_format" in _s):
-
- msgbox = QtGui.QMessageBox()
- if _s["use_va_format"].toBool():
- remove_va_file_naming_format()
- msgbox.information(msgbox,
- _("Various Artists file naming scheme removal"),
- _("The separate file naming scheme for various artists "
- "albums has been removed in this version of Picard.\n"
- "Your file naming scheme has automatically been "
- "merged with that of single artist albums."),
- QtGui.QMessageBox.Ok)
-
- elif (_s["va_file_naming_format"].toString() !=
- r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
- "cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
- "%title%"):
-
- answer = msgbox.question(msgbox,
- _("Various Artists file naming scheme removal"),
- _("The separate file naming scheme for various artists "
- "albums has been removed in this version of Picard.\n"
- "You currently do not use this option, but have a "
- "separate file naming scheme defined.\n"
- "Do you want to remove it or merge it with your file "
- "naming scheme for single artist albums?"),
- _("Merge"), _("Remove"))
-
- if answer:
- remove_va_file_naming_format(merge=False)
- else:
- remove_va_file_naming_format()
- else:
- # default format, disabled
- remove_va_file_naming_format(merge=False)
-
- def upgrade_to_v1_3_0_dev_1():
- # the setting `windows_compatible_filenames` has been renamed
- # to `windows_compatibility`
- if "windows_compatible_filenames" in _s:
- _s["windows_compatibility"] = _s["windows_compatible_filenames"]
- _s.remove("windows_compatible_filenames")
- log.debug("Config upgrade: windows_compatible_filenames "
- "renamed windows_compatibility")
-
- def upgrade_to_v1_3_0_dev_2():
- # preserved_tags spaces to comma separator, PICARD-536
- if "preserved_tags" in _s:
- _s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
- log.debug("Config upgrade: convert preserved_tags separator "
- "from spaces to comma")
-
- cfg = config._config
- cfg.register_upgrade_hooks(locals())
- cfg.run_upgrade_hooks()
-
def move_files_to_album(self, files, albumid=None, album=None):
"""Move `files` to tracks on album `albumid`."""
if album is None:
From 432ef5b996065db800201f2f0cd8c616c76f0c11 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Wed, 1 Jan 2014 18:17:02 +0100
Subject: [PATCH 40/59] Log explicit messages for config upgrades and drop now
useless comments
Use log.info() instead of log.debug() as it is useful for any user to know
config options were modified.
---
picard/config_upgrade.py | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index 4f4ab6021..695d30026 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -86,20 +86,17 @@ def upgrade_config():
remove_va_file_naming_format(merge=False)
def upgrade_to_v1_3_0_dev_1():
- # the setting `windows_compatible_filenames` has been renamed
- # to `windows_compatibility`
if "windows_compatible_filenames" in _s:
_s["windows_compatibility"] = _s["windows_compatible_filenames"]
_s.remove("windows_compatible_filenames")
- log.debug("Config upgrade: windows_compatible_filenames "
- "renamed windows_compatibility")
+ log.info('Config upgrade: option "windows_compatible_filenames" '
+ ' was renamed "windows_compatibility" (PICARD-110).')
def upgrade_to_v1_3_0_dev_2():
- # preserved_tags spaces to comma separator, PICARD-536
if "preserved_tags" in _s:
_s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
- log.debug("Config upgrade: convert preserved_tags separator "
- "from spaces to comma")
+ log.info('Config upgrade: option "preserved_tags" is now using '
+ 'comma instead of spaces as tag separator (PICARD-536).')
cfg = config._config
cfg.register_upgrade_hooks(locals())
From 69f59348c1d7b09129e682afa88b5449127ceae7 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 03:38:59 +0100
Subject: [PATCH 41/59] Add a README.md
---
README.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 README.md
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..f74a37151
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+MusicBrainz Picard
+==================
+
+[MusicBrainz Picard](http://musicbrainz.org/doc/MusicBrainz_Picard) is a cross-platform (Linux/Mac OS X/Windows) application written in Python and is the official [MusicBrainz](http://musicbrainz.org) tagger.
+
+Picard supports the majority of audio file formats, is capable of using audio fingerprints ([AcoustIDs](http://musicbrainz.org/doc/AcoustID)), performing CD lookups and [disc ID](http://musicbrainz.org/doc/Disc_ID) submissions, and it has excellent Unicode support. Additionally, there are several plugins available that extend Picard's features.
+
+When tagging files, Picard uses an album-oriented approach. This approach allows it to utilize the MusicBrainz data as effectively as possible and correctly tag your music. For more information, [see the illustrated quick start guide to tagging](http://musicbrainz.org/doc/How_To_Tag_Files_With_Picard).
+
+Picard is named after Captain Jean-Luc Picard from the TV series Star Trek: The Next Generation.
+
+Binary downloads are available [here](http://musicbrainz.org/doc/MusicBrainz_Picard).
+
+To submit bugs or improvements, please use [Picard bug-tracker](http://tickets.musicbrainz.org/browse/PICARD).
From 81ec25afcdea27158cd4cb5601aad0f61f1257d5 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 11:50:51 +0100
Subject: [PATCH 42/59] Make version_from_string() more tolerant
---
picard/__init__.py | 2 +-
test/test_versions.py | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/picard/__init__.py b/picard/__init__.py
index d0e324c66..eb5d67bba 100644
--- a/picard/__init__.py
+++ b/picard/__init__.py
@@ -48,7 +48,7 @@ def version_to_string(version, short=False):
def version_from_string(version_str):
- g = re.match(r"^(\d+).(\d+).(\d+)(dev|final)(\d+)$", version_str).groups()
+ g = re.match(r"^(\d+)[._](\d+)[._](\d+)[._]?(dev|final)[._]?(\d+)$", version_str).groups()
return (int(g[0]), int(g[1]), int(g[2]), g[3], int(g[4]))
diff --git a/test/test_versions.py b/test/test_versions.py
index d30832d3f..c99dca7e5 100644
--- a/test/test_versions.py
+++ b/test/test_versions.py
@@ -54,3 +54,7 @@ class VersionsTest(unittest.TestCase):
def test_version_conv_11(self):
l, s = ('1', '1', '0', 'dev', '0'), '1.1.0dev0'
self.assertEqual(version_to_string(l), s)
+
+ def test_version_conv_12(self):
+ l, s = (1, 1, 0, 'dev', 0), '1_1_0_dev_0'
+ self.assertEqual(l, version_from_string(s))
From d0005ccac93158b816a8dc3b285d7d02a7bc79cc Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 11:52:15 +0100
Subject: [PATCH 43/59] Drop autodetection of hooks, but still extract version
from hook name
---
picard/config.py | 26 ++++++--------------------
picard/config_upgrade.py | 4 +++-
2 files changed, 9 insertions(+), 21 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index f0cf18a3f..5604ae582 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -95,27 +95,13 @@ class Config(QtCore.QSettings):
else:
raise KeyError("Unknown profile '%s'" % (profilename,))
- def _detect_upgrade_hooks(self, symbol_table):
- """Detect upgrade functions based on their names"""
- hooks = dict()
- pattern = re.compile("^upgrade_to_v(\d+)_(\d+)_(\d+)_(dev|final)_(\d+)$")
- for symbol in symbol_table:
- match = re.search(pattern, symbol)
- if not match:
- continue
- version = match.groups()
- version_string = version_to_string(version)
- hooks[version_string] = symbol_table[symbol]
- return hooks
-
- def register_upgrade_hooks(self, symbol_table):
- hooks = self._detect_upgrade_hooks(symbol_table)
- for version in sorted(hooks):
- self._register_upgrade_hook(version, hooks[version])
-
- def _register_upgrade_hook(self, to_version_str, func, *args):
+ def register_upgrade_hook(self, func, *args):
"""Register a function to upgrade from one config version to another"""
- to_version = version_from_string(to_version_str)
+ pattern = re.compile("(\d+_\d+_\d+_(?:dev|final)_\d+)$")
+ match = re.search(pattern, func.__name__)
+ assert match, "config upgrade function name '%s' " \
+ "have to match '%s' regex" % (func.__name__, pattern.pattern)
+ to_version = version_from_string(match.group(1))
assert to_version <= PICARD_VERSION, "%r > %r !!!" % (to_version, PICARD_VERSION)
hook = {
'to': to_version,
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index 695d30026..fb8955d94 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -99,5 +99,7 @@ def upgrade_config():
'comma instead of spaces as tag separator (PICARD-536).')
cfg = config._config
- cfg.register_upgrade_hooks(locals())
+ cfg.register_upgrade_hook(upgrade_to_v1_0_0_final_0)
+ cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_1)
+ cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_2)
cfg.run_upgrade_hooks()
From 57732ce17beff29e030eefd1b6c15e6eca352909 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 13:00:40 +0100
Subject: [PATCH 44/59] Un-indent upgrade functions
---
picard/config_upgrade.py | 130 ++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 63 deletions(-)
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index fb8955d94..fa66ec20f 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -24,80 +24,84 @@ import re
from picard import (log, config)
-def upgrade_config():
- _s = config.setting
+# TO ADD AN UPGRADE HOOK:
+# ----------------------
+# add a function here, named after the version you want upgrade to
+# ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
+# and modify PICARD_VERSION to match it
+#
- # TO ADD AN UPGRADE HOOK:
- # ----------------------
- # add a function here, named after the version you want upgrade to
- # ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
- # and modify PICARD_VERSION to match it
- #
+_s = config.setting
- # In version 1.0, the file naming formats for single and various
- # artist releases were merged.
- def upgrade_to_v1_0_0_final_0():
- def remove_va_file_naming_format(merge=True):
- if merge:
- _s["file_naming_format"] = (
- "$if($eq(%%compilation%%,1),\n$noop(Various Artist "
- "albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
- _s["va_file_naming_format"].toString(),
- _s["file_naming_format"]
- ))
- _s.remove("va_file_naming_format")
- _s.remove("use_va_format")
- if ("va_file_naming_format" in _s and
- "use_va_format" in _s):
+# In version 1.0, the file naming formats for single and various
+# artist releases were merged.
+def upgrade_to_v1_0_0_final_0():
+ def remove_va_file_naming_format(merge=True):
+ if merge:
+ _s["file_naming_format"] = (
+ "$if($eq(%%compilation%%,1),\n$noop(Various Artist "
+ "albums)\n%s,\n$noop(Single Artist Albums)\n%s)" % (
+ _s["va_file_naming_format"].toString(),
+ _s["file_naming_format"]
+ ))
+ _s.remove("va_file_naming_format")
+ _s.remove("use_va_format")
- msgbox = QtGui.QMessageBox()
- if _s["use_va_format"].toBool():
- remove_va_file_naming_format()
- msgbox.information(msgbox,
- _("Various Artists file naming scheme removal"),
- _("The separate file naming scheme for various artists "
- "albums has been removed in this version of Picard.\n"
- "Your file naming scheme has automatically been "
- "merged with that of single artist albums."),
- QtGui.QMessageBox.Ok)
+ if ("va_file_naming_format" in _s and
+ "use_va_format" in _s):
- elif (_s["va_file_naming_format"].toString() !=
- r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
- "cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
- "%title%"):
+ msgbox = QtGui.QMessageBox()
+ if _s["use_va_format"].toBool():
+ remove_va_file_naming_format()
+ msgbox.information(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "Your file naming scheme has automatically been "
+ "merged with that of single artist albums."),
+ QtGui.QMessageBox.Ok)
- answer = msgbox.question(msgbox,
- _("Various Artists file naming scheme removal"),
- _("The separate file naming scheme for various artists "
- "albums has been removed in this version of Picard.\n"
- "You currently do not use this option, but have a "
- "separate file naming scheme defined.\n"
- "Do you want to remove it or merge it with your file "
- "naming scheme for single artist albums?"),
- _("Merge"), _("Remove"))
+ elif (_s["va_file_naming_format"].toString() !=
+ r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldis"
+ "cs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - "
+ "%title%"):
- if answer:
- remove_va_file_naming_format(merge=False)
- else:
- remove_va_file_naming_format()
- else:
- # default format, disabled
+ answer = msgbox.question(msgbox,
+ _("Various Artists file naming scheme removal"),
+ _("The separate file naming scheme for various artists "
+ "albums has been removed in this version of Picard.\n"
+ "You currently do not use this option, but have a "
+ "separate file naming scheme defined.\n"
+ "Do you want to remove it or merge it with your file "
+ "naming scheme for single artist albums?"),
+ _("Merge"), _("Remove"))
+
+ if answer:
remove_va_file_naming_format(merge=False)
+ else:
+ remove_va_file_naming_format()
+ else:
+ # default format, disabled
+ remove_va_file_naming_format(merge=False)
- def upgrade_to_v1_3_0_dev_1():
- if "windows_compatible_filenames" in _s:
- _s["windows_compatibility"] = _s["windows_compatible_filenames"]
- _s.remove("windows_compatible_filenames")
- log.info('Config upgrade: option "windows_compatible_filenames" '
- ' was renamed "windows_compatibility" (PICARD-110).')
- def upgrade_to_v1_3_0_dev_2():
- if "preserved_tags" in _s:
- _s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
- log.info('Config upgrade: option "preserved_tags" is now using '
- 'comma instead of spaces as tag separator (PICARD-536).')
+def upgrade_to_v1_3_0_dev_1():
+ if "windows_compatible_filenames" in _s:
+ _s["windows_compatibility"] = _s["windows_compatible_filenames"]
+ _s.remove("windows_compatible_filenames")
+ log.info('Config upgrade: option "windows_compatible_filenames" '
+ ' was renamed "windows_compatibility" (PICARD-110).')
+
+def upgrade_to_v1_3_0_dev_2():
+ if "preserved_tags" in _s:
+ _s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
+ log.info('Config upgrade: option "preserved_tags" is now using '
+ 'comma instead of spaces as tag separator (PICARD-536).')
+
+
+def upgrade_config():
cfg = config._config
cfg.register_upgrade_hook(upgrade_to_v1_0_0_final_0)
cfg.register_upgrade_hook(upgrade_to_v1_3_0_dev_1)
From 708faa9ba48b0e0fd4436fcc0e44d746911e4cd2 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 14:23:34 +0100
Subject: [PATCH 45/59] _upgrade_hooks is now a dict, with version as key
---
picard/config.py | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index 5604ae582..7fce0bba5 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -85,7 +85,7 @@ class Config(QtCore.QSettings):
TextOption("application", "version", '0.0.0dev0')
self._version = version_from_string(self.application["version"])
- self._upgrade_hooks = []
+ self._upgrade_hooks = dict()
def switchProfile(self, profilename):
"""Sets the current profile."""
@@ -104,12 +104,11 @@ class Config(QtCore.QSettings):
to_version = version_from_string(match.group(1))
assert to_version <= PICARD_VERSION, "%r > %r !!!" % (to_version, PICARD_VERSION)
hook = {
- 'to': to_version,
'func': func,
'args': args,
'done': False
}
- self._upgrade_hooks.append(hook)
+ self._upgrade_hooks[to_version] = hook
def run_upgrade_hooks(self):
"""Executes registered functions to upgrade config version to the latest"""
@@ -123,10 +122,9 @@ class Config(QtCore.QSettings):
version_to_string(PICARD_VERSION)
))
return
- # sort upgrade hooks by version
- self._upgrade_hooks.sort(key=itemgetter("to"))
- for hook in self._upgrade_hooks:
- if self._version < hook['to']:
+ for version in sorted(self._upgrade_hooks):
+ hook = self._upgrade_hooks[version]
+ if self._version < version:
try:
hook['func'](*hook['args'])
except:
@@ -135,19 +133,19 @@ class Config(QtCore.QSettings):
"Error during config upgrade from version %s to %s "
"using %s():\n%s" % (
version_to_string(self._version),
- version_to_string(hook['to']),
+ version_to_string(version),
hook['func'].__name__,
traceback.format_exc()
))
else:
hook['done'] = True
- self._version = hook['to']
+ self._version = version
self._write_version()
else:
# hook is not applicable, mark as done
hook['done'] = True
- if all(map(itemgetter("done"), self._upgrade_hooks)):
+ if all(map(itemgetter("done"), self._upgrade_hooks.values())):
# all hooks were executed, ensure config is marked with latest version
self._version = PICARD_VERSION
self._write_version()
From 22271d880cf4d8d6e38bb8dbb063115213a304d3 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:09:28 +0100
Subject: [PATCH 46/59] Remove useless intermediate variable
---
picard/config.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index 7fce0bba5..efd31fcf4 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -103,12 +103,11 @@ class Config(QtCore.QSettings):
"have to match '%s' regex" % (func.__name__, pattern.pattern)
to_version = version_from_string(match.group(1))
assert to_version <= PICARD_VERSION, "%r > %r !!!" % (to_version, PICARD_VERSION)
- hook = {
+ self._upgrade_hooks[to_version] = {
'func': func,
'args': args,
'done': False
}
- self._upgrade_hooks[to_version] = hook
def run_upgrade_hooks(self):
"""Executes registered functions to upgrade config version to the latest"""
From 6e889ca0a06f6e1cca1284dcdcc5b6b15ea11a02 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:28:41 +0100
Subject: [PATCH 47/59] Use exceptions in place of assertions -> VersionError
---
picard/__init__.py | 19 +++++++++++++++----
test/test_versions.py | 10 ++++++----
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/picard/__init__.py b/picard/__init__.py
index eb5d67bba..954830c5f 100644
--- a/picard/__init__.py
+++ b/picard/__init__.py
@@ -25,9 +25,15 @@ PICARD_ORG_NAME = "MusicBrainz"
PICARD_VERSION = (1, 3, 0, 'dev', 2)
+class VersionError(Exception):
+ pass
+
+
def version_to_string(version, short=False):
- assert len(version) == 5
- assert version[3] in ('final', 'dev')
+ if len(version) != 5:
+ raise VersionError("Length != 5")
+ if version[3] not in ('final', 'dev'):
+ raise VersionError("Should be either 'final' or 'dev'")
_version = []
for p in version:
try:
@@ -47,9 +53,14 @@ def version_to_string(version, short=False):
return version_str
+_version_re = re.compile("^(\d+)[._](\d+)[._](\d+)[._]?(dev|final)[._]?(\d+)$")
def version_from_string(version_str):
- g = re.match(r"^(\d+)[._](\d+)[._](\d+)[._]?(dev|final)[._]?(\d+)$", version_str).groups()
- return (int(g[0]), int(g[1]), int(g[2]), g[3], int(g[4]))
+ m = _version_re.search(version_str)
+ if m:
+ g = m.groups()
+ return (int(g[0]), int(g[1]), int(g[2]), g[3], int(g[4]))
+ raise VersionError("String '%s' do not match regex '%s'" % (version_str,
+ _version_re.pattern))
__version__ = PICARD_VERSION_STR = version_to_string(PICARD_VERSION)
diff --git a/test/test_versions.py b/test/test_versions.py
index c99dca7e5..aad5b8e6f 100644
--- a/test/test_versions.py
+++ b/test/test_versions.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
import unittest
-from picard import version_to_string, version_from_string
+from picard import (version_to_string,
+ version_from_string,
+ VersionError)
class VersionsTest(unittest.TestCase):
@@ -23,8 +25,8 @@ class VersionsTest(unittest.TestCase):
def test_version_conv_4(self):
l, s = (1, 0, 2, '', 0), '1.0.2'
- self.assertRaises(AssertionError, version_to_string, (l))
- self.assertRaises(AttributeError, version_from_string, (s))
+ self.assertRaises(VersionError, version_to_string, (l))
+ self.assertRaises(VersionError, version_from_string, (s))
def test_version_conv_5(self):
l, s = (999, 999, 999, 'dev', 999), '999.999.999dev999'
@@ -33,7 +35,7 @@ class VersionsTest(unittest.TestCase):
def test_version_conv_6(self):
l = (1, 0, 2, 'xx', 0)
- self.assertRaises(AssertionError, version_to_string, (l))
+ self.assertRaises(VersionError, version_to_string, (l))
def test_version_conv_7(self):
l, s = (1, 1, 0, 'final', 0), '1.1'
From c2d53a4d4d1ea00138347b00bfa696d1ef32bc42 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:32:34 +0100
Subject: [PATCH 48/59] version_from_string(): match end of the string instead
full string
---
picard/__init__.py | 2 +-
test/test_versions.py | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/picard/__init__.py b/picard/__init__.py
index 954830c5f..d1d6cb897 100644
--- a/picard/__init__.py
+++ b/picard/__init__.py
@@ -53,7 +53,7 @@ def version_to_string(version, short=False):
return version_str
-_version_re = re.compile("^(\d+)[._](\d+)[._](\d+)[._]?(dev|final)[._]?(\d+)$")
+_version_re = re.compile("(\d+)[._](\d+)[._](\d+)[._]?(dev|final)[._]?(\d+)$")
def version_from_string(version_str):
m = _version_re.search(version_str)
if m:
diff --git a/test/test_versions.py b/test/test_versions.py
index aad5b8e6f..a473fb771 100644
--- a/test/test_versions.py
+++ b/test/test_versions.py
@@ -60,3 +60,11 @@ class VersionsTest(unittest.TestCase):
def test_version_conv_12(self):
l, s = (1, 1, 0, 'dev', 0), '1_1_0_dev_0'
self.assertEqual(l, version_from_string(s))
+
+ def test_version_conv_13(self):
+ l, s = (1, 1, 0, 'dev', 0), 'anything_28_1_1_0_dev_0'
+ self.assertEqual(l, version_from_string(s))
+
+ def test_version_conv_14(self):
+ l = 'anything_28x_1_0_dev_0'
+ self.assertRaises(VersionError, version_to_string, (l))
From d713d1cf005924d85cbe9356cd6f5512cea16b6a Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:36:29 +0100
Subject: [PATCH 49/59] Let version_from_string() raises an exception if hook
name is incorrect
---
picard/config.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/picard/config.py b/picard/config.py
index efd31fcf4..ed0923199 100644
--- a/picard/config.py
+++ b/picard/config.py
@@ -97,11 +97,7 @@ class Config(QtCore.QSettings):
def register_upgrade_hook(self, func, *args):
"""Register a function to upgrade from one config version to another"""
- pattern = re.compile("(\d+_\d+_\d+_(?:dev|final)_\d+)$")
- match = re.search(pattern, func.__name__)
- assert match, "config upgrade function name '%s' " \
- "have to match '%s' regex" % (func.__name__, pattern.pattern)
- to_version = version_from_string(match.group(1))
+ to_version = version_from_string(func.__name__)
assert to_version <= PICARD_VERSION, "%r > %r !!!" % (to_version, PICARD_VERSION)
self._upgrade_hooks[to_version] = {
'func': func,
From 861ed91800f948867b77704f58b1bde69c89e589 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:47:02 +0100
Subject: [PATCH 50/59] Mark messages for translation.
---
picard/config_upgrade.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index fa66ec20f..3aff6a9c6 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -90,15 +90,15 @@ def upgrade_to_v1_3_0_dev_1():
if "windows_compatible_filenames" in _s:
_s["windows_compatibility"] = _s["windows_compatible_filenames"]
_s.remove("windows_compatible_filenames")
- log.info('Config upgrade: option "windows_compatible_filenames" '
- ' was renamed "windows_compatibility" (PICARD-110).')
+ log.info(_('Config upgrade: option "windows_compatible_filenames" '
+ ' was renamed "windows_compatibility" (PICARD-110).'))
def upgrade_to_v1_3_0_dev_2():
if "preserved_tags" in _s:
_s["preserved_tags"] = re.sub(r"\s+", ",", _s["preserved_tags"].strip())
- log.info('Config upgrade: option "preserved_tags" is now using '
- 'comma instead of spaces as tag separator (PICARD-536).')
+ log.info(_('Config upgrade: option "preserved_tags" is now using '
+ 'comma instead of spaces as tag separator (PICARD-536).'))
def upgrade_config():
From 1de7f3fa550d7a73f33507a1eb85bedd35639fdd Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 17:50:31 +0100
Subject: [PATCH 51/59] Update comment
---
picard/config_upgrade.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index 3aff6a9c6..702936e16 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -28,6 +28,7 @@ from picard import (log, config)
# ----------------------
# add a function here, named after the version you want upgrade to
# ie. upgrade_to_v1_0_0_dev_1() for 1.0.0dev1
+# register it in upgrade_config()
# and modify PICARD_VERSION to match it
#
From 45b9619b4c9b60df8a0d71d1f29daca69af9b9d8 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 2 Jan 2014 18:11:52 +0100
Subject: [PATCH 52/59] Regenerate picard.pot
---
po/picard.pot | 981 ++++++++++++++++++++++++++------------------------
1 file changed, 502 insertions(+), 479 deletions(-)
diff --git a/po/picard.pot b/po/picard.pot
index 211e2ee3f..e5ea78f78 100644
--- a/po/picard.pot
+++ b/po/picard.pot
@@ -1,14 +1,14 @@
# Translations template for PROJECT.
-# Copyright (C) 2013 ORGANIZATION
+# Copyright (C) 2014 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
-# FIRST AUTHOR , 2013.
+# FIRST AUTHOR , 2014.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2013-11-26 22:35+0100\n"
+"POT-Creation-Date: 2014-01-02 18:11+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -150,42 +150,42 @@ msgstr ""
msgid "AcoustIDs successfully submitted!"
msgstr ""
-#: picard/album.py:64 picard/cluster.py:235
+#: picard/album.py:64 picard/cluster.py:234
msgid "Unmatched Files"
msgstr ""
-#: picard/album.py:181
+#: picard/album.py:187
#, python-format
msgid "[could not load album %s]"
msgstr ""
-#: picard/album.py:267
+#: picard/album.py:272
#, python-format
msgid "Album %s loaded"
msgstr ""
-#: picard/album.py:283
+#: picard/album.py:288
msgid "[loading album information]"
msgstr ""
-#: picard/album.py:455
+#: picard/album.py:460
#, python-format
msgid "; %i image"
msgid_plural "; %i images"
msgstr[0] ""
msgstr[1] ""
-#: picard/cluster.py:151 picard/cluster.py:160
+#: picard/cluster.py:150 picard/cluster.py:159
#, python-format
msgid "No matching releases for cluster %s"
msgstr ""
-#: picard/cluster.py:162
+#: picard/cluster.py:161
#, python-format
msgid "Cluster %s identified!"
msgstr ""
-#: picard/cluster.py:169
+#: picard/cluster.py:168
#, python-format
msgid "Looking up the metadata for cluster %s..."
msgstr ""
@@ -209,1193 +209,1235 @@ msgstr[1] ""
msgid "Error loading collections: %s"
msgstr ""
-#: picard/const.py:55
-msgid "CD"
+#: picard/config_upgrade.py:59 picard/config_upgrade.py:72
+msgid "Various Artists file naming scheme removal"
msgstr ""
-#: picard/const.py:56
-msgid "CD-R"
+#: picard/config_upgrade.py:60
+msgid ""
+"The separate file naming scheme for various artists albums has been "
+"removed in this version of Picard.\n"
+"Your file naming scheme has automatically been merged with that of single"
+" artist albums."
msgstr ""
-#: picard/const.py:57
-msgid "HDCD"
+#: picard/config_upgrade.py:73
+msgid ""
+"The separate file naming scheme for various artists albums has been "
+"removed in this version of Picard.\n"
+"You currently do not use this option, but have a separate file naming "
+"scheme defined.\n"
+"Do you want to remove it or merge it with your file naming scheme for "
+"single artist albums?"
msgstr ""
-#: picard/const.py:58
-msgid "8cm CD"
+#: picard/config_upgrade.py:79
+msgid "Merge"
msgstr ""
-#: picard/const.py:59
-msgid "Vinyl"
+#: picard/config_upgrade.py:79 picard/ui/metadatabox.py:254
+msgid "Remove"
msgstr ""
-#: picard/const.py:60
-msgid "7\" Vinyl"
+#: picard/config_upgrade.py:94
+msgid ""
+"Config upgrade: option \"windows_compatible_filenames\" was renamed "
+"\"windows_compatibility\" (PICARD-110)."
msgstr ""
-#: picard/const.py:61
-msgid "10\" Vinyl"
-msgstr ""
-
-#: picard/const.py:62
-msgid "12\" Vinyl"
-msgstr ""
-
-#: picard/const.py:63
-msgid "Digital Media"
-msgstr ""
-
-#: picard/const.py:64
-msgid "USB Flash Drive"
-msgstr ""
-
-#: picard/const.py:65
-msgid "slotMusic"
-msgstr ""
-
-#: picard/const.py:66
-msgid "Cassette"
+#: picard/config_upgrade.py:101
+msgid ""
+"Config upgrade: option \"preserved_tags\" is now using comma instead of "
+"spaces as tag separator (PICARD-536)."
msgstr ""
#: picard/const.py:67
-msgid "DVD"
+msgid "CD"
msgstr ""
#: picard/const.py:68
-msgid "DVD-Audio"
+msgid "CD-R"
msgstr ""
#: picard/const.py:69
-msgid "DVD-Video"
+msgid "HDCD"
msgstr ""
#: picard/const.py:70
-msgid "SACD"
+msgid "8cm CD"
msgstr ""
#: picard/const.py:71
-msgid "DualDisc"
+msgid "Vinyl"
msgstr ""
#: picard/const.py:72
-msgid "MiniDisc"
+msgid "7\" Vinyl"
msgstr ""
#: picard/const.py:73
-msgid "Blu-ray"
+msgid "10\" Vinyl"
msgstr ""
#: picard/const.py:74
-msgid "HD-DVD"
+msgid "12\" Vinyl"
msgstr ""
#: picard/const.py:75
-msgid "Videotape"
+msgid "Digital Media"
msgstr ""
#: picard/const.py:76
-msgid "VHS"
+msgid "USB Flash Drive"
msgstr ""
#: picard/const.py:77
-msgid "Betamax"
+msgid "slotMusic"
msgstr ""
#: picard/const.py:78
-msgid "VCD"
+msgid "Cassette"
msgstr ""
#: picard/const.py:79
-msgid "SVCD"
+msgid "DVD"
msgstr ""
#: picard/const.py:80
+msgid "DVD-Audio"
+msgstr ""
+
+#: picard/const.py:81
+msgid "DVD-Video"
+msgstr ""
+
+#: picard/const.py:82
+msgid "SACD"
+msgstr ""
+
+#: picard/const.py:83
+msgid "DualDisc"
+msgstr ""
+
+#: picard/const.py:84
+msgid "MiniDisc"
+msgstr ""
+
+#: picard/const.py:85
+msgid "Blu-ray"
+msgstr ""
+
+#: picard/const.py:86
+msgid "HD-DVD"
+msgstr ""
+
+#: picard/const.py:87
+msgid "Videotape"
+msgstr ""
+
+#: picard/const.py:88
+msgid "VHS"
+msgstr ""
+
+#: picard/const.py:89
+msgid "Betamax"
+msgstr ""
+
+#: picard/const.py:90
+msgid "VCD"
+msgstr ""
+
+#: picard/const.py:91
+msgid "SVCD"
+msgstr ""
+
+#: picard/const.py:92
msgid "UMD"
msgstr ""
-#: picard/const.py:81 picard/coverartarchive.py:33
+#: picard/const.py:93 picard/coverartarchive.py:33
#: picard/ui/ui_options_releases.py:226
msgid "Other"
msgstr ""
-#: picard/const.py:82
+#: picard/const.py:94
msgid "LaserDisc"
msgstr ""
-#: picard/const.py:83
+#: picard/const.py:95
msgid "Cartridge"
msgstr ""
-#: picard/const.py:84
+#: picard/const.py:96
msgid "Reel-to-reel"
msgstr ""
-#: picard/const.py:85
+#: picard/const.py:97
msgid "DAT"
msgstr ""
-#: picard/const.py:86
+#: picard/const.py:98
msgid "Wax Cylinder"
msgstr ""
-#: picard/const.py:87
+#: picard/const.py:99
msgid "Piano Roll"
msgstr ""
-#: picard/const.py:88
+#: picard/const.py:100
msgid "DCC"
msgstr ""
-#: picard/const.py:93
+#: picard/const.py:105
msgid "Bangladesh"
msgstr ""
-#: picard/const.py:94
+#: picard/const.py:106
msgid "Belgium"
msgstr ""
-#: picard/const.py:95
+#: picard/const.py:107
msgid "Burkina Faso"
msgstr ""
-#: picard/const.py:96
+#: picard/const.py:108
msgid "Bulgaria"
msgstr ""
-#: picard/const.py:97
+#: picard/const.py:109
msgid "Barbados"
msgstr ""
-#: picard/const.py:98
+#: picard/const.py:110
msgid "Wallis and Futuna Islands"
msgstr ""
-#: picard/const.py:99
+#: picard/const.py:111
msgid "Bermuda"
msgstr ""
-#: picard/const.py:100
+#: picard/const.py:112
msgid "Brunei Darussalam"
msgstr ""
-#: picard/const.py:101
+#: picard/const.py:113
msgid "Bolivia"
msgstr ""
-#: picard/const.py:102
+#: picard/const.py:114
msgid "Bahrain"
msgstr ""
-#: picard/const.py:103
+#: picard/const.py:115
msgid "Burundi"
msgstr ""
-#: picard/const.py:104
+#: picard/const.py:116
msgid "Benin"
msgstr ""
-#: picard/const.py:105
+#: picard/const.py:117
msgid "Bhutan"
msgstr ""
-#: picard/const.py:106
+#: picard/const.py:118
msgid "Jamaica"
msgstr ""
-#: picard/const.py:107
+#: picard/const.py:119
msgid "Bouvet Island"
msgstr ""
-#: picard/const.py:108
+#: picard/const.py:120
msgid "Botswana"
msgstr ""
-#: picard/const.py:109
+#: picard/const.py:121
msgid "Samoa"
msgstr ""
-#: picard/const.py:110
+#: picard/const.py:122
msgid "Brazil"
msgstr ""
-#: picard/const.py:111
+#: picard/const.py:123
msgid "Bahamas"
msgstr ""
-#: picard/const.py:112
+#: picard/const.py:124
msgid "Belarus"
msgstr ""
-#: picard/const.py:113
+#: picard/const.py:125
msgid "Belize"
msgstr ""
-#: picard/const.py:114
+#: picard/const.py:126
msgid "Russian Federation"
msgstr ""
-#: picard/const.py:115
+#: picard/const.py:127
msgid "Rwanda"
msgstr ""
-#: picard/const.py:116
+#: picard/const.py:128
msgid "Reunion"
msgstr ""
-#: picard/const.py:117
+#: picard/const.py:129
msgid "Turkmenistan"
msgstr ""
-#: picard/const.py:118
+#: picard/const.py:130
msgid "Tajikistan"
msgstr ""
-#: picard/const.py:119
+#: picard/const.py:131
msgid "Romania"
msgstr ""
-#: picard/const.py:120
+#: picard/const.py:132
msgid "Tokelau"
msgstr ""
-#: picard/const.py:121
+#: picard/const.py:133
msgid "Guinea-Bissa"
msgstr ""
-#: picard/const.py:122
+#: picard/const.py:134
msgid "Guam"
msgstr ""
-#: picard/const.py:123
+#: picard/const.py:135
msgid "Guatemala"
msgstr ""
-#: picard/const.py:124
+#: picard/const.py:136
msgid "Greece"
msgstr ""
-#: picard/const.py:125
+#: picard/const.py:137
msgid "Equatorial Guinea"
msgstr ""
-#: picard/const.py:126
+#: picard/const.py:138
msgid "Guadeloupe"
msgstr ""
-#: picard/const.py:127
+#: picard/const.py:139
msgid "Japan"
msgstr ""
-#: picard/const.py:128
+#: picard/const.py:140
msgid "Guyana"
msgstr ""
-#: picard/const.py:129
+#: picard/const.py:141
msgid "French Guiana"
msgstr ""
-#: picard/const.py:130
+#: picard/const.py:142
msgid "Georgia"
msgstr ""
-#: picard/const.py:131
+#: picard/const.py:143
msgid "Grenada"
msgstr ""
-#: picard/const.py:132
+#: picard/const.py:144
msgid "United Kingdom"
msgstr ""
-#: picard/const.py:133
+#: picard/const.py:145
msgid "Gabon"
msgstr ""
-#: picard/const.py:134
+#: picard/const.py:146
msgid "El Salvador"
msgstr ""
-#: picard/const.py:135
+#: picard/const.py:147
msgid "Guinea"
msgstr ""
-#: picard/const.py:136
+#: picard/const.py:148
msgid "Gambia"
msgstr ""
-#: picard/const.py:137
+#: picard/const.py:149
msgid "Greenland"
msgstr ""
-#: picard/const.py:138
+#: picard/const.py:150
msgid "Gibraltar"
msgstr ""
-#: picard/const.py:139
+#: picard/const.py:151
msgid "Ghana"
msgstr ""
-#: picard/const.py:140
+#: picard/const.py:152
msgid "Oman"
msgstr ""
-#: picard/const.py:141
+#: picard/const.py:153
msgid "Tunisia"
msgstr ""
-#: picard/const.py:142
+#: picard/const.py:154
msgid "Jordan"
msgstr ""
-#: picard/const.py:143
+#: picard/const.py:155
msgid "Haiti"
msgstr ""
-#: picard/const.py:144
+#: picard/const.py:156
msgid "Hungary"
msgstr ""
-#: picard/const.py:145
+#: picard/const.py:157
msgid "Hong Kong"
msgstr ""
-#: picard/const.py:146
+#: picard/const.py:158
msgid "Honduras"
msgstr ""
-#: picard/const.py:147
+#: picard/const.py:159
msgid "Heard and Mc Donald Islands"
msgstr ""
-#: picard/const.py:148
+#: picard/const.py:160
msgid "Venezuela"
msgstr ""
-#: picard/const.py:149
+#: picard/const.py:161
msgid "Puerto Rico"
msgstr ""
-#: picard/const.py:150
+#: picard/const.py:162
msgid "Palau"
msgstr ""
-#: picard/const.py:151
+#: picard/const.py:163
msgid "Portugal"
msgstr ""
-#: picard/const.py:152
+#: picard/const.py:164
msgid "Svalbard and Jan Mayen Islands"
msgstr ""
-#: picard/const.py:153
+#: picard/const.py:165
msgid "Paraguay"
msgstr ""
-#: picard/const.py:154
+#: picard/const.py:166
msgid "Iraq"
msgstr ""
-#: picard/const.py:155
+#: picard/const.py:167
msgid "Panama"
msgstr ""
-#: picard/const.py:156
+#: picard/const.py:168
msgid "French Polynesia"
msgstr ""
-#: picard/const.py:157
+#: picard/const.py:169
msgid "Papua New Guinea"
msgstr ""
-#: picard/const.py:158
+#: picard/const.py:170
msgid "Peru"
msgstr ""
-#: picard/const.py:159
+#: picard/const.py:171
msgid "Pakistan"
msgstr ""
-#: picard/const.py:160
+#: picard/const.py:172
msgid "Philippines"
msgstr ""
-#: picard/const.py:161
+#: picard/const.py:173
msgid "Pitcairn"
msgstr ""
-#: picard/const.py:162
+#: picard/const.py:174
msgid "Poland"
msgstr ""
-#: picard/const.py:163
+#: picard/const.py:175
msgid "St. Pierre and Miquelon"
msgstr ""
-#: picard/const.py:164
+#: picard/const.py:176
msgid "Zambia"
msgstr ""
-#: picard/const.py:165
+#: picard/const.py:177
msgid "Western Sahara"
msgstr ""
-#: picard/const.py:166
+#: picard/const.py:178
msgid "Estonia"
msgstr ""
-#: picard/const.py:167
+#: picard/const.py:179
msgid "Egypt"
msgstr ""
-#: picard/const.py:168
+#: picard/const.py:180
msgid "South Africa"
msgstr ""
-#: picard/const.py:169
+#: picard/const.py:181
msgid "Ecuador"
msgstr ""
-#: picard/const.py:170
+#: picard/const.py:182
msgid "Italy"
msgstr ""
-#: picard/const.py:171
+#: picard/const.py:183
msgid "Viet Nam"
msgstr ""
-#: picard/const.py:172
+#: picard/const.py:184
msgid "Solomon Islands"
msgstr ""
-#: picard/const.py:173
+#: picard/const.py:185
msgid "Ethiopia"
msgstr ""
-#: picard/const.py:174
+#: picard/const.py:186
msgid "Somalia"
msgstr ""
-#: picard/const.py:175
+#: picard/const.py:187
msgid "Zimbabwe"
msgstr ""
-#: picard/const.py:176
+#: picard/const.py:188
msgid "Saudi Arabia"
msgstr ""
-#: picard/const.py:177
+#: picard/const.py:189
msgid "Spain"
msgstr ""
-#: picard/const.py:178
+#: picard/const.py:190
msgid "Eritrea"
msgstr ""
-#: picard/const.py:179
+#: picard/const.py:191
msgid "Moldova, Republic of"
msgstr ""
-#: picard/const.py:180
+#: picard/const.py:192
msgid "Madagascar"
msgstr ""
-#: picard/const.py:181
+#: picard/const.py:193
msgid "Morocco"
msgstr ""
-#: picard/const.py:182
+#: picard/const.py:194
msgid "Monaco"
msgstr ""
-#: picard/const.py:183
+#: picard/const.py:195
msgid "Uzbekistan"
msgstr ""
-#: picard/const.py:184
+#: picard/const.py:196
msgid "Myanmar"
msgstr ""
-#: picard/const.py:185
+#: picard/const.py:197
msgid "Mali"
msgstr ""
-#: picard/const.py:186
+#: picard/const.py:198
msgid "Macau"
msgstr ""
-#: picard/const.py:187
+#: picard/const.py:199
msgid "Mongolia"
msgstr ""
-#: picard/const.py:188
+#: picard/const.py:200
msgid "Marshall Islands"
msgstr ""
-#: picard/const.py:189
+#: picard/const.py:201
msgid "Macedonia, The Former Yugoslav Republic of"
msgstr ""
-#: picard/const.py:190
+#: picard/const.py:202
msgid "Mauritius"
msgstr ""
-#: picard/const.py:191
+#: picard/const.py:203
msgid "Malta"
msgstr ""
-#: picard/const.py:192
+#: picard/const.py:204
msgid "Malawi"
msgstr ""
-#: picard/const.py:193
+#: picard/const.py:205
msgid "Maldives"
msgstr ""
-#: picard/const.py:194
+#: picard/const.py:206
msgid "Martinique"
msgstr ""
-#: picard/const.py:195
+#: picard/const.py:207
msgid "Northern Mariana Islands"
msgstr ""
-#: picard/const.py:196
+#: picard/const.py:208
msgid "Montserrat"
msgstr ""
-#: picard/const.py:197
+#: picard/const.py:209
msgid "Mauritania"
msgstr ""
-#: picard/const.py:198
+#: picard/const.py:210
msgid "Uganda"
msgstr ""
-#: picard/const.py:199
+#: picard/const.py:211
msgid "Malaysia"
msgstr ""
-#: picard/const.py:200
+#: picard/const.py:212
msgid "Mexico"
msgstr ""
-#: picard/const.py:201
+#: picard/const.py:213
msgid "Israel"
msgstr ""
-#: picard/const.py:202
+#: picard/const.py:214
msgid "France"
msgstr ""
-#: picard/const.py:203
+#: picard/const.py:215
msgid "British Indian Ocean Territory"
msgstr ""
-#: picard/const.py:204
+#: picard/const.py:216
msgid "St. Helena"
msgstr ""
-#: picard/const.py:205
+#: picard/const.py:217
msgid "Finland"
msgstr ""
-#: picard/const.py:206
+#: picard/const.py:218
msgid "Fiji"
msgstr ""
-#: picard/const.py:207
+#: picard/const.py:219
msgid "Falkland Islands (Malvinas)"
msgstr ""
-#: picard/const.py:208
+#: picard/const.py:220
msgid "Micronesia, Federated States of"
msgstr ""
-#: picard/const.py:209
+#: picard/const.py:221
msgid "Faroe Islands"
msgstr ""
-#: picard/const.py:210
+#: picard/const.py:222
msgid "Nicaragua"
msgstr ""
-#: picard/const.py:211
+#: picard/const.py:223
msgid "Netherlands"
msgstr ""
-#: picard/const.py:212
+#: picard/const.py:224
msgid "Norway"
msgstr ""
-#: picard/const.py:213
+#: picard/const.py:225
msgid "Namibia"
msgstr ""
-#: picard/const.py:214
+#: picard/const.py:226
msgid "Vanuatu"
msgstr ""
-#: picard/const.py:215
+#: picard/const.py:227
msgid "New Caledonia"
msgstr ""
-#: picard/const.py:216
+#: picard/const.py:228
msgid "Niger"
msgstr ""
-#: picard/const.py:217
+#: picard/const.py:229
msgid "Norfolk Island"
msgstr ""
-#: picard/const.py:218
+#: picard/const.py:230
msgid "Nigeria"
msgstr ""
-#: picard/const.py:219
+#: picard/const.py:231
msgid "New Zealand"
msgstr ""
-#: picard/const.py:220
+#: picard/const.py:232
msgid "Zaire"
msgstr ""
-#: picard/const.py:221
+#: picard/const.py:233
msgid "Nepal"
msgstr ""
-#: picard/const.py:222
+#: picard/const.py:234
msgid "Nauru"
msgstr ""
-#: picard/const.py:223
+#: picard/const.py:235
msgid "Niue"
msgstr ""
-#: picard/const.py:224
+#: picard/const.py:236
msgid "Cook Islands"
msgstr ""
-#: picard/const.py:225
+#: picard/const.py:237
msgid "Cote d'Ivoire"
msgstr ""
-#: picard/const.py:226
+#: picard/const.py:238
msgid "Switzerland"
msgstr ""
-#: picard/const.py:227
+#: picard/const.py:239
msgid "Colombia"
msgstr ""
-#: picard/const.py:228
+#: picard/const.py:240
msgid "China"
msgstr ""
-#: picard/const.py:229
+#: picard/const.py:241
msgid "Cameroon"
msgstr ""
-#: picard/const.py:230
+#: picard/const.py:242
msgid "Chile"
msgstr ""
-#: picard/const.py:231
+#: picard/const.py:243
msgid "Cocos (Keeling) Islands"
msgstr ""
-#: picard/const.py:232
+#: picard/const.py:244
msgid "Canada"
msgstr ""
-#: picard/const.py:233
+#: picard/const.py:245
msgid "Congo"
msgstr ""
-#: picard/const.py:234
+#: picard/const.py:246
msgid "Central African Republic"
msgstr ""
-#: picard/const.py:235
+#: picard/const.py:247
msgid "Czech Republic"
msgstr ""
-#: picard/const.py:236
+#: picard/const.py:248
msgid "Cyprus"
msgstr ""
-#: picard/const.py:237
+#: picard/const.py:249
msgid "Christmas Island"
msgstr ""
-#: picard/const.py:238
+#: picard/const.py:250
msgid "Costa Rica"
msgstr ""
-#: picard/const.py:239
+#: picard/const.py:251
msgid "Cape Verde"
msgstr ""
-#: picard/const.py:240
+#: picard/const.py:252
msgid "Cuba"
msgstr ""
-#: picard/const.py:241
+#: picard/const.py:253
msgid "Swaziland"
msgstr ""
-#: picard/const.py:242
+#: picard/const.py:254
msgid "Syrian Arab Republic"
msgstr ""
-#: picard/const.py:243
+#: picard/const.py:255
msgid "Kyrgyzstan"
msgstr ""
-#: picard/const.py:244
+#: picard/const.py:256
msgid "Kenya"
msgstr ""
-#: picard/const.py:245
+#: picard/const.py:257
msgid "Suriname"
msgstr ""
-#: picard/const.py:246
+#: picard/const.py:258
msgid "Kiribati"
msgstr ""
-#: picard/const.py:247
+#: picard/const.py:259
msgid "Cambodia"
msgstr ""
-#: picard/const.py:248
+#: picard/const.py:260
msgid "Saint Kitts and Nevis"
msgstr ""
-#: picard/const.py:249
+#: picard/const.py:261
msgid "Comoros"
msgstr ""
-#: picard/const.py:250
+#: picard/const.py:262
msgid "Sao Tome and Principe"
msgstr ""
-#: picard/const.py:251
+#: picard/const.py:263
msgid "Slovenia"
msgstr ""
-#: picard/const.py:252
+#: picard/const.py:264
msgid "Kuwait"
msgstr ""
-#: picard/const.py:253
+#: picard/const.py:265
msgid "Senegal"
msgstr ""
-#: picard/const.py:254
+#: picard/const.py:266
msgid "San Marino"
msgstr ""
-#: picard/const.py:255
+#: picard/const.py:267
msgid "Sierra Leone"
msgstr ""
-#: picard/const.py:256
+#: picard/const.py:268
msgid "Seychelles"
msgstr ""
-#: picard/const.py:257
+#: picard/const.py:269
msgid "Kazakhstan"
msgstr ""
-#: picard/const.py:258
+#: picard/const.py:270
msgid "Cayman Islands"
msgstr ""
-#: picard/const.py:259
+#: picard/const.py:271
msgid "Singapore"
msgstr ""
-#: picard/const.py:260
+#: picard/const.py:272
msgid "Sweden"
msgstr ""
-#: picard/const.py:261
+#: picard/const.py:273
msgid "Sudan"
msgstr ""
-#: picard/const.py:262
+#: picard/const.py:274
msgid "Dominican Republic"
msgstr ""
-#: picard/const.py:263
+#: picard/const.py:275
msgid "Dominica"
msgstr ""
-#: picard/const.py:264
+#: picard/const.py:276
msgid "Djibouti"
msgstr ""
-#: picard/const.py:265
+#: picard/const.py:277
msgid "Denmark"
msgstr ""
-#: picard/const.py:266
+#: picard/const.py:278
msgid "Virgin Islands (British)"
msgstr ""
-#: picard/const.py:267
+#: picard/const.py:279
msgid "Germany"
msgstr ""
-#: picard/const.py:268
+#: picard/const.py:280
msgid "Yemen"
msgstr ""
-#: picard/const.py:269
+#: picard/const.py:281
msgid "Algeria"
msgstr ""
-#: picard/const.py:270
+#: picard/const.py:282
msgid "United States"
msgstr ""
-#: picard/const.py:271
+#: picard/const.py:283
msgid "Uruguay"
msgstr ""
-#: picard/const.py:272
+#: picard/const.py:284
msgid "Mayotte"
msgstr ""
-#: picard/const.py:273
+#: picard/const.py:285
msgid "United States Minor Outlying Islands"
msgstr ""
-#: picard/const.py:274
+#: picard/const.py:286
msgid "Lebanon"
msgstr ""
-#: picard/const.py:275
+#: picard/const.py:287
msgid "Saint Lucia"
msgstr ""
-#: picard/const.py:276
+#: picard/const.py:288
msgid "Lao People's Democratic Republic"
msgstr ""
-#: picard/const.py:277
+#: picard/const.py:289
msgid "Tuvalu"
msgstr ""
-#: picard/const.py:278
+#: picard/const.py:290
msgid "Taiwan"
msgstr ""
-#: picard/const.py:279
+#: picard/const.py:291
msgid "Trinidad and Tobago"
msgstr ""
-#: picard/const.py:280
+#: picard/const.py:292
msgid "Turkey"
msgstr ""
-#: picard/const.py:281
+#: picard/const.py:293
msgid "Sri Lanka"
msgstr ""
-#: picard/const.py:282
+#: picard/const.py:294
msgid "Liechtenstein"
msgstr ""
-#: picard/const.py:283
+#: picard/const.py:295
msgid "Latvia"
msgstr ""
-#: picard/const.py:284
+#: picard/const.py:296
msgid "Tonga"
msgstr ""
-#: picard/const.py:285
+#: picard/const.py:297
msgid "Lithuania"
msgstr ""
-#: picard/const.py:286
+#: picard/const.py:298
msgid "Luxembourg"
msgstr ""
-#: picard/const.py:287
+#: picard/const.py:299
msgid "Liberia"
msgstr ""
-#: picard/const.py:288
+#: picard/const.py:300
msgid "Lesotho"
msgstr ""
-#: picard/const.py:289
+#: picard/const.py:301
msgid "Thailand"
msgstr ""
-#: picard/const.py:290
+#: picard/const.py:302
msgid "French Southern Territories"
msgstr ""
-#: picard/const.py:291
+#: picard/const.py:303
msgid "Togo"
msgstr ""
-#: picard/const.py:292
+#: picard/const.py:304
msgid "Chad"
msgstr ""
-#: picard/const.py:293
+#: picard/const.py:305
msgid "Turks and Caicos Islands"
msgstr ""
-#: picard/const.py:294
+#: picard/const.py:306
msgid "Libyan Arab Jamahiriya"
msgstr ""
-#: picard/const.py:295
+#: picard/const.py:307
msgid "Vatican City State (Holy See)"
msgstr ""
-#: picard/const.py:296
+#: picard/const.py:308
msgid "Saint Vincent and The Grenadines"
msgstr ""
-#: picard/const.py:297
+#: picard/const.py:309
msgid "United Arab Emirates"
msgstr ""
-#: picard/const.py:298
+#: picard/const.py:310
msgid "Andorra"
msgstr ""
-#: picard/const.py:299
+#: picard/const.py:311
msgid "Antigua and Barbuda"
msgstr ""
-#: picard/const.py:300
+#: picard/const.py:312
msgid "Afghanistan"
msgstr ""
-#: picard/const.py:301
+#: picard/const.py:313
msgid "Anguilla"
msgstr ""
-#: picard/const.py:302
+#: picard/const.py:314
msgid "Virgin Islands (U.S.)"
msgstr ""
-#: picard/const.py:303
+#: picard/const.py:315
msgid "Iceland"
msgstr ""
-#: picard/const.py:304
+#: picard/const.py:316
msgid "Iran (Islamic Republic of)"
msgstr ""
-#: picard/const.py:305
+#: picard/const.py:317
msgid "Armenia"
msgstr ""
-#: picard/const.py:306
+#: picard/const.py:318
msgid "Albania"
msgstr ""
-#: picard/const.py:307
+#: picard/const.py:319
msgid "Angola"
msgstr ""
-#: picard/const.py:308
+#: picard/const.py:320
msgid "Netherlands Antilles"
msgstr ""
-#: picard/const.py:309
+#: picard/const.py:321
msgid "Antarctica"
msgstr ""
-#: picard/const.py:310
+#: picard/const.py:322
msgid "American Samoa"
msgstr ""
-#: picard/const.py:311
+#: picard/const.py:323
msgid "Argentina"
msgstr ""
-#: picard/const.py:312
+#: picard/const.py:324
msgid "Australia"
msgstr ""
-#: picard/const.py:313
+#: picard/const.py:325
msgid "Austria"
msgstr ""
-#: picard/const.py:314
+#: picard/const.py:326
msgid "Aruba"
msgstr ""
-#: picard/const.py:315
+#: picard/const.py:327
msgid "India"
msgstr ""
-#: picard/const.py:316
+#: picard/const.py:328
msgid "Tanzania, United Republic of"
msgstr ""
-#: picard/const.py:317
+#: picard/const.py:329
msgid "Azerbaijan"
msgstr ""
-#: picard/const.py:318
+#: picard/const.py:330
msgid "Ireland"
msgstr ""
-#: picard/const.py:319
+#: picard/const.py:331
msgid "Indonesia"
msgstr ""
-#: picard/const.py:320
+#: picard/const.py:332
msgid "Ukraine"
msgstr ""
-#: picard/const.py:321
+#: picard/const.py:333
msgid "Qatar"
msgstr ""
-#: picard/const.py:322
+#: picard/const.py:334
msgid "Mozambique"
msgstr ""
-#: picard/const.py:323
+#: picard/const.py:335
msgid "Bosnia and Herzegovina"
msgstr ""
-#: picard/const.py:324
+#: picard/const.py:336
msgid "Congo, The Democratic Republic of the"
msgstr ""
-#: picard/const.py:325
+#: picard/const.py:337
msgid "Serbia and Montenegro (historical, 2003-2006)"
msgstr ""
-#: picard/const.py:326
+#: picard/const.py:338
msgid "Serbia"
msgstr ""
-#: picard/const.py:327
+#: picard/const.py:339
msgid "Montenegro"
msgstr ""
-#: picard/const.py:328
+#: picard/const.py:340
msgid "Croatia"
msgstr ""
-#: picard/const.py:329
+#: picard/const.py:341
msgid "Korea (North), Democratic People's Republic of"
msgstr ""
-#: picard/const.py:330
+#: picard/const.py:342
msgid "Korea (South), Republic of"
msgstr ""
-#: picard/const.py:331
+#: picard/const.py:343
msgid "Slovakia"
msgstr ""
-#: picard/const.py:332
+#: picard/const.py:344
msgid "Soviet Union (historical, 1922-1991)"
msgstr ""
-#: picard/const.py:333
+#: picard/const.py:345
msgid "East Timor"
msgstr ""
-#: picard/const.py:334
+#: picard/const.py:346
msgid "Czechoslovakia (historical, 1918-1992)"
msgstr ""
-#: picard/const.py:335
+#: picard/const.py:347
msgid "Europe"
msgstr ""
-#: picard/const.py:336
+#: picard/const.py:348
msgid "East Germany (historical, 1949-1990)"
msgstr ""
-#: picard/const.py:337
+#: picard/const.py:349
msgid "[Unknown Country]"
msgstr ""
-#: picard/const.py:338
+#: picard/const.py:350
msgid "[Worldwide]"
msgstr ""
-#: picard/const.py:339
+#: picard/const.py:351
msgid "Yugoslavia (historical, 1918-1992)"
msgstr ""
-#: picard/const.py:351
+#: picard/const.py:363
msgid "Danish"
msgstr ""
-#: picard/const.py:352
+#: picard/const.py:364
msgid "German"
msgstr ""
-#: picard/const.py:354
+#: picard/const.py:366
msgid "English"
msgstr ""
-#: picard/const.py:355
+#: picard/const.py:367
msgid "English (Canada)"
msgstr ""
-#: picard/const.py:356
+#: picard/const.py:368
msgid "English (UK)"
msgstr ""
-#: picard/const.py:358
+#: picard/const.py:370
msgid "Spanish"
msgstr ""
-#: picard/const.py:359
+#: picard/const.py:371
msgid "Estonian"
msgstr ""
-#: picard/const.py:361
+#: picard/const.py:373
msgid "Finnish"
msgstr ""
-#: picard/const.py:363
+#: picard/const.py:375
msgid "French"
msgstr ""
-#: picard/const.py:372
+#: picard/const.py:384
msgid "Italian"
msgstr ""
-#: picard/const.py:379
+#: picard/const.py:391
msgid "Dutch"
msgstr ""
-#: picard/const.py:381
+#: picard/const.py:393
msgid "Polish"
msgstr ""
-#: picard/const.py:383
+#: picard/const.py:395
msgid "Brazilian Portuguese"
msgstr ""
-#: picard/const.py:390
+#: picard/const.py:402
msgid "Swedish"
msgstr ""
-#: picard/coverart.py:99
+#: picard/coverart.py:98
#, python-format
msgid "Coverart %s downloaded"
msgstr ""
-#: picard/coverart.py:260
+#: picard/coverart.py:259
#, python-format
msgid "Downloading http://%s:%i%s"
msgstr ""
@@ -1440,40 +1482,44 @@ msgstr ""
msgid "Unknown"
msgstr ""
-#: picard/file.py:536
+#: picard/file.py:534
#, python-format
msgid "No matching tracks for file %s"
msgstr ""
-#: picard/file.py:548
+#: picard/file.py:546
#, python-format
msgid "No matching tracks above the threshold for file %s"
msgstr ""
-#: picard/file.py:551
+#: picard/file.py:549
#, python-format
msgid "File %s identified!"
msgstr ""
-#: picard/file.py:567
+#: picard/file.py:565
#, python-format
msgid "Looking up the metadata for file %s..."
msgstr ""
#: picard/releasegroup.py:64
+msgid "[no barcode]"
+msgstr ""
+
+#: picard/releasegroup.py:84
msgid "[no release info]"
msgstr ""
-#: picard/tagger.py:348
+#: picard/tagger.py:298
#, python-format
msgid "Loading directory %s"
msgstr ""
-#: picard/tagger.py:484
+#: picard/tagger.py:434
msgid "CD Lookup Error"
msgstr ""
-#: picard/tagger.py:485
+#: picard/tagger.py:435
#, python-format
msgid ""
"Error while reading CD:\n"
@@ -1507,7 +1553,7 @@ msgstr ""
msgid "Catalog #s"
msgstr ""
-#: picard/ui/cdlookup.py:35 picard/util/tags.py:77
+#: picard/ui/cdlookup.py:35 picard/util/tags.py:78
msgid "Barcode"
msgstr ""
@@ -1594,19 +1640,19 @@ msgstr ""
msgid "&Info"
msgstr ""
-#: picard/ui/infostatus.py:52
+#: picard/ui/infostatus.py:51
msgid "Files"
msgstr ""
-#: picard/ui/infostatus.py:53
+#: picard/ui/infostatus.py:52
msgid "Albums"
msgstr ""
-#: picard/ui/infostatus.py:54
+#: picard/ui/infostatus.py:53
msgid "Pending files"
msgstr ""
-#: picard/ui/infostatus.py:55
+#: picard/ui/infostatus.py:54
msgid "Pending requests"
msgstr ""
@@ -1614,7 +1660,7 @@ msgstr ""
msgid "Title"
msgstr ""
-#: picard/ui/itemviews.py:95 picard/util/tags.py:86
+#: picard/ui/itemviews.py:95 picard/util/tags.py:87
msgid "Length"
msgstr ""
@@ -1634,31 +1680,31 @@ msgstr ""
msgid "Loading..."
msgstr ""
-#: picard/ui/itemviews.py:331
+#: picard/ui/itemviews.py:333
msgid "Collections"
msgstr ""
-#: picard/ui/itemviews.py:334
+#: picard/ui/itemviews.py:336
msgid "&Plugins"
msgstr ""
-#: picard/ui/itemviews.py:510
+#: picard/ui/itemviews.py:512
msgid "file view"
msgstr ""
-#: picard/ui/itemviews.py:511
+#: picard/ui/itemviews.py:513
msgid "Contains unmatched files and clusters"
msgstr ""
-#: picard/ui/itemviews.py:531
+#: picard/ui/itemviews.py:533
msgid "Clusters"
msgstr ""
-#: picard/ui/itemviews.py:540
+#: picard/ui/itemviews.py:542
msgid "album view"
msgstr ""
-#: picard/ui/itemviews.py:541
+#: picard/ui/itemviews.py:543
msgid "Contains albums and matched files"
msgstr ""
@@ -1670,34 +1716,34 @@ msgstr ""
msgid "Status History"
msgstr ""
-#: picard/ui/mainwindow.py:77
+#: picard/ui/mainwindow.py:78
msgid "MusicBrainz Picard"
msgstr ""
-#: picard/ui/mainwindow.py:158
+#: picard/ui/mainwindow.py:159
msgid "Unsaved Changes"
msgstr ""
-#: picard/ui/mainwindow.py:159
+#: picard/ui/mainwindow.py:160
msgid "Are you sure you want to quit Picard?"
msgstr ""
-#: picard/ui/mainwindow.py:160
+#: picard/ui/mainwindow.py:161
#, python-format
msgid "There is %d unsaved file. Closing Picard will lose all unsaved changes."
msgid_plural "There are %d unsaved files. Closing Picard will lose all unsaved changes."
msgstr[0] ""
msgstr[1] ""
-#: picard/ui/mainwindow.py:167
+#: picard/ui/mainwindow.py:168
msgid "&Quit Picard"
msgstr ""
-#: picard/ui/mainwindow.py:219
+#: picard/ui/mainwindow.py:220
msgid "Ready"
msgstr ""
-#: picard/ui/mainwindow.py:223
+#: picard/ui/mainwindow.py:224
msgid ""
"Picard listens on a port to integrate with your browser and downloads "
"release information when you click the \"Tagger\" buttons on the "
@@ -1955,47 +2001,17 @@ msgstr ""
msgid "All Supported Formats"
msgstr ""
-#: picard/ui/mainwindow.py:673 picard/ui/mainwindow.py:682
-msgid "Various Artists file naming scheme removal"
-msgstr ""
-
-#: picard/ui/mainwindow.py:674
-msgid ""
-"The separate file naming scheme for various artists albums has been\n"
-"removed in this version of Picard. You currently do not use the this "
-"option,\n"
-"but have a separate file naming scheme defined. Do you want to remove it "
-"or\n"
-"merge it with your file naming scheme for single artist albums?"
-msgstr ""
-
-#: picard/ui/mainwindow.py:678
-msgid "Merge"
-msgstr ""
-
-#: picard/ui/mainwindow.py:678 picard/ui/metadatabox.py:254
-msgid "Remove"
-msgstr ""
-
-#: picard/ui/mainwindow.py:683
-msgid ""
-"The separate file naming scheme for various artists albums has been\n"
-"removed in this version of Picard. Your file naming scheme has "
-"automatically\n"
-"been merged with that of single artist albums."
-msgstr ""
-
-#: picard/ui/mainwindow.py:727
+#: picard/ui/mainwindow.py:710
msgid "Configuration Required"
msgstr ""
-#: picard/ui/mainwindow.py:728
+#: picard/ui/mainwindow.py:711
msgid ""
"Audio fingerprinting is not yet configured. Would you like to configure "
"it now?"
msgstr ""
-#: picard/ui/mainwindow.py:806 picard/ui/mainwindow.py:813
+#: picard/ui/mainwindow.py:789 picard/ui/mainwindow.py:796
#, python-format
msgid " (Error: %s)"
msgstr ""
@@ -2276,7 +2292,7 @@ msgstr ""
msgid "Username:"
msgstr ""
-#: picard/ui/ui_options_general.py:98 picard/ui/options/general.py:29
+#: picard/ui/ui_options_general.py:98 picard/ui/options/general.py:30
msgid "General"
msgstr ""
@@ -2332,7 +2348,7 @@ msgstr ""
msgid "Minimal similarity for cluster lookups:"
msgstr ""
-#: picard/ui/ui_options_metadata.py:114 picard/ui/options/metadata.py:30
+#: picard/ui/ui_options_metadata.py:114 picard/ui/options/metadata.py:29
msgid "Metadata"
msgstr ""
@@ -2401,7 +2417,7 @@ msgstr ""
msgid "Name"
msgstr ""
-#: picard/ui/ui_options_plugins.py:133 picard/util/tags.py:37
+#: picard/ui/ui_options_plugins.py:133 picard/util/tags.py:38
msgid "Version"
msgstr ""
@@ -2457,7 +2473,7 @@ msgstr ""
msgid "EP"
msgstr ""
-#: picard/ui/ui_options_releases.py:219 picard/util/tags.py:68
+#: picard/ui/ui_options_releases.py:219
msgid "Compilation"
msgstr ""
@@ -2572,7 +2588,7 @@ msgid ""
msgstr ""
#: picard/ui/ui_options_tags.py:172
-msgid "Tags are separated by spaces, and are case-sensitive."
+msgid "Tags are separated by commas, and are case-sensitive."
msgstr ""
#: picard/ui/ui_options_tags.py:173
@@ -2650,24 +2666,24 @@ msgstr ""
msgid "&Cancel"
msgstr ""
-#: picard/ui/options/about.py:32
+#: picard/ui/options/about.py:33
msgid "About"
msgstr ""
-#: picard/ui/options/about.py:47
+#: picard/ui/options/about.py:48
msgid "is not installed"
msgstr ""
-#: picard/ui/options/about.py:56
+#: picard/ui/options/about.py:59
msgid "translator-credits"
msgstr ""
-#: picard/ui/options/about.py:59
+#: picard/ui/options/about.py:62
#, python-format
msgid "
Translated to LANG by %s"
msgstr ""
-#: picard/ui/options/about.py:63
+#: picard/ui/options/about.py:66
#, python-format
msgid ""
"\n"
-"Donate "
-"now!
\n"
+"Donate now!
"
+"\n"
"Credits
\n"
"Copyright © 2004-2011 Robert Kaye, Lukáš Lalinský and others"
"%(translator-credits)s
\n"
-"http://musicbrainz.org/doc/MusicBrainz_Picard
"
-"\n"
+"%(picard-doc-"
+"url)s
\n"
msgstr ""
#: picard/ui/options/advanced.py:26
@@ -2715,11 +2730,11 @@ msgstr ""
msgid "System default"
msgstr ""
-#: picard/ui/options/interface.py:92
+#: picard/ui/options/interface.py:96
msgid "Language changed"
msgstr ""
-#: picard/ui/options/interface.py:92
+#: picard/ui/options/interface.py:96
msgid ""
"You have changed the interface language. You have to restart Picard in "
"order for the change to take effect."
@@ -2749,15 +2764,15 @@ msgstr ""
msgid "File naming"
msgstr ""
-#: picard/ui/options/renaming.py:166
+#: picard/ui/options/renaming.py:184
msgid "Error"
msgstr ""
-#: picard/ui/options/renaming.py:166
+#: picard/ui/options/renaming.py:184
msgid "The location to move files to must not be empty."
msgstr ""
-#: picard/ui/options/renaming.py:176
+#: picard/ui/options/renaming.py:194
msgid "The file naming format must not be empty."
msgstr ""
@@ -2769,62 +2784,62 @@ msgstr ""
msgid "Script Error"
msgstr ""
-#: picard/util/bytes2human.py:35
+#: picard/util/bytes2human.py:33
#, python-format
msgid "%s B"
msgstr ""
-#: picard/util/bytes2human.py:36
+#: picard/util/bytes2human.py:34
#, python-format
msgid "%s kB"
msgstr ""
-#: picard/util/bytes2human.py:37
+#: picard/util/bytes2human.py:35
#, python-format
msgid "%s KiB"
msgstr ""
-#: picard/util/bytes2human.py:38
+#: picard/util/bytes2human.py:36
#, python-format
msgid "%s MB"
msgstr ""
-#: picard/util/bytes2human.py:39
+#: picard/util/bytes2human.py:37
#, python-format
msgid "%s MiB"
msgstr ""
-#: picard/util/bytes2human.py:40
+#: picard/util/bytes2human.py:38
#, python-format
msgid "%s GB"
msgstr ""
-#: picard/util/bytes2human.py:41
+#: picard/util/bytes2human.py:39
#, python-format
msgid "%s GiB"
msgstr ""
-#: picard/util/bytes2human.py:42
+#: picard/util/bytes2human.py:40
#, python-format
msgid "%s TB"
msgstr ""
-#: picard/util/bytes2human.py:43
+#: picard/util/bytes2human.py:41
#, python-format
msgid "%s TiB"
msgstr ""
-#: picard/util/bytes2human.py:44
+#: picard/util/bytes2human.py:42
#, python-format
msgid "%s PB"
msgstr ""
-#: picard/util/bytes2human.py:45
+#: picard/util/bytes2human.py:43
#, python-format
msgid "%s PiB"
msgstr ""
-#: picard/util/bytes2human.py:86
+#: picard/util/bytes2human.py:84
#, python-format
msgid "%s "
msgstr ""
@@ -2834,242 +2849,250 @@ msgid "Original Release Date"
msgstr ""
#: picard/util/tags.py:26
-msgid "Album Artist"
+msgid "Original Year"
msgstr ""
#: picard/util/tags.py:27
-msgid "Track Number"
+msgid "Album Artist"
msgstr ""
#: picard/util/tags.py:28
-msgid "Total Tracks"
+msgid "Track Number"
msgstr ""
#: picard/util/tags.py:29
-msgid "Disc Number"
+msgid "Total Tracks"
msgstr ""
#: picard/util/tags.py:30
-msgid "Total Discs"
+msgid "Disc Number"
msgstr ""
#: picard/util/tags.py:31
-msgid "Album Artist Sort Order"
+msgid "Total Discs"
msgstr ""
#: picard/util/tags.py:32
-msgid "Artist Sort Order"
+msgid "Album Artist Sort Order"
msgstr ""
#: picard/util/tags.py:33
-msgid "Title Sort Order"
+msgid "Artist Sort Order"
msgstr ""
#: picard/util/tags.py:34
-msgid "Album Sort Order"
+msgid "Title Sort Order"
msgstr ""
#: picard/util/tags.py:35
-msgid "ASIN"
+msgid "Album Sort Order"
msgstr ""
#: picard/util/tags.py:36
+msgid "ASIN"
+msgstr ""
+
+#: picard/util/tags.py:37
msgid "Grouping"
msgstr ""
-#: picard/util/tags.py:38
+#: picard/util/tags.py:39
msgid "ISRC"
msgstr ""
-#: picard/util/tags.py:39
+#: picard/util/tags.py:40
msgid "Mood"
msgstr ""
-#: picard/util/tags.py:40
+#: picard/util/tags.py:41
msgid "BPM"
msgstr ""
-#: picard/util/tags.py:41
+#: picard/util/tags.py:42
msgid "Copyright"
msgstr ""
-#: picard/util/tags.py:42
+#: picard/util/tags.py:43
msgid "License"
msgstr ""
-#: picard/util/tags.py:43
+#: picard/util/tags.py:44
msgid "Composer"
msgstr ""
-#: picard/util/tags.py:44
+#: picard/util/tags.py:45
msgid "Writer"
msgstr ""
-#: picard/util/tags.py:45
+#: picard/util/tags.py:46
msgid "Conductor"
msgstr ""
-#: picard/util/tags.py:46
+#: picard/util/tags.py:47
msgid "Lyricist"
msgstr ""
-#: picard/util/tags.py:47
+#: picard/util/tags.py:48
msgid "Arranger"
msgstr ""
-#: picard/util/tags.py:48
+#: picard/util/tags.py:49
msgid "Producer"
msgstr ""
-#: picard/util/tags.py:49
+#: picard/util/tags.py:50
msgid "Engineer"
msgstr ""
-#: picard/util/tags.py:50
+#: picard/util/tags.py:51
msgid "Subtitle"
msgstr ""
-#: picard/util/tags.py:51
+#: picard/util/tags.py:52
msgid "Disc Subtitle"
msgstr ""
-#: picard/util/tags.py:52
+#: picard/util/tags.py:53
msgid "Remixer"
msgstr ""
-#: picard/util/tags.py:53
+#: picard/util/tags.py:54
msgid "MusicBrainz Recording Id"
msgstr ""
-#: picard/util/tags.py:54
+#: picard/util/tags.py:55
msgid "MusicBrainz Track Id"
msgstr ""
-#: picard/util/tags.py:55
+#: picard/util/tags.py:56
msgid "MusicBrainz Release Id"
msgstr ""
-#: picard/util/tags.py:56
+#: picard/util/tags.py:57
msgid "MusicBrainz Artist Id"
msgstr ""
-#: picard/util/tags.py:57
+#: picard/util/tags.py:58
msgid "MusicBrainz Release Artist Id"
msgstr ""
-#: picard/util/tags.py:58
+#: picard/util/tags.py:59
msgid "MusicBrainz Work Id"
msgstr ""
-#: picard/util/tags.py:59
+#: picard/util/tags.py:60
msgid "MusicBrainz Release Group Id"
msgstr ""
-#: picard/util/tags.py:60
+#: picard/util/tags.py:61
msgid "MusicBrainz Disc Id"
msgstr ""
-#: picard/util/tags.py:61
+#: picard/util/tags.py:62
msgid "MusicBrainz Sort Name"
msgstr ""
-#: picard/util/tags.py:62
+#: picard/util/tags.py:63
msgid "MusicIP PUID"
msgstr ""
-#: picard/util/tags.py:63
+#: picard/util/tags.py:64
msgid "MusicIP Fingerprint"
msgstr ""
-#: picard/util/tags.py:64
+#: picard/util/tags.py:65
msgid "AcoustID"
msgstr ""
-#: picard/util/tags.py:65
+#: picard/util/tags.py:66
msgid "AcoustID Fingerprint"
msgstr ""
-#: picard/util/tags.py:66
+#: picard/util/tags.py:67
msgid "Disc Id"
msgstr ""
-#: picard/util/tags.py:67
+#: picard/util/tags.py:68
msgid "Website"
msgstr ""
#: picard/util/tags.py:69
-msgid "Comment"
+msgid "Compilation (iTunes)"
msgstr ""
#: picard/util/tags.py:70
-msgid "Genre"
+msgid "Comment"
msgstr ""
#: picard/util/tags.py:71
-msgid "Encoded By"
+msgid "Genre"
msgstr ""
#: picard/util/tags.py:72
-msgid "Performer"
+msgid "Encoded By"
msgstr ""
#: picard/util/tags.py:73
-msgid "Release Type"
+msgid "Performer"
msgstr ""
#: picard/util/tags.py:74
-msgid "Release Status"
+msgid "Release Type"
msgstr ""
#: picard/util/tags.py:75
-msgid "Release Country"
+msgid "Release Status"
msgstr ""
#: picard/util/tags.py:76
+msgid "Release Country"
+msgstr ""
+
+#: picard/util/tags.py:77
msgid "Record Label"
msgstr ""
-#: picard/util/tags.py:78
+#: picard/util/tags.py:79
msgid "Catalog Number"
msgstr ""
-#: picard/util/tags.py:79
+#: picard/util/tags.py:80
msgid "Format"
msgstr ""
-#: picard/util/tags.py:80
+#: picard/util/tags.py:81
msgid "DJ-Mixer"
msgstr ""
-#: picard/util/tags.py:81
+#: picard/util/tags.py:82
msgid "Media"
msgstr ""
-#: picard/util/tags.py:82
+#: picard/util/tags.py:83
msgid "Lyrics"
msgstr ""
-#: picard/util/tags.py:83
+#: picard/util/tags.py:84
msgid "Mixer"
msgstr ""
-#: picard/util/tags.py:84
+#: picard/util/tags.py:85
msgid "Language"
msgstr ""
-#: picard/util/tags.py:85
+#: picard/util/tags.py:86
msgid "Script"
msgstr ""
-#: picard/util/tags.py:87
+#: picard/util/tags.py:88
msgid "Rating"
msgstr ""
-#: picard/util/webbrowser2.py:88
+#: picard/util/webbrowser2.py:90
msgid "Web Browser Error"
msgstr ""
-#: picard/util/webbrowser2.py:88
+#: picard/util/webbrowser2.py:90
#, python-format
msgid ""
"Error while launching a web browser:\n"
From 0a1b97732bbbb5c82e265edd8b13980a3b40d353 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ionu=C8=9B=20Cioc=C3=AErlan?=
Date: Sat, 4 Jan 2014 21:43:39 +0200
Subject: [PATCH 53/59] PICARD-540: return relative paths for shortened
filenames
---
picard/file.py | 2 ++
picard/util/filenaming.py | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/picard/file.py b/picard/file.py
index 9a4b77c45..fb225b612 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -279,6 +279,8 @@ class File(QtCore.QObject, Item):
new_filename = os.path.basename(new_filename)
new_filename = make_short_filename(new_dirname, new_filename,
config.setting['windows_compatibility'], config.setting['windows_compatibility_drive_root'])
+ # TODO: move following logic under util.filenaming
+ # (and reconsider its necessity)
# win32 compatibility fixes
if settings['windows_compatibility'] or sys.platform == 'win32':
new_filename = new_filename.replace('./', '_/').replace('.\\', '_\\')
diff --git a/picard/util/filenaming.py b/picard/util/filenaming.py
index 1e166124d..9981bb57d 100644
--- a/picard/util/filenaming.py
+++ b/picard/util/filenaming.py
@@ -311,7 +311,7 @@ def make_short_filename(basedir, relpath, win_compat=False, relative_to=""):
reserved = len(basedir)
if not basedir.endswith(os.path.sep):
reserved += 1
- return os.path.join(basedir, _make_win_short_filename(relpath, reserved))
+ return _make_win_short_filename(relpath, reserved)
# if we're being windows compatible, figure out how much
# needs to be reserved for the basedir part
if win_compat:
@@ -337,4 +337,4 @@ def make_short_filename(basedir, relpath, win_compat=False, relative_to=""):
# and filesystem-dependent
limit = _get_filename_limit(basedir)
relpath = shorten_path(relpath, limit, mode=SHORTEN_BYTES)
- return os.path.join(basedir, relpath)
+ return relpath
From a8fa19588dccb43e4f74d44cc29ffce9843fa299 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sun, 5 Jan 2014 13:38:03 +0100
Subject: [PATCH 54/59] Drop useless spaces in button label
It is problematic when it comes to i18n and is useless here.
---
picard/ui/ui_cdlookup.py | 2 +-
ui/cdlookup.ui | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/picard/ui/ui_cdlookup.py b/picard/ui/ui_cdlookup.py
index 4d12eed1a..31eca9cdd 100644
--- a/picard/ui/ui_cdlookup.py
+++ b/picard/ui/ui_cdlookup.py
@@ -66,6 +66,6 @@ class Ui_Dialog(object):
Dialog.setWindowTitle(_("CD Lookup"))
self.label.setText(_("The following releases on MusicBrainz match the CD:"))
self.ok_button.setText(_("OK"))
- self.lookup_button.setText(_(" Lookup manually "))
+ self.lookup_button.setText(_("Lookup manually"))
self.cancel_button.setText(_("Cancel"))
diff --git a/ui/cdlookup.ui b/ui/cdlookup.ui
index b1738ae42..36c6af31b 100644
--- a/ui/cdlookup.ui
+++ b/ui/cdlookup.ui
@@ -68,7 +68,7 @@
-
- Lookup manually
+ Lookup manually
From 3e833083572d23a1fd7f7b9dda99f6f2e9500f74 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Sun, 5 Jan 2014 14:01:09 +0100
Subject: [PATCH 55/59] Regenerate picard.pot
---
po/picard.pot | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/po/picard.pot b/po/picard.pot
index e5ea78f78..b63f5dcd7 100644
--- a/po/picard.pot
+++ b/po/picard.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2014-01-02 18:11+0100\n"
+"POT-Creation-Date: 2014-01-05 14:00+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -1482,22 +1482,22 @@ msgstr ""
msgid "Unknown"
msgstr ""
-#: picard/file.py:534
+#: picard/file.py:536
#, python-format
msgid "No matching tracks for file %s"
msgstr ""
-#: picard/file.py:546
+#: picard/file.py:548
#, python-format
msgid "No matching tracks above the threshold for file %s"
msgstr ""
-#: picard/file.py:549
+#: picard/file.py:551
#, python-format
msgid "File %s identified!"
msgstr ""
-#: picard/file.py:565
+#: picard/file.py:567
#, python-format
msgid "Looking up the metadata for file %s..."
msgstr ""
@@ -2100,7 +2100,7 @@ msgid "OK"
msgstr ""
#: picard/ui/ui_cdlookup.py:69
-msgid " Lookup manually "
+msgid "Lookup manually"
msgstr ""
#: picard/ui/ui_cdlookup.py:70
From cbcbc734081e949846b5c02b90b74f32c51a1c40 Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Mon, 6 Jan 2014 11:25:27 +0100
Subject: [PATCH 56/59] Update README.md
Typo fix
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f74a37151..006cb9c79 100644
--- a/README.md
+++ b/README.md
@@ -11,4 +11,4 @@ Picard is named after Captain Jean-Luc Picard from the TV series Star Trek: The
Binary downloads are available [here](http://musicbrainz.org/doc/MusicBrainz_Picard).
-To submit bugs or improvements, please use [Picard bug-tracker](http://tickets.musicbrainz.org/browse/PICARD).
+To submit bugs or improvements, please use [Picard bug tracker](http://tickets.musicbrainz.org/browse/PICARD).
From 0d04cbdf8ad52b7408763e99f78255f1861c4867 Mon Sep 17 00:00:00 2001
From: Ismael Olea
Date: Mon, 6 Jan 2014 17:11:27 +0100
Subject: [PATCH 57/59] Update about.py
updated copyright dates
---
picard/ui/options/about.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/picard/ui/options/about.py b/picard/ui/options/about.py
index bb7a3c3c3..84d55d272 100644
--- a/picard/ui/options/about.py
+++ b/picard/ui/options/about.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
-# Copyright (C) 2006 Lukáš Lalinský
+# Copyright (C) 2006-2014 Lukáš Lalinský
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -75,7 +75,7 @@ Discid %(discid-version)s
Thank you for using Picard. Picard relies on the MusicBrainz database, which is operated by the MetaBrainz Foundation with the help of thousands of volunteers. If you like this application please consider donating to the MetaBrainz Foundation to keep the service running.
Donate now!
Credits
-Copyright © 2004-2011 Robert Kaye, Lukáš Lalinský and others%(translator-credits)s
+Copyright © 2004-2014 Robert Kaye, Lukáš Lalinský and others%(translator-credits)s
%(picard-doc-url)s
""") % args
self.ui.label.setOpenExternalLinks(True)
From 156aeda8a0c45009ddf9fe869e6b3bd9f485489f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ionu=C8=9B=20Cioc=C3=AErlan?=
Date: Tue, 7 Jan 2014 17:59:50 +0200
Subject: [PATCH 58/59] updated tests for filename shortening (which now
returns relative paths)
---
test/test_util_filenaming.py | 40 ++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 18 deletions(-)
diff --git a/test/test_util_filenaming.py b/test/test_util_filenaming.py
index b7b2056fa..e04441ca5 100644
--- a/test/test_util_filenaming.py
+++ b/test/test_util_filenaming.py
@@ -17,7 +17,7 @@ class ShortFilenameTest(unittest.TestCase):
def test_bmp_unicode_on_unicode_fs(self):
char = u"\N{LATIN SMALL LETTER SHARP S}"
fn = make_short_filename(self.root, os.path.join(*[char * 120] * 2))
- self.assertEqual(fn, os.path.join(self.root, *[char * 120] * 2))
+ self.assertEqual(fn, os.path.join(*[char * 120] * 2))
@unittest.skipUnless(sys.platform not in ("win32", "darwin"), "non-windows, non-osx test")
def test_bmp_unicode_on_nix(self):
@@ -25,28 +25,28 @@ class ShortFilenameTest(unittest.TestCase):
max_len = 255
divisor = len(char.encode(sys.getfilesystemencoding()))
fn = make_short_filename(self.root, os.path.join(*[char * 200] * 2))
- self.assertEqual(fn, os.path.join(self.root, *[char * (max_len // divisor)] * 2))
+ self.assertEqual(fn, os.path.join(*[char * (max_len // divisor)] * 2))
@unittest.skipUnless(sys.platform == "darwin", "os x test")
def test_precomposed_unicode_on_osx(self):
char = u"\N{LATIN SMALL LETTER A WITH BREVE}"
max_len = 255
fn = make_short_filename(self.root, os.path.join(*[char * 200] * 2))
- self.assertEqual(fn, os.path.join(self.root, *[char * (max_len // 2)] * 2))
+ self.assertEqual(fn, os.path.join(*[char * (max_len // 2)] * 2))
@unittest.skipUnless(sys.platform == "win32", "windows test")
def test_nonbmp_unicode_on_windows(self):
char = u"\N{MUSICAL SYMBOL G CLEF}"
remaining = 259 - (3 + 10 + 1 + 200 + 1)
fn = make_short_filename(self.root, os.path.join(*[char * 100] * 2))
- self.assertEqual(fn, os.path.join(self.root, char * 100, char * (remaining // 2)))
+ self.assertEqual(fn, os.path.join(char * 100, char * (remaining // 2)))
@unittest.skipUnless(sys.platform == "darwin", "os x test")
def test_nonbmp_unicode_on_osx(self):
char = u"\N{MUSICAL SYMBOL G CLEF}"
max_len = 255
fn = make_short_filename(self.root, os.path.join(*[char * 200] * 2))
- self.assertEqual(fn, os.path.join(self.root, *[char * (max_len // 2)] * 2))
+ self.assertEqual(fn, os.path.join(*[char * (max_len // 2)] * 2))
@unittest.skipUnless(sys.platform not in ("win32", "darwin"), "non-windows, non-osx test")
def test_nonbmp_unicode_on_nix(self):
@@ -54,7 +54,7 @@ class ShortFilenameTest(unittest.TestCase):
max_len = 255
divisor = len(char.encode(sys.getfilesystemencoding()))
fn = make_short_filename(self.root, os.path.join(*[char * 100] * 2))
- self.assertEqual(fn, os.path.join(self.root, *[char * (max_len // divisor)] * 2))
+ self.assertEqual(fn, os.path.join(*[char * (max_len // divisor)] * 2))
@unittest.skipUnless(sys.platform not in ("win32", "darwin"), "non-windows, non-osx test")
def test_nonbmp_unicode_on_nix_with_windows_compat(self):
@@ -63,45 +63,49 @@ class ShortFilenameTest(unittest.TestCase):
remaining = 259 - (3 + 10 + 1 + 200 + 1)
divisor = len(char.encode(sys.getfilesystemencoding()))
fn = make_short_filename(self.root, os.path.join(*[char * 100] * 2), win_compat=True)
- self.assertEqual(fn, os.path.join(self.root, char * (max_len // divisor), char * (remaining // 2)))
+ self.assertEqual(fn, os.path.join(char * (max_len // divisor), char * (remaining // 2)))
def test_windows_shortening(self):
fn = make_short_filename(self.root, os.path.join("a" * 200, "b" * 200, "c" * 200 + ".ext"), win_compat=True)
- self.assertEqual(fn, os.path.join(self.root, "a" * 116, "b" * 116, "c" * 7 + ".ext"))
+ self.assertEqual(fn, os.path.join("a" * 116, "b" * 116, "c" * 7 + ".ext"))
@unittest.skipUnless(sys.platform != "win32", "non-windows test")
def test_windows_shortening_with_ancestor_on_nix(self):
+ root = os.path.join(self.root, "w" * 10, "x" * 10, "y" * 9, "z" * 9)
fn = make_short_filename(
- os.path.join(self.root, "w" * 10, "x" * 10, "y" * 9, "z" * 9), os.path.join("b" * 200, "c" * 200, "d" * 200 + ".ext"),
+ root, os.path.join("b" * 200, "c" * 200, "d" * 200 + ".ext"),
win_compat=True, relative_to = self.root)
- self.assertEqual(fn, os.path.join(self.root, "w" * 10, "x" * 10, "y" * 9, "z" * 9, "b" * 100, "c" * 100, "d" * 7 + ".ext"))
+ self.assertEqual(fn, os.path.join("b" * 100, "c" * 100, "d" * 7 + ".ext"))
def test_windows_node_maxlength_shortening(self):
max_len = 226
remaining = 259 - (3 + 10 + 1 + max_len + 1)
fn = make_short_filename(self.root, os.path.join("a" * 300, "b" * 100 + ".ext"), win_compat=True)
- self.assertEqual(fn, os.path.join(self.root, "a" * max_len, "b" * (remaining - 4) + ".ext"))
+ self.assertEqual(fn, os.path.join("a" * max_len, "b" * (remaining - 4) + ".ext"))
def test_windows_selective_shortening(self):
root = self.root + "x" * (44 - 10 - 3)
fn = make_short_filename(root, os.path.join(
os.path.join(*["a" * 9] * 10 + ["b" * 15] * 10), "c" * 10), win_compat=True)
- self.assertEqual(fn, os.path.join(root, os.path.join(*["a" * 9] * 10 + ["b" * 9] * 10), "c" * 10))
+ self.assertEqual(fn, os.path.join(os.path.join(*["a" * 9] * 10 + ["b" * 9] * 10), "c" * 10))
def test_windows_shortening_not_needed(self):
- fn = make_short_filename(self.root + "x" * 33, os.path.join(
+ root = self.root + "x" * 33
+ fn = make_short_filename(root, os.path.join(
os.path.join(*["a" * 9] * 20), "b" * 10), win_compat=True)
- self.assertEqual(fn, os.path.join(self.root + "x" * 33, os.path.join(*["a" * 9] * 20), "b" * 10))
+ self.assertEqual(fn, os.path.join(os.path.join(*["a" * 9] * 20), "b" * 10))
def test_windows_path_too_long(self):
+ root = self.root + "x" * 230
self.assertRaises(IOError, make_short_filename,
- self.root + "x" * 230, os.path.join("a", "b", "c", "d"), win_compat=True)
+ root, os.path.join("a", "b", "c", "d"), win_compat=True)
def test_windows_path_not_too_long(self):
- fn = make_short_filename(self.root + "x" * 230, os.path.join("a", "b", "c"), win_compat=True)
- self.assertEqual(fn, os.path.join(self.root + "x" * 230, "a", "b", "c"))
+ root = self.root + "x" * 230
+ fn = make_short_filename(root, os.path.join("a", "b", "c"), win_compat=True)
+ self.assertEqual(fn, os.path.join("a", "b", "c"))
def test_whitespace(self):
fn = make_short_filename(self.root, os.path.join("a1234567890 ", " b1234567890 "))
- self.assertEqual(fn, os.path.join(self.root, "a1234567890", "b1234567890"))
+ self.assertEqual(fn, os.path.join("a1234567890", "b1234567890"))
From 9747a46780aa08e3a2a97df167a5f83a7ec5ff8b Mon Sep 17 00:00:00 2001
From: Laurent Monin
Date: Thu, 9 Jan 2014 15:54:03 +0100
Subject: [PATCH 59/59] Remove extra imports
---
setup.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/setup.py b/setup.py
index 306869719..134d6f916 100755
--- a/setup.py
+++ b/setup.py
@@ -89,8 +89,6 @@ class picard_test(Command):
self.verbosity = int(self.verbosity)
def run(self):
- import os.path
- import glob
import unittest
names = []