diff --git a/picard/cluster.py b/picard/cluster.py index 746f8ad15..c14e47818 100644 --- a/picard/cluster.py +++ b/picard/cluster.py @@ -212,7 +212,7 @@ class Cluster(QtCore.QObject, Item): artist_hist = {} for track_id in album: cluster = artist_cluster_engine.getClusterFromId( - tracks[track_id][0]) + tracks[track_id][0]) cnt = artist_hist.get(cluster, 0) + 1 if cnt > artist_max: artist_max = cnt diff --git a/picard/const.py b/picard/const.py index b18de1006..31152db57 100644 --- a/picard/const.py +++ b/picard/const.py @@ -43,11 +43,11 @@ ACOUSTID_HOST = 'api.acoustid.org' ACOUSTID_PORT = 80 FPCALC_NAMES = ['fpcalc', 'pyfpcalc'] -#Cover art archive URL and port +# Cover art archive URL and port CAA_HOST = "coverartarchive.org" CAA_PORT = 80 -#URLs +# URLs PICARD_URLS = { 'documentation': "http://musicbrainz.org/doc/Picard_Documentation", 'troubleshooting': "http://musicbrainz.org/doc/Picard_Troubleshooting", diff --git a/picard/coverart.py b/picard/coverart.py index 025c8670e..df5cac28d 100644 --- a/picard/coverart.py +++ b/picard/coverart.py @@ -40,9 +40,9 @@ COVERART_SITES = ( # CD-Baby # tested with http://musicbrainz.org/release/6e228dfa-b0c7-4987-a36d-7ac14541ae66 { - 'name': 'cdbaby', - 'regexp': r'http://(www\.)?cdbaby.com/cd/(\w)(\w)(\w*)', - 'imguri': 'http://cdbaby.name/$2/$3/$2$3$4.jpg', + 'name': 'cdbaby', + 'regexp': r'http://(www\.)?cdbaby.com/cd/(\w)(\w)(\w*)', + 'imguri': 'http://cdbaby.name/$2/$3/$2$3$4.jpg', }, ) @@ -208,16 +208,16 @@ def coverart(album, metadata, release, try_list=None): if config.setting['ca_provider_use_caa'] and has_caa_artwork\ and len(caa_types) > 0: log.debug("There are suitable images in the cover art archive for %s" - % release.id) + % release.id) album._requests += 1 album.tagger.xmlws.download( - CAA_HOST, CAA_PORT, "/release/%s/" % - metadata["musicbrainz_albumid"], - partial(_caa_json_downloaded, album, metadata, release, try_list), - priority=True, important=False) + CAA_HOST, CAA_PORT, "/release/%s/" % + metadata["musicbrainz_albumid"], + partial(_caa_json_downloaded, album, metadata, release, try_list), + priority=True, important=False) else: log.debug("There are no suitable images in the cover art archive for %s" - % release.id) + % release.id) _fill_try_list(album, release, try_list) _walk_try_list(album, metadata, release, try_list) diff --git a/picard/formats/id3.py b/picard/formats/id3.py index b63a85b69..9024c3701 100644 --- a/picard/formats/id3.py +++ b/picard/formats/id3.py @@ -487,5 +487,5 @@ class ID3Metadata(Metadata): def __fix_date_mm(self, value): # Return yyyy if date format is yyyy-mm if len(value) < 10: - return value[:4] + return value[:4] return value diff --git a/picard/formats/vorbis.py b/picard/formats/vorbis.py index c8a2d5fd6..538005ec3 100644 --- a/picard/formats/vorbis.py +++ b/picard/formats/vorbis.py @@ -118,7 +118,7 @@ class VCommentFile(File): for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data) - ) + ) except KeyError: pass self._info(metadata, file) diff --git a/picard/releasegroup.py b/picard/releasegroup.py index 46161b9a6..70d4bc031 100644 --- a/picard/releasegroup.py +++ b/picard/releasegroup.py @@ -85,7 +85,7 @@ class ReleaseGroup(DataObject): name = "%s / %s" % (_('[no release info]'), name) versions[name].append(release) - #de-duplicate names if possible + # de-duplicate names if possible for name, releases in versions.iteritems(): for a, b in combinations(releases, 2): for key in extrakeys: diff --git a/picard/script.py b/picard/script.py index bf413363e..2b073fb35 100644 --- a/picard/script.py +++ b/picard/script.py @@ -116,6 +116,7 @@ def isidentif(ch): class ScriptParser(object): + """Tagger script parser. Grammar: @@ -268,7 +269,7 @@ Grammar: def register_script_function(function, name=None, eval_args=True, - check_argcount=True): + check_argcount=True): """Registers a script function. If ``name`` is ``None``, ``function.__name__`` will be used. If ``eval_args`` is ``False``, the arguments will not be evaluated before being diff --git a/picard/tagger.py b/picard/tagger.py index ec221ab8b..9a31d12ba 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -206,7 +206,6 @@ class Tagger(QtGui.QApplication): _s["windows_compatibility"] = _s["windows_compatible_filenames"] _s.remove("windows_compatible_filenames") - cfg.register_upgrade_hook("1.0.0final0", upgrade_to_v1_0) # TODO: uncomment this and replace with proper version before release #cfg.register_upgrade_hook("1.3.0dev1", upgrade_windows_compatibility_setting) diff --git a/picard/ui/infodialog.py b/picard/ui/infodialog.py index 3c5ed71f5..b45f98f3c 100644 --- a/picard/ui/infodialog.py +++ b/picard/ui/infodialog.py @@ -122,12 +122,12 @@ class AlbumInfoDialog(InfoDialog): if album.errors: tabWidget.setTabText(tab_index, _("&Errors")) text = '
'.join(map(lambda s: '%s' % - '
'.join(unicode(QtCore.Qt.escape(s)) - .replace('\t', ' ') - .replace(' ', ' ') - .splitlines() - ), album.errors) - ) + '
'.join(unicode(QtCore.Qt.escape(s)) + .replace('\t', ' ') + .replace(' ', ' ') + .splitlines() + ), album.errors) + ) self.ui.info.setText(text + '
') else: tabWidget.setTabText(tab_index, _("&Info")) diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py index 2d0f7707d..6d4ad1c2d 100644 --- a/picard/ui/mainwindow.py +++ b/picard/ui/mainwindow.py @@ -56,13 +56,13 @@ class MainWindow(QtGui.QMainWindow): options = [ config.Option("persist", "window_state", QtCore.QByteArray(), - QtCore.QVariant.toByteArray), + QtCore.QVariant.toByteArray), config.Option("persist", "window_position", QtCore.QPoint(), - QtCore.QVariant.toPoint), + QtCore.QVariant.toPoint), config.Option("persist", "window_size", QtCore.QSize(780, 560), - QtCore.QVariant.toSize), + QtCore.QVariant.toSize), config.Option("persist", "bottom_splitter_state", QtCore.QByteArray(), - QtCore.QVariant.toByteArray), + QtCore.QVariant.toByteArray), config.BoolOption("persist", "window_maximized", False), config.BoolOption("persist", "view_cover_art", False), config.BoolOption("persist", "view_file_browser", False), diff --git a/picard/ui/metadatabox.py b/picard/ui/metadatabox.py index 0d7f9815b..bec999ff0 100644 --- a/picard/ui/metadatabox.py +++ b/picard/ui/metadatabox.py @@ -447,7 +447,7 @@ class MetadataBox(QtGui.QTableWidget): self.set_item_value(new_item, self.tag_diff.new, name) color = self.colors.get(result.tag_status(name), - self.colors[TagStatus.NoChange]) + self.colors[TagStatus.NoChange]) orig_item.setForeground(color) new_item.setForeground(color) diff --git a/picard/ui/options/cover.py b/picard/ui/options/cover.py index df1255c90..7cd9b3627 100644 --- a/picard/ui/options/cover.py +++ b/picard/ui/options/cover.py @@ -114,7 +114,7 @@ class CoverOptionsPage(OptionsPage): self.ui.cb_approved_only.setChecked(config.setting["caa_approved_only"]) self.ui.cb_type_as_filename.setChecked(config.setting["caa_image_type_as_filename"]) self.connect(self.ui.caprovider_caa, QtCore.SIGNAL("toggled(bool)"), - self.ui.gb_caa.setEnabled) + self.ui.gb_caa.setEnabled) def save(self): config.setting["save_images_to_tags"] = self.ui.save_images_to_tags.isChecked() diff --git a/picard/ui/options/interface.py b/picard/ui/options/interface.py index a2ad1a12d..5def4c5df 100644 --- a/picard/ui/options/interface.py +++ b/picard/ui/options/interface.py @@ -63,11 +63,11 @@ class InterfaceOptionsPage(OptionsPage): self.ui.starting_directory.stateChanged.connect(partial( enabledSlot, self.ui.starting_directory_path.setEnabled) - ) + ) self.ui.starting_directory.stateChanged.connect(partial( enabledSlot, self.ui.starting_directory_browse.setEnabled) - ) + ) self.ui.starting_directory_browse.clicked.connect(self.starting_directory_browse) def load(self): diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py index c26942bf9..80a385992 100644 --- a/picard/ui/options/releases.py +++ b/picard/ui/options/releases.py @@ -75,9 +75,9 @@ class ReleasesOptionsPage(OptionsPage): release_type_slider.setValue(int(scores.get(release_type, 0.5) * 100)) self._load_list_items("preferred_release_countries", RELEASE_COUNTRIES, - self.ui.country_list, self.ui.preferred_country_list) + self.ui.country_list, self.ui.preferred_country_list) self._load_list_items("preferred_release_formats", RELEASE_FORMATS, - self.ui.format_list, self.ui.preferred_format_list) + self.ui.format_list, self.ui.preferred_format_list) def save(self): scores = {} diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py index d19f4f34a..34b60fc38 100644 --- a/picard/ui/options/renaming.py +++ b/picard/ui/options/renaming.py @@ -64,42 +64,42 @@ class RenamingOptionsPage(OptionsPage): if not sys.platform == "win32": self.ui.rename_files.stateChanged.connect(partial( - enabledSlot, - self.ui.windows_compatibility.setEnabled) - ) + enabledSlot, + self.ui.windows_compatibility.setEnabled) + ) self.ui.move_files.stateChanged.connect(partial( - enabledSlot, - self.ui.delete_empty_dirs.setEnabled) - ) + enabledSlot, + self.ui.delete_empty_dirs.setEnabled) + ) self.ui.move_files.stateChanged.connect(partial( - enabledSlot, - self.ui.move_files_to.setEnabled) - ) + enabledSlot, + self.ui.move_files_to.setEnabled) + ) self.ui.move_files.stateChanged.connect(partial( - enabledSlot, - self.ui.move_files_to_browse.setEnabled) - ) + enabledSlot, + self.ui.move_files_to_browse.setEnabled) + ) self.ui.move_files.stateChanged.connect(partial( - enabledSlot, - self.ui.move_additional_files.setEnabled) - ) + enabledSlot, + self.ui.move_additional_files.setEnabled) + ) self.ui.move_files.stateChanged.connect(partial( - enabledSlot, - self.ui.move_additional_files_pattern.setEnabled) - ) + enabledSlot, + self.ui.move_additional_files_pattern.setEnabled) + ) self.ui.rename_files.stateChanged.connect(partial( - enabledSlot, - self.ui.ascii_filenames.setEnabled) - ) + enabledSlot, + self.ui.ascii_filenames.setEnabled) + ) self.ui.rename_files.stateChanged.connect(partial( - enabledSlot, - self.ui.file_naming_format.setEnabled) - ) + enabledSlot, + self.ui.file_naming_format.setEnabled) + ) self.ui.rename_files.stateChanged.connect(partial( - enabledSlot, - self.ui.file_naming_format_default.setEnabled) - ) + enabledSlot, + self.ui.file_naming_format_default.setEnabled) + ) self.ui.file_naming_format.textChanged.connect(self.check_formats) self.ui.file_naming_format_default.clicked.connect(self.set_file_naming_format_default) self.highlighter = TaggerScriptSyntaxHighlighter(self.ui.file_naming_format.document()) diff --git a/picard/util/__init__.py b/picard/util/__init__.py index 78f27d7c1..f4797fc79 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -336,6 +336,7 @@ _tracknum_regexps = ( r"\D?(\d{2})$", ) + def tracknum_from_filename(base_filename): """Guess and extract track number from filename Returns -1 if none found, the number as integer else diff --git a/picard/util/filenaming.py b/picard/util/filenaming.py index b18122c6e..1e166124d 100644 --- a/picard/util/filenaming.py +++ b/picard/util/filenaming.py @@ -39,6 +39,7 @@ def _get_utf16_length(text): # and divide the resulting length by 2 return len(text.encode("utf-16%ce" % sys.byteorder[0])) // 2 + def _shorten_to_utf16_length(text, length): """Truncates a unicode object to the given number of UTF-16 code points. """ @@ -65,6 +66,7 @@ def _shorten_to_utf16_length(text, length): shortened = shortened[:-2] return shortened.decode(enc) + def _shorten_to_utf16_nfd_length(text, length): text = unicodedata.normalize('NFD', text) newtext = _shorten_to_utf16_length(text, length) @@ -124,6 +126,7 @@ def shorten_filename(filename, length, mode): if mode == SHORTEN_UTF16_NFD: return _shorten_to_utf16_nfd_length(filename, length) + def shorten_path(path, length, mode): """Reduce path nodes' length to given limit(s). @@ -135,7 +138,7 @@ def shorten_path(path, length, mode): dirpath, filename = os.path.split(path) fileroot, ext = os.path.splitext(filename) return os.path.join( - os.path.join(*[shorten(node, length) \ + os.path.join(*[shorten(node, length) for node in dirpath.split(os.path.sep)]), shorten(fileroot, length - len(ext)) + ext ) @@ -150,6 +153,7 @@ def _shorten_to_utf16_ratio(text, ratio): else: return _shorten_to_utf16_length(text, limit).strip() + def _make_win_short_filename(relpath, reserved=0): """Shorten a relative file path according to WinAPI quirks. @@ -186,7 +190,7 @@ def _make_win_short_filename(relpath, reserved=0): # what if dirpath is already the right size? dplen = xlength(dirpath) if dplen <= remaining: - filename_max = MAX_FILEPATH_LEN - (reserved + dplen + 1) # the final separator + filename_max = MAX_FILEPATH_LEN - (reserved + dplen + 1) # the final separator filename = shorten(filename, filename_max) return os.path.join(dirpath, filename) @@ -334,4 +338,3 @@ def make_short_filename(basedir, relpath, win_compat=False, relative_to=""): limit = _get_filename_limit(basedir) relpath = shorten_path(relpath, limit, mode=SHORTEN_BYTES) return os.path.join(basedir, relpath) - diff --git a/picard/util/webbrowser2.py b/picard/util/webbrowser2.py index 2e220deb2..d1bb0a822 100644 --- a/picard/util/webbrowser2.py +++ b/picard/util/webbrowser2.py @@ -62,6 +62,7 @@ else: if 'windows-default' in webbrowser._tryorder: class WindowsDefault2(webbrowser.BaseBrowser): + def open(self, url, new=0, autoraise=1): try: os.startfile(url) @@ -88,5 +89,6 @@ def open(url): except webbrowser.Error as e: QtGui.QMessageBox.critical(None, _("Web Browser Error"), _("Error while launching a web browser:\n\n%s") % (e,)) + def goto(url_id): open(PICARD_URLS[url_id]) diff --git a/picard/webservice.py b/picard/webservice.py index 6c1fe9e48..d9b17b8b8 100644 --- a/picard/webservice.py +++ b/picard/webservice.py @@ -65,7 +65,7 @@ def _escape_lucene_query(text): def _wrap_xml_metadata(data): return ('' + - '%s' % data) + '%s' % data) class XmlNode(object): @@ -167,7 +167,7 @@ class XmlWebService(QtCore.QObject): self.manager.setCache(cache) log.debug("NetworkDiskCache dir: %s", cache.cacheDirectory()) log.debug("NetworkDiskCache size: %s / %s", cache.cacheSize(), - cache.maximumCacheSize()) + cache.maximumCacheSize()) def setup_proxy(self): proxy = QtNetwork.QNetworkProxy() @@ -181,7 +181,7 @@ class XmlWebService(QtCore.QObject): def _start_request(self, method, host, port, path, data, handler, xml, mblogin=False, cacheloadcontrol=None, refresh=None): - if mblogin and host in MUSICBRAINZ_SERVERS and port==80: + if mblogin and host in MUSICBRAINZ_SERVERS and port == 80: urlstring = "https://%s%s" % (host, path) else: urlstring = "http://%s:%d%s" % (host, port, path) @@ -234,18 +234,18 @@ class XmlWebService(QtCore.QObject): fromCache = reply.attribute(QtNetwork.QNetworkRequest.SourceIsFromCacheAttribute).toBool() cached = ' (CACHED)' if fromCache else '' log.debug("Received reply for %s: HTTP %d (%s) %s", - reply.request().url().toString(), - reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute).toInt()[0], - reply.attribute(QtNetwork.QNetworkRequest.HttpReasonPhraseAttribute).toString(), - cached - ) + reply.request().url().toString(), + reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute).toInt()[0], + reply.attribute(QtNetwork.QNetworkRequest.HttpReasonPhraseAttribute).toString(), + cached + ) if handler is not None: if error: log.error("Network request error for %s: %s (QT code %d, HTTP code %d)", - reply.request().url().toString(), - reply.errorString(), - error, - reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute).toInt()[0]) + reply.request().url().toString(), + reply.errorString(), + error, + reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute).toInt()[0]) # Redirect if found and not infinite if not redirect.isEmpty() and not XmlWebService.urls_equivalent(redirect, reply.request().url()): @@ -260,8 +260,8 @@ class XmlWebService(QtCore.QObject): if ((original_host, original_port) in REQUEST_DELAY and (redirect_host, redirect_port) not in REQUEST_DELAY): log.debug("Setting rate limit for %s:%i to %i" % - (redirect_host, redirect_port, - REQUEST_DELAY[(original_host, original_port)])) + (redirect_host, redirect_port, + REQUEST_DELAY[(original_host, original_port)])) REQUEST_DELAY[(redirect_host, redirect_port)] =\ REQUEST_DELAY[(original_host, original_port)]