Move PROGRAM_UPDATE_LEVELS to picard.constants

- Move PROGRAM_UPDATE_LEVELS to picard.constants
- Logging changes
- Formatting and translation clean-up
- Change picard.const.PROGRAM_UPDATE_LEVELS to numeric keys
- Add releases endpoint to picard.const.PLUGINS_API
- Refactor to remove duplicated code in mainwindow.py
- General cleanup of debug log translations
- Use intermediate variables to cache config information
This commit is contained in:
Bob Swift
2018-08-22 16:14:54 -06:00
committed by Laurent Monin
parent df3ca29ab6
commit fbd5cca092
8 changed files with 107 additions and 130 deletions

View File

@@ -24,26 +24,12 @@ PICARD_ORG_NAME = "MusicBrainz"
PICARD_APP_NAME = "Picard"
PICARD_VERSION = (2, 0, 4, 'dev', 1)
# optional build version
# it should be in the form '<platform>_<YYMMDDHHMMSS>'
# ie. win32_20140415091256
PICARD_BUILD_VERSION_STR = ""
PROGRAM_UPDATE_LEVELS = {
'stable': {
'level': 0,
'title': 'Stable releases only',
},
'beta': {
'level': 1,
'title': 'Stable and Beta releases',
},
'dev': {
'level': 2,
'title': 'Stable, Beta and Dev releases',
},
}
class VersionError(Exception):
pass

View File

@@ -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.
from collections import OrderedDict
import os
import sys
@@ -101,13 +102,14 @@ MUSICBRAINZ_SERVERS = [
'beta.musicbrainz.org',
]
# Plugins API
# Plugins and Release Versions API
PLUGINS_API = {
'host': 'picard.musicbrainz.org',
'port': 443,
'endpoint': {
'plugins': '/api/v2/plugins/',
'download': '/api/v2/download/'
'download': '/api/v2/download/',
'releases': '/api/releases',
}
}
@@ -116,3 +118,27 @@ QUERY_LIMIT = 25
# Maximum number of covers to draw in a stack in CoverArtThumbnail
MAX_COVERS_TO_STACK = 4
# Update levels available for automatic checking
PROGRAM_UPDATE_LEVELS = OrderedDict(
[
(
0, {
'name': 'stable',
'title': N_('Stable releases only'),
}
),
(
1, {
'name': 'beta',
'title': N_('Stable and Beta releases'),
}
),
(
2, {
'name': 'dev',
'title': N_('Stable, Beta and Dev releases'),
}
),
]
)

View File

@@ -83,6 +83,7 @@ from picard.util import (
uniqify,
versions,
)
from picard.util.checkupdate import UpdateCheckManager
from picard.webservice import WebService
from picard.webservice.api_helpers import (
AcoustIdAPIHelper,
@@ -97,8 +98,6 @@ from picard.ui.searchdialog.album import AlbumSearchDialog
from picard.ui.searchdialog.artist import ArtistSearchDialog
from picard.ui.searchdialog.track import TrackSearchDialog
from picard.util.checkupdate import UpdateCheckManager
# A "fix" for https://bugs.python.org/issue1438480
def _patched_shutil_copystat(src, dst, *, follow_symlinks=True):

View File

@@ -31,10 +31,10 @@ from PyQt5 import (
from picard import (
config,
log,
PROGRAM_UPDATE_LEVELS,
)
from picard.album import Album
from picard.cluster import Cluster
from picard.const import PROGRAM_UPDATE_LEVELS
from picard.file import File
from picard.formats import supported_formats
from picard.plugin import ExtensionPoint
@@ -176,19 +176,7 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
def show(self):
self.restoreWindowState()
super().show()
for key in PROGRAM_UPDATE_LEVELS.keys():
if PROGRAM_UPDATE_LEVELS[key]['level'] == config.setting["update_level"]:
update_level_text = key
do_auto_update_check = config.setting['check_for_updates'] and config.setting['update_check_days'] > 0 and datetime.date.today().toordinal() >= config.persist['last_update_check'] + config.setting['update_check_days']
log.debug(_("{check_status} start-up check for program updates. Today: {today_date}, Last check: {last_check} (Check interval: {check_interval} days), Update level: {update_level}".format(
check_status='Initiating' if do_auto_update_check else 'Skipping',
today_date=datetime.date.today(),
last_check=str(datetime.date.fromordinal(config.persist['last_update_check'])) if config.persist['last_update_check'] > 0 else 'never',
check_interval=config.setting['update_check_days'],
update_level=update_level_text if update_level_text else 'unknown',
)))
if do_auto_update_check:
self.tagger.updatecheckmanager.check_update(show_always=False, update_level=config.setting["update_level"], callback=update_last_check_date)
self.auto_update_check()
self.metadata_box.restore_state()
def closeEvent(self, event):
@@ -551,7 +539,7 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
self.open_folder_action.triggered.connect(self.open_folder)
self.check_update_action = QtWidgets.QAction(_("&Check for Update"), self)
self.check_update_action.triggered.connect(self.check_for_update)
self.check_update_action.triggered.connect(self.do_update_check)
def toggle_rename_files(self, checked):
config.setting["rename_files"] = checked
@@ -1108,10 +1096,36 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
self.tagger.paste_files(target)
self.paste_action.setEnabled(False)
def check_for_update(self):
self.tagger.updatecheckmanager.check_update(show_always=True, update_level=config.setting["update_level"], callback=update_last_check_date)
def do_update_check(self):
self.check_for_update(True)
def auto_update_check(self):
check_for_updates = config.setting['check_for_updates']
update_check_days = config.setting['update_check_days']
last_update_check = config.persist['last_update_check']
update_level = config.setting['update_level']
today = datetime.date.today().toordinal()
do_auto_update_check = check_for_updates and update_check_days > 0 and today >= last_update_check + update_check_days
log.debug('{check_status} start-up check for program updates. Today: {today_date}, Last check: {last_check} (Check interval: {check_interval} days), Update level: {update_level} ({update_level_name})'.format(
check_status='Initiating' if do_auto_update_check else 'Skipping',
today_date=datetime.date.today(),
last_check=str(datetime.date.fromordinal(last_update_check)) if last_update_check > 0 else 'never',
check_interval=update_check_days,
update_level=update_level,
update_level_name=PROGRAM_UPDATE_LEVELS[update_level]['name'] if update_level in PROGRAM_UPDATE_LEVELS else 'unknown',
))
if do_auto_update_check:
self.check_for_update(False)
def check_for_update(self, show_always):
self.tagger.updatecheckmanager.check_update(
show_always=show_always,
update_level=config.setting['update_level'],
callback=update_last_check_date
)
def update_last_check_date(is_success):
log.debug('Processing update_last_check_date callback with argument: %s' % (is_success,))
if is_success:
config.persist['last_update_check'] = datetime.date.today().toordinal()
else:
log.debug('The update check was unsuccessful. The last update date will not be changed.')

View File

@@ -20,12 +20,12 @@
from PyQt5 import QtCore
from PyQt5.QtWidgets import QInputDialog
from picard import (
config,
from picard import config
from picard.collection import load_user_collections
from picard.const import (
MUSICBRAINZ_SERVERS,
PROGRAM_UPDATE_LEVELS,
)
from picard.collection import load_user_collections
from picard.const import MUSICBRAINZ_SERVERS
from picard.util import webbrowser2
from picard.ui.options import (
@@ -76,14 +76,9 @@ class GeneralOptionsPage(OptionsPage):
self.ui.ignore_file_mbids.setChecked(config.setting["ignore_file_mbids"])
self.ui.check_for_updates.setChecked(config.setting["check_for_updates"])
self.ui.update_level.clear()
index = 0
for key in PROGRAM_UPDATE_LEVELS.keys():
self.ui.update_level.addItem(
_(PROGRAM_UPDATE_LEVELS[key]['title']),
PROGRAM_UPDATE_LEVELS[key]['level'])
if PROGRAM_UPDATE_LEVELS[key]['level'] == config.setting["update_level"]:
self.ui.update_level.setCurrentIndex(index)
index += 1
for level, description in PROGRAM_UPDATE_LEVELS.items():
self.ui.update_level.addItem(_(description['title']), level)
self.ui.update_level.setCurrentIndex(self.ui.update_level.findData(config.setting["update_level"]))
self.ui.update_check_days.setValue(config.setting["update_check_days"])
def save(self):

View File

@@ -8,7 +8,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_GeneralOptionsPage(object):
def setupUi(self, GeneralOptionsPage):
GeneralOptionsPage.setObjectName("GeneralOptionsPage")
GeneralOptionsPage.resize(304, 435)
GeneralOptionsPage.resize(283, 435)
self.vboxlayout = QtWidgets.QVBoxLayout(GeneralOptionsPage)
self.vboxlayout.setObjectName("vboxlayout")
self.groupBox = QtWidgets.QGroupBox(GeneralOptionsPage)
@@ -116,9 +116,6 @@ class Ui_GeneralOptionsPage(object):
self.update_level.setSizePolicy(sizePolicy)
self.update_level.setEditable(False)
self.update_level.setObjectName("update_level")
self.update_level.addItem("")
self.update_level.addItem("")
self.update_level.addItem("")
self.gridLayout_2.addWidget(self.update_level, 0, 1, 1, 1)
self.verticalLayout_2.addLayout(self.gridLayout_2)
self.vboxlayout.addWidget(self.groupBox_3)
@@ -126,7 +123,6 @@ class Ui_GeneralOptionsPage(object):
self.vboxlayout.addItem(spacerItem1)
self.retranslateUi(GeneralOptionsPage)
self.update_level.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(GeneralOptionsPage)
GeneralOptionsPage.setTabOrder(self.server_host, self.server_port)
@@ -145,7 +141,4 @@ class Ui_GeneralOptionsPage(object):
self.check_for_updates.setText(_("Check for updates during start-up"))
self.label_2.setText(_("Days between checks:"))
self.label_3.setText(_("Updates to check:"))
self.update_level.setItemText(0, _("Stable releases only"))
self.update_level.setItemText(1, _("Stable and Beta releases"))
self.update_level.setItemText(2, _("Stable, Beta and Dev releases"))

View File

@@ -17,25 +17,25 @@
# 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 import (PICARD_VERSION, PICARD_FANCY_VERSION_STR, PROGRAM_UPDATE_LEVELS, log)
import picard.util.webbrowser2 as wb2
from functools import partial
from PyQt5 import QtCore
from PyQt5.QtWidgets import QMessageBox
from picard.util import load_json, compare_version_tuples
from functools import partial
import re
# Used to strip leading and trailing text from version string.
_RE_CLEAN_VERSION = re.compile('^[^0-9]*(.*)[^0-9]*$', re.IGNORECASE)
# GitHub API information
VERSIONS_API = {
'host': 'picard.musicbrainz.org',
'port': 443,
'endpoint': '/api/releases'
}
from picard import (
PICARD_FANCY_VERSION_STR,
PICARD_VERSION,
log,
)
from picard.const import (
PLUGINS_API,
PROGRAM_UPDATE_LEVELS,
)
from picard.util import (
compare_version_tuples,
load_json,
webbrowser2,
)
class UpdateCheckManager(QtCore.QObject):
@@ -43,21 +43,7 @@ class UpdateCheckManager(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent=parent)
self._parent = parent
# PICARD_VERSIONS dictionary valid keys are: 'stable', 'beta' and 'dev'.
# Each of these keys contains a dictionary with the keys: 'tag' (string),
# 'version' (tuple) and 'urls' (dictionary). The 'version' tuple comprises
# major (int), minor (int), micro (int), type (str) and development (int)
# as defined in PEP-440. The Picard developers have standardized on using
# only 'dev' or 'final' as the str_type segment of the version tuple. Each
# key in the 'urls' dictionary contains a string with the specified url.
# Valid keys include: 'download' and 'changelog'. The only required key in
# the 'urls' dictionary is 'download'.
# Initialize empty dictionary for 'stable' key
self._available_versions = {
'stable': { 'tag': '', 'version': (0, 0, 0, 'dev', 0), 'urls': {'download': ''} },
}
self._available_versions = {}
self._show_always = False
self._update_level = 0
@@ -88,25 +74,20 @@ class UpdateCheckManager(QtCore.QObject):
self._show_always = show_always
self._update_level = update_level
if self._available_versions['stable']['tag']:
if self._available_versions:
# Release information already acquired from specified website api.
self._display_results()
else:
# Gets list of releases from specified website api.
self._query_available_updates(callback=callback)
@property
def available_versions(self):
'''Provide a list of the latest version tuples for each update type.'''
return self._available_versions
def _query_available_updates(self, callback=None):
'''Gets list of releases from specified website api.'''
log.debug(_("Getting release information from {host_url}.".format(host_url=VERSIONS_API['host'],)))
log.debug("Getting Picard release information from {host_url}".format(host_url=PLUGINS_API['host'],))
self.tagger.webservice.get(
VERSIONS_API['host'],
VERSIONS_API['port'],
VERSIONS_API['endpoint'],
PLUGINS_API['host'],
PLUGINS_API['port'],
PLUGINS_API['endpoint']['releases'],
partial(self._releases_json_loaded, callback=callback),
parse_response_type=None,
priority=True,
@@ -116,16 +97,19 @@ class UpdateCheckManager(QtCore.QObject):
def _releases_json_loaded(self, response, reply, error, callback=None):
'''Processes response from specified website api query.'''
if error:
log.error(N_("Error loading releases list: {error_message}".format(error_message=reply.errorString(),)))
log.error(_("Error loading Picard releases list: {error_message}").format(error_message=reply.errorString(),))
if self._show_always:
QMessageBox.information(
self._parent,
_("Picard Update"),
_("Unable to retrieve the latest version information."),
_("Unable to retrieve the latest version information from the website.\n(https://{url}{endpoint})").format(
url=PLUGINS_API['host'],
endpoint=PLUGINS_API['endpoint']['releases'],
),
QMessageBox.Ok, QMessageBox.Ok)
else:
self._available_versions = load_json(response)['versions']
for key in self._available_versions.keys():
for key in self._available_versions:
log.debug("Version key '{version_key}' --> {version_information}".format(
version_key=key, version_information=self._available_versions[key],))
self._display_results()
@@ -136,16 +120,17 @@ class UpdateCheckManager(QtCore.QObject):
# Display results to user.
key = ''
high_version = PICARD_VERSION
for test_key in PROGRAM_UPDATE_LEVELS.keys():
if self._update_level >= PROGRAM_UPDATE_LEVELS[test_key]['level'] and compare_version_tuples(high_version, self._available_versions[test_key]['version']) > 0:
key = test_key
high_version = self._available_versions[test_key]['version']
for test_key in PROGRAM_UPDATE_LEVELS:
test_version = self._available_versions[PROGRAM_UPDATE_LEVELS[test_key]['name']]['version']
if self._update_level >= test_key and compare_version_tuples(high_version, test_version) > 0:
key = PROGRAM_UPDATE_LEVELS[test_key]['name']
high_version = test_version
if key:
if QMessageBox.information(
self._parent,
_("Picard Update"),
_("A new version of Picard is available.\n\n"
"Old version: {picard_old_version}\n"
"This version: {picard_old_version}\n"
"New version: {picard_new_version}\n\n"
"Would you like to download the new version?").format(
picard_old_version=PICARD_FANCY_VERSION_STR,
@@ -154,18 +139,15 @@ class UpdateCheckManager(QtCore.QObject):
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Cancel
) == QMessageBox.Ok:
wb2.open(self._available_versions[key]['urls']['download'])
webbrowser2.open(self._available_versions[key]['urls']['download'])
else:
if self._show_always:
for key in PROGRAM_UPDATE_LEVELS.keys():
if self._update_level == PROGRAM_UPDATE_LEVELS[key]['level']:
update_level_text = PROGRAM_UPDATE_LEVELS[key]['title']
QMessageBox.information(
self._parent,
_("Picard Update"),
_("There is no update currently available for your subscribed update level: {update_level}\n\n"
"Your version: {picard_old_version}\n").format(
update_level=_(update_level_text if update_level_text else 'unknown'),
update_level=_(PROGRAM_UPDATE_LEVELS[self._update_level]['title']) if self._update_level in PROGRAM_UPDATE_LEVELS else _('unknown'),
picard_old_version=PICARD_FANCY_VERSION_STR,
),
QMessageBox.Ok, QMessageBox.Ok

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<width>283</width>
<height>435</height>
</rect>
</property>
@@ -213,24 +213,6 @@
<property name="editable">
<bool>false</bool>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Stable releases only</string>
</property>
</item>
<item>
<property name="text">
<string>Stable and Beta releases</string>
</property>
</item>
<item>
<property name="text">
<string>Stable, Beta and Dev releases</string>
</property>
</item>
</widget>
</item>
</layout>