mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
convert qt strings to f-strings with flynt
Also revealed an incorrect type def in editor.py that mypy wasn't noticing before :-(
This commit is contained in:
parent
5ab115c145
commit
88c002f4eb
30 changed files with 169 additions and 181 deletions
|
@ -232,7 +232,7 @@ def setupLangAndBackend(
|
||||||
else:
|
else:
|
||||||
qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
|
qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
|
||||||
qt_lang = lang.replace("-", "_")
|
qt_lang = lang.replace("-", "_")
|
||||||
if _qtrans.load("qtbase_" + qt_lang, qt_dir):
|
if _qtrans.load(f"qtbase_{qt_lang}", qt_dir):
|
||||||
app.installTranslator(_qtrans)
|
app.installTranslator(_qtrans)
|
||||||
|
|
||||||
return anki.lang.current_i18n
|
return anki.lang.current_i18n
|
||||||
|
@ -249,7 +249,7 @@ class AnkiApp(QApplication):
|
||||||
|
|
||||||
appMsg = pyqtSignal(str)
|
appMsg = pyqtSignal(str)
|
||||||
|
|
||||||
KEY = "anki" + checksum(getpass.getuser())
|
KEY = f"anki{checksum(getpass.getuser())}"
|
||||||
TMOUT = 30000
|
TMOUT = 30000
|
||||||
|
|
||||||
def __init__(self, argv: List[str]) -> None:
|
def __init__(self, argv: List[str]) -> None:
|
||||||
|
@ -319,7 +319,7 @@ def parseArgs(argv: List[str]) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
# as there's no such profile
|
# as there's no such profile
|
||||||
if isMac and len(argv) > 1 and argv[1].startswith("-psn"):
|
if isMac and len(argv) > 1 and argv[1].startswith("-psn"):
|
||||||
argv = [argv[0]]
|
argv = [argv[0]]
|
||||||
parser = argparse.ArgumentParser(description="Anki " + appVersion)
|
parser = argparse.ArgumentParser(description=f"Anki {appVersion}")
|
||||||
parser.usage = "%(prog)s [OPTIONS] [file to import/add-on to install]"
|
parser.usage = "%(prog)s [OPTIONS] [file to import/add-on to install]"
|
||||||
parser.add_argument("-b", "--base", help="path to base folder", default="")
|
parser.add_argument("-b", "--base", help="path to base folder", default="")
|
||||||
parser.add_argument("-p", "--profile", help="profile name to load", default="")
|
parser.add_argument("-p", "--profile", help="profile name to load", default="")
|
||||||
|
@ -424,7 +424,7 @@ def run() -> None:
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
None,
|
None,
|
||||||
"Startup Error",
|
"Startup Error",
|
||||||
"Please notify support of this error:\n\n" + traceback.format_exc(),
|
f"Please notify support of this error:\n\n{traceback.format_exc()}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
||||||
(add-on provided name [Add-on folder, installed at, version, is config changed])
|
(add-on provided name [Add-on folder, installed at, version, is config changed])
|
||||||
{newline.join(sorted(inactive))}
|
{newline.join(sorted(inactive))}
|
||||||
"""
|
"""
|
||||||
info = " " + " ".join(info.splitlines(True))
|
info = f" {' '.join(info.splitlines(True))}"
|
||||||
QApplication.clipboard().setText(info)
|
QApplication.clipboard().setText(info)
|
||||||
tooltip(tr(TR.ABOUT_COPIED_TO_CLIPBOARD), parent=dialog)
|
tooltip(tr(TR.ABOUT_COPIED_TO_CLIPBOARD), parent=dialog)
|
||||||
|
|
||||||
|
@ -93,9 +93,9 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
||||||
# WebView contents
|
# WebView contents
|
||||||
######################################################################
|
######################################################################
|
||||||
abouttext = "<center><img src='/_anki/imgs/anki-logo-thin.png'></center>"
|
abouttext = "<center><img src='/_anki/imgs/anki-logo-thin.png'></center>"
|
||||||
abouttext += "<p>" + tr(TR.ABOUT_ANKI_IS_A_FRIENDLY_INTELLIGENT_SPACED)
|
abouttext += f"<p>{tr(TR.ABOUT_ANKI_IS_A_FRIENDLY_INTELLIGENT_SPACED)}"
|
||||||
abouttext += "<p>" + tr(TR.ABOUT_ANKI_IS_LICENSED_UNDER_THE_AGPL3)
|
abouttext += f"<p>{tr(TR.ABOUT_ANKI_IS_LICENSED_UNDER_THE_AGPL3)}"
|
||||||
abouttext += "<p>" + tr(TR.ABOUT_VERSION, val=versionWithBuild()) + "<br>"
|
abouttext += f"<p>{tr(TR.ABOUT_VERSION, val=versionWithBuild())}<br>"
|
||||||
abouttext += ("Python %s Qt %s PyQt %s<br>") % (
|
abouttext += ("Python %s Qt %s PyQt %s<br>") % (
|
||||||
platform.python_version(),
|
platform.python_version(),
|
||||||
QT_VERSION_STR,
|
QT_VERSION_STR,
|
||||||
|
@ -211,8 +211,8 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
||||||
abouttext += "<p>" + tr(
|
abouttext += "<p>" + tr(
|
||||||
TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES, cont=", ".join(allusers)
|
TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES, cont=", ".join(allusers)
|
||||||
)
|
)
|
||||||
abouttext += "<p>" + tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE)
|
abouttext += f"<p>{tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE)}"
|
||||||
abouttext += "<p>" + tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE)
|
abouttext += f"<p>{tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE)}"
|
||||||
abt.label.setMinimumWidth(800)
|
abt.label.setMinimumWidth(800)
|
||||||
abt.label.setMinimumHeight(600)
|
abt.label.setMinimumHeight(600)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
|
@ -84,7 +84,7 @@ class AddCards(QDialog):
|
||||||
self.helpButton.setAutoDefault(False)
|
self.helpButton.setAutoDefault(False)
|
||||||
bb.addButton(self.helpButton, QDialogButtonBox.HelpRole)
|
bb.addButton(self.helpButton, QDialogButtonBox.HelpRole)
|
||||||
# history
|
# history
|
||||||
b = bb.addButton(tr(TR.ADDING_HISTORY) + " " + downArrow(), ar)
|
b = bb.addButton(f"{tr(TR.ADDING_HISTORY)} {downArrow()}", ar)
|
||||||
if isMac:
|
if isMac:
|
||||||
sc = "Ctrl+Shift+H"
|
sc = "Ctrl+Shift+H"
|
||||||
else:
|
else:
|
||||||
|
@ -149,7 +149,7 @@ class AddCards(QDialog):
|
||||||
fields = note.fields
|
fields = note.fields
|
||||||
txt = htmlToTextLine(", ".join(fields))
|
txt = htmlToTextLine(", ".join(fields))
|
||||||
if len(txt) > 30:
|
if len(txt) > 30:
|
||||||
txt = txt[:30] + "..."
|
txt = f"{txt[:30]}..."
|
||||||
line = tr(TR.ADDING_EDIT, val=txt)
|
line = tr(TR.ADDING_EDIT, val=txt)
|
||||||
line = gui_hooks.addcards_will_add_history_entry(line, note)
|
line = gui_hooks.addcards_will_add_history_entry(line, note)
|
||||||
a = m.addAction(line)
|
a = m.addAction(line)
|
||||||
|
|
|
@ -309,7 +309,7 @@ class AddonManager:
|
||||||
meta = self.addon_meta(dir)
|
meta = self.addon_meta(dir)
|
||||||
name = meta.human_name()
|
name = meta.human_name()
|
||||||
if not meta.enabled:
|
if not meta.enabled:
|
||||||
name += " " + tr(TR.ADDONS_DISABLED)
|
name += f" {tr(TR.ADDONS_DISABLED)}"
|
||||||
return name
|
return name
|
||||||
|
|
||||||
# Conflict resolution
|
# Conflict resolution
|
||||||
|
@ -741,11 +741,9 @@ class AddonsDialog(QDialog):
|
||||||
name = addon.human_name()
|
name = addon.human_name()
|
||||||
|
|
||||||
if not addon.enabled:
|
if not addon.enabled:
|
||||||
return name + " " + tr(TR.ADDONS_DISABLED2)
|
return f"{name} {tr(TR.ADDONS_DISABLED2)}"
|
||||||
elif not addon.compatible():
|
elif not addon.compatible():
|
||||||
return (
|
return f"{name} {tr(TR.ADDONS_REQUIRES, val=self.compatible_string(addon))}"
|
||||||
name + " " + tr(TR.ADDONS_REQUIRES, val=self.compatible_string(addon))
|
|
||||||
)
|
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@ -818,7 +816,7 @@ class AddonsDialog(QDialog):
|
||||||
if not addon:
|
if not addon:
|
||||||
return
|
return
|
||||||
if re.match(r"^\d+$", addon):
|
if re.match(r"^\d+$", addon):
|
||||||
openLink(aqt.appShared + f"info/{addon}")
|
openLink(f"{aqt.appShared}info/{addon}")
|
||||||
else:
|
else:
|
||||||
showWarning(tr(TR.ADDONS_ADDON_WAS_NOT_DOWNLOADED_FROM_ANKIWEB))
|
showWarning(tr(TR.ADDONS_ADDON_WAS_NOT_DOWNLOADED_FROM_ANKIWEB))
|
||||||
|
|
||||||
|
@ -864,7 +862,7 @@ class AddonsDialog(QDialog):
|
||||||
|
|
||||||
def onInstallFiles(self, paths: Optional[List[str]] = None) -> Optional[bool]:
|
def onInstallFiles(self, paths: Optional[List[str]] = None) -> Optional[bool]:
|
||||||
if not paths:
|
if not paths:
|
||||||
key = tr(TR.ADDONS_PACKAGED_ANKI_ADDON) + f" (*{self.mgr.ext})"
|
key = f"{tr(TR.ADDONS_PACKAGED_ANKI_ADDON)} (*{self.mgr.ext})"
|
||||||
paths_ = getFile(
|
paths_ = getFile(
|
||||||
self, tr(TR.ADDONS_INSTALL_ADDONS), None, key, key="addons", multi=True
|
self, tr(TR.ADDONS_INSTALL_ADDONS), None, key, key="addons", multi=True
|
||||||
)
|
)
|
||||||
|
@ -924,7 +922,7 @@ class GetAddons(QDialog):
|
||||||
saveGeom(self, "getaddons")
|
saveGeom(self, "getaddons")
|
||||||
|
|
||||||
def onBrowse(self) -> None:
|
def onBrowse(self) -> None:
|
||||||
openLink(aqt.appShared + "addons/2.1")
|
openLink(f"{aqt.appShared}addons/2.1")
|
||||||
|
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
# get codes
|
# get codes
|
||||||
|
@ -946,7 +944,7 @@ def download_addon(client: HttpClient, id: int) -> Union[DownloadOk, DownloadErr
|
||||||
"Fetch a single add-on from AnkiWeb."
|
"Fetch a single add-on from AnkiWeb."
|
||||||
try:
|
try:
|
||||||
resp = client.get(
|
resp = client.get(
|
||||||
aqt.appShared + f"download/{id}?v=2.1&p={current_point_version}"
|
f"{aqt.appShared}download/{id}?v=2.1&p={current_point_version}"
|
||||||
)
|
)
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
return DownloadError(status_code=resp.status_code)
|
return DownloadError(status_code=resp.status_code)
|
||||||
|
@ -1107,7 +1105,7 @@ def show_log_to_user(parent: QWidget, log: List[DownloadLogEntry]) -> None:
|
||||||
text = tr(TR.ADDONS_ONE_OR_MORE_ERRORS_OCCURRED)
|
text = tr(TR.ADDONS_ONE_OR_MORE_ERRORS_OCCURRED)
|
||||||
else:
|
else:
|
||||||
text = tr(TR.ADDONS_DOWNLOAD_COMPLETE_PLEASE_RESTART_ANKI_TO)
|
text = tr(TR.ADDONS_DOWNLOAD_COMPLETE_PLEASE_RESTART_ANKI_TO)
|
||||||
text += "<br><br>" + download_log_to_html(log)
|
text += f"<br><br>{download_log_to_html(log)}"
|
||||||
|
|
||||||
if have_problem:
|
if have_problem:
|
||||||
showWarning(text, textFormat="rich", parent=parent)
|
showWarning(text, textFormat="rich", parent=parent)
|
||||||
|
@ -1153,7 +1151,7 @@ def _fetch_update_info_batch(
|
||||||
"""Get update info from AnkiWeb.
|
"""Get update info from AnkiWeb.
|
||||||
|
|
||||||
Chunk must not contain more than 25 ids."""
|
Chunk must not contain more than 25 ids."""
|
||||||
resp = client.get(aqt.appShared + "updates/" + ",".join(chunk) + "?v=3")
|
resp = client.get(f"{aqt.appShared}updates/{','.join(chunk)}?v=3")
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
return resp.json()
|
return resp.json()
|
||||||
else:
|
else:
|
||||||
|
@ -1366,7 +1364,7 @@ class ConfigEditor(QDialog):
|
||||||
showInfo(msg)
|
showInfo(msg)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
showInfo(tr(TR.ADDONS_INVALID_CONFIGURATION) + " " + repr(e))
|
showInfo(f"{tr(TR.ADDONS_INVALID_CONFIGURATION)} {repr(e)}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not isinstance(new_conf, dict):
|
if not isinstance(new_conf, dict):
|
||||||
|
@ -1419,7 +1417,7 @@ def installAddonPackages(
|
||||||
if log:
|
if log:
|
||||||
log_html = "<br>".join(log)
|
log_html = "<br>".join(log)
|
||||||
if advise_restart:
|
if advise_restart:
|
||||||
log_html += "<br><br>" + tr(TR.ADDONS_PLEASE_RESTART_ANKI_TO_COMPLETE_THE)
|
log_html += f"<br><br>{tr(TR.ADDONS_PLEASE_RESTART_ANKI_TO_COMPLETE_THE)}"
|
||||||
if len(log) == 1 and not strictly_modal:
|
if len(log) == 1 and not strictly_modal:
|
||||||
tooltip(log_html, parent=parent)
|
tooltip(log_html, parent=parent)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -115,7 +115,7 @@ class CardLayout(QDialog):
|
||||||
self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
|
self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
|
||||||
self.topAreaForm.setupUi(self.topArea)
|
self.topAreaForm.setupUi(self.topArea)
|
||||||
self.topAreaForm.templateOptions.setText(
|
self.topAreaForm.templateOptions.setText(
|
||||||
tr(TR.ACTIONS_OPTIONS) + " " + downArrow()
|
f"{tr(TR.ACTIONS_OPTIONS)} {downArrow()}"
|
||||||
)
|
)
|
||||||
qconnect(self.topAreaForm.templateOptions.clicked, self.onMore)
|
qconnect(self.topAreaForm.templateOptions.clicked, self.onMore)
|
||||||
qconnect(
|
qconnect(
|
||||||
|
@ -305,7 +305,7 @@ class CardLayout(QDialog):
|
||||||
qconnect(pform.preview_front.clicked, self.on_preview_toggled)
|
qconnect(pform.preview_front.clicked, self.on_preview_toggled)
|
||||||
qconnect(pform.preview_back.clicked, self.on_preview_toggled)
|
qconnect(pform.preview_back.clicked, self.on_preview_toggled)
|
||||||
pform.preview_settings.setText(
|
pform.preview_settings.setText(
|
||||||
tr(TR.CARD_TEMPLATES_PREVIEW_SETTINGS) + " " + downArrow()
|
f"{tr(TR.CARD_TEMPLATES_PREVIEW_SETTINGS)} {downArrow()}"
|
||||||
)
|
)
|
||||||
qconnect(pform.preview_settings.clicked, self.on_preview_settings)
|
qconnect(pform.preview_settings.clicked, self.on_preview_settings)
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ class CardLayout(QDialog):
|
||||||
text = a
|
text = a
|
||||||
|
|
||||||
# use _showAnswer to avoid the longer delay
|
# use _showAnswer to avoid the longer delay
|
||||||
self.preview_web.eval("_showAnswer(%s,'%s');" % (json.dumps(text), bodyclass))
|
self.preview_web.eval(f"_showAnswer({json.dumps(text)},'{bodyclass}');")
|
||||||
self.preview_web.eval(
|
self.preview_web.eval(
|
||||||
f"_emulateMobile({json.dumps(self.mobile_emulation_enabled)});"
|
f"_emulateMobile({json.dumps(self.mobile_emulation_enabled)});"
|
||||||
)
|
)
|
||||||
|
@ -522,14 +522,14 @@ class CardLayout(QDialog):
|
||||||
def answerRepl(match: Match) -> str:
|
def answerRepl(match: Match) -> str:
|
||||||
res = self.mw.reviewer.correct("exomple", "an example")
|
res = self.mw.reviewer.correct("exomple", "an example")
|
||||||
if hadHR:
|
if hadHR:
|
||||||
res = "<hr id=answer>" + res
|
res = f"<hr id=answer>{res}"
|
||||||
return res
|
return res
|
||||||
|
|
||||||
repl: Union[str, Callable]
|
repl: Union[str, Callable]
|
||||||
|
|
||||||
if type == "q":
|
if type == "q":
|
||||||
repl = "<input id='typeans' type=text value='exomple' readonly='readonly'>"
|
repl = "<input id='typeans' type=text value='exomple' readonly='readonly'>"
|
||||||
repl = "<center>%s</center>" % repl
|
repl = f"<center>{repl}</center>"
|
||||||
else:
|
else:
|
||||||
repl = answerRepl
|
repl = answerRepl
|
||||||
return re.sub(r"\[\[type:.+?\]\]", repl, txt)
|
return re.sub(r"\[\[type:.+?\]\]", repl, txt)
|
||||||
|
|
|
@ -59,7 +59,7 @@ class CustomStudy(QDialog):
|
||||||
def plus(num: Union[int, str]) -> str:
|
def plus(num: Union[int, str]) -> str:
|
||||||
if num == 1000:
|
if num == 1000:
|
||||||
num = "1000+"
|
num = "1000+"
|
||||||
return "<b>" + str(num) + "</b>"
|
return f"<b>{str(num)}</b>"
|
||||||
|
|
||||||
if idx == RADIO_NEW:
|
if idx == RADIO_NEW:
|
||||||
new = self.mw.col.sched.totalNewForCurrentDeck()
|
new = self.mw.col.sched.totalNewForCurrentDeck()
|
||||||
|
|
|
@ -288,7 +288,7 @@ class DeckBrowser:
|
||||||
|
|
||||||
extra = tr(TR.DECKS_IT_HAS_CARD, count=count)
|
extra = tr(TR.DECKS_IT_HAS_CARD, count=count)
|
||||||
if askUser(
|
if askUser(
|
||||||
tr(TR.DECKS_ARE_YOU_SURE_YOU_WISH_TO, val=deck["name"]) + " " + extra
|
f"{tr(TR.DECKS_ARE_YOU_SURE_YOU_WISH_TO, val=deck['name'])} {extra}"
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -332,4 +332,4 @@ class DeckBrowser:
|
||||||
)
|
)
|
||||||
|
|
||||||
def _onShared(self) -> None:
|
def _onShared(self) -> None:
|
||||||
openLink(aqt.appShared + "decks/")
|
openLink(f"{aqt.appShared}decks/")
|
||||||
|
|
|
@ -130,7 +130,7 @@ class Editor:
|
||||||
None,
|
None,
|
||||||
"fields",
|
"fields",
|
||||||
tr(TR.EDITING_CUSTOMIZE_FIELDS),
|
tr(TR.EDITING_CUSTOMIZE_FIELDS),
|
||||||
tr(TR.EDITING_FIELDS) + "...",
|
f"{tr(TR.EDITING_FIELDS)}...",
|
||||||
disables=False,
|
disables=False,
|
||||||
rightside=False,
|
rightside=False,
|
||||||
),
|
),
|
||||||
|
@ -138,7 +138,7 @@ class Editor:
|
||||||
None,
|
None,
|
||||||
"cards",
|
"cards",
|
||||||
tr(TR.EDITING_CUSTOMIZE_CARD_TEMPLATES_CTRLANDL),
|
tr(TR.EDITING_CUSTOMIZE_CARD_TEMPLATES_CTRLANDL),
|
||||||
tr(TR.EDITING_CARDS) + "...",
|
f"{tr(TR.EDITING_CARDS)}...",
|
||||||
disables=False,
|
disables=False,
|
||||||
rightside=False,
|
rightside=False,
|
||||||
),
|
),
|
||||||
|
@ -239,7 +239,7 @@ class Editor:
|
||||||
with open(path, "rb") as fp:
|
with open(path, "rb") as fp:
|
||||||
data = fp.read()
|
data = fp.read()
|
||||||
data64 = b"".join(base64.encodebytes(data).splitlines())
|
data64 = b"".join(base64.encodebytes(data).splitlines())
|
||||||
return "data:%s;base64,%s" % (mime, data64.decode("ascii"))
|
return f"data:{mime};base64,{data64.decode('ascii')}"
|
||||||
|
|
||||||
def addButton(
|
def addButton(
|
||||||
self,
|
self,
|
||||||
|
@ -314,7 +314,7 @@ class Editor:
|
||||||
else:
|
else:
|
||||||
imgelm = ""
|
imgelm = ""
|
||||||
if label or not imgelm:
|
if label or not imgelm:
|
||||||
labelelm = """<span class=blabel>{}</span>""".format(label or cmd)
|
labelelm = f"""<span class=blabel>{label or cmd}</span>"""
|
||||||
else:
|
else:
|
||||||
labelelm = ""
|
labelelm = ""
|
||||||
if id:
|
if id:
|
||||||
|
@ -539,7 +539,7 @@ class Editor:
|
||||||
if err == 2:
|
if err == 2:
|
||||||
cols[0] = "dupe"
|
cols[0] = "dupe"
|
||||||
|
|
||||||
self.web.eval("setBackgrounds(%s);" % json.dumps(cols))
|
self.web.eval(f"setBackgrounds({json.dumps(cols)});")
|
||||||
|
|
||||||
def showDupes(self) -> None:
|
def showDupes(self) -> None:
|
||||||
aqt.dialogs.open(
|
aqt.dialogs.open(
|
||||||
|
@ -734,23 +734,23 @@ class Editor:
|
||||||
self._wrapWithColour(self.fcolour)
|
self._wrapWithColour(self.fcolour)
|
||||||
|
|
||||||
def _updateForegroundButton(self) -> None:
|
def _updateForegroundButton(self) -> None:
|
||||||
self.web.eval("setFGButton('%s')" % self.fcolour)
|
self.web.eval(f"setFGButton('{self.fcolour}')")
|
||||||
|
|
||||||
def onColourChanged(self) -> None:
|
def onColourChanged(self) -> None:
|
||||||
self._updateForegroundButton()
|
self._updateForegroundButton()
|
||||||
self.mw.pm.profile["lastColour"] = self.fcolour
|
self.mw.pm.profile["lastColour"] = self.fcolour
|
||||||
|
|
||||||
def _wrapWithColour(self, colour: str) -> None:
|
def _wrapWithColour(self, colour: str) -> None:
|
||||||
self.web.eval("setFormat('forecolor', '%s')" % colour)
|
self.web.eval(f"setFormat('forecolor', '{colour}')")
|
||||||
|
|
||||||
# Audio/video/images
|
# Audio/video/images
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def onAddMedia(self) -> None:
|
def onAddMedia(self) -> None:
|
||||||
extension_filter = " ".join(
|
extension_filter = " ".join(
|
||||||
"*." + extension for extension in sorted(itertools.chain(pics, audio))
|
f"*.{extension}" for extension in sorted(itertools.chain(pics, audio))
|
||||||
)
|
)
|
||||||
key = tr(TR.EDITING_MEDIA) + " (" + extension_filter + ")"
|
key = f"{tr(TR.EDITING_MEDIA)} ({extension_filter})"
|
||||||
|
|
||||||
def accept(file: str) -> None:
|
def accept(file: str) -> None:
|
||||||
self.addMedia(file, canDelete=True)
|
self.addMedia(file, canDelete=True)
|
||||||
|
@ -770,7 +770,7 @@ class Editor:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
showWarning(str(e))
|
showWarning(str(e))
|
||||||
return
|
return
|
||||||
self.web.eval("setFormat('inserthtml', %s);" % json.dumps(html))
|
self.web.eval(f"setFormat('inserthtml', {json.dumps(html)});")
|
||||||
|
|
||||||
def _addMedia(self, path: str, canDelete: bool = False) -> str:
|
def _addMedia(self, path: str, canDelete: bool = False) -> str:
|
||||||
"Add to media folder and return local img or sound tag."
|
"Add to media folder and return local img or sound tag."
|
||||||
|
@ -810,15 +810,15 @@ class Editor:
|
||||||
ext = fname.split(".")[-1].lower()
|
ext = fname.split(".")[-1].lower()
|
||||||
if ext in pics:
|
if ext in pics:
|
||||||
name = urllib.parse.quote(fname.encode("utf8"))
|
name = urllib.parse.quote(fname.encode("utf8"))
|
||||||
return '<img src="%s">' % name
|
return f'<img src="{name}">'
|
||||||
else:
|
else:
|
||||||
av_player.play_file(fname)
|
av_player.play_file(fname)
|
||||||
return "[sound:%s]" % html.escape(fname, quote=False)
|
return f"[sound:{html.escape(fname, quote=False)}]"
|
||||||
|
|
||||||
def urlToFile(self, url: str) -> Optional[str]:
|
def urlToFile(self, url: str) -> Optional[str]:
|
||||||
l = url.lower()
|
l = url.lower()
|
||||||
for suffix in pics + audio:
|
for suffix in pics + audio:
|
||||||
if l.endswith("." + suffix):
|
if l.endswith(f".{suffix}"):
|
||||||
return self._retrieveURL(url)
|
return self._retrieveURL(url)
|
||||||
# not a supported type
|
# not a supported type
|
||||||
return None
|
return None
|
||||||
|
@ -842,7 +842,7 @@ class Editor:
|
||||||
data = base64.b64decode(b64data, validate=True)
|
data = base64.b64decode(b64data, validate=True)
|
||||||
if ext == "jpeg":
|
if ext == "jpeg":
|
||||||
ext = "jpg"
|
ext = "jpg"
|
||||||
return self._addPastedImage(data, "." + ext)
|
return self._addPastedImage(data, f".{ext}")
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -857,7 +857,7 @@ class Editor:
|
||||||
def _addPastedImage(self, data: bytes, ext: str) -> str:
|
def _addPastedImage(self, data: bytes, ext: str) -> str:
|
||||||
# hash and write
|
# hash and write
|
||||||
csum = checksum(data)
|
csum = checksum(data)
|
||||||
fname = "{}-{}{}".format("paste", csum, ext)
|
fname = f"paste-{csum}{ext}"
|
||||||
return self._addMediaFromData(fname, data)
|
return self._addMediaFromData(fname, data)
|
||||||
|
|
||||||
def _retrieveURL(self, url: str) -> Optional[str]:
|
def _retrieveURL(self, url: str) -> Optional[str]:
|
||||||
|
@ -967,9 +967,7 @@ class Editor:
|
||||||
ext = "true"
|
ext = "true"
|
||||||
else:
|
else:
|
||||||
ext = "false"
|
ext = "false"
|
||||||
self.web.eval(
|
self.web.eval(f"pasteHTML({json.dumps(html)}, {json.dumps(internal)}, {ext});")
|
||||||
"pasteHTML(%s, %s, %s);" % (json.dumps(html), json.dumps(internal), ext)
|
|
||||||
)
|
|
||||||
|
|
||||||
def doDrop(self, html: str, internal: bool, extended: bool = False) -> None:
|
def doDrop(self, html: str, internal: bool, extended: bool = False) -> None:
|
||||||
def pasteIfField(ret: bool) -> None:
|
def pasteIfField(ret: bool) -> None:
|
||||||
|
@ -1187,8 +1185,8 @@ class EditorWebView(AnkiWebView):
|
||||||
token = html.escape(token).replace("\t", " " * 4)
|
token = html.escape(token).replace("\t", " " * 4)
|
||||||
# if there's more than one consecutive space,
|
# if there's more than one consecutive space,
|
||||||
# use non-breaking spaces for the second one on
|
# use non-breaking spaces for the second one on
|
||||||
def repl(match: Match) -> None:
|
def repl(match: Match) -> str:
|
||||||
return match.group(1).replace(" ", " ") + " "
|
return f"{match.group(1).replace(' ', ' ')} "
|
||||||
|
|
||||||
token = re.sub(" ( +)", repl, token)
|
token = re.sub(" ( +)", repl, token)
|
||||||
processed.append(token)
|
processed.append(token)
|
||||||
|
@ -1247,7 +1245,7 @@ class EditorWebView(AnkiWebView):
|
||||||
if not mime.hasHtml():
|
if not mime.hasHtml():
|
||||||
return
|
return
|
||||||
html = mime.html()
|
html = mime.html()
|
||||||
mime.setHtml("<!--anki-->" + html)
|
mime.setHtml(f"<!--anki-->{html}")
|
||||||
clip.setMimeData(mime)
|
clip.setMimeData(mime)
|
||||||
|
|
||||||
def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
|
def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
|
||||||
|
|
|
@ -95,13 +95,13 @@ class ErrorHandler(QObject):
|
||||||
|
|
||||||
if self.mw.addonManager.dirty:
|
if self.mw.addonManager.dirty:
|
||||||
txt = markdown(tr(TR.ERRORS_ADDONS_ACTIVE_POPUP))
|
txt = markdown(tr(TR.ERRORS_ADDONS_ACTIVE_POPUP))
|
||||||
error = supportText() + self._addonText(error) + "\n" + error
|
error = f"{supportText() + self._addonText(error)}\n{error}"
|
||||||
else:
|
else:
|
||||||
txt = markdown(tr(TR.ERRORS_STANDARD_POPUP))
|
txt = markdown(tr(TR.ERRORS_STANDARD_POPUP))
|
||||||
error = supportText() + "\n" + error
|
error = f"{supportText()}\n{error}"
|
||||||
|
|
||||||
# show dialog
|
# show dialog
|
||||||
txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
|
txt = f"{txt}<div style='white-space: pre-wrap'>{error}</div>"
|
||||||
showText(txt, type="html", copyBtn=True)
|
showText(txt, type="html", copyBtn=True)
|
||||||
|
|
||||||
def _addonText(self, error: str) -> str:
|
def _addonText(self, error: str) -> str:
|
||||||
|
@ -113,6 +113,6 @@ class ErrorHandler(QObject):
|
||||||
mw.addonManager.addonName(i) for i in dict.fromkeys(reversed(matches))
|
mw.addonManager.addonName(i) for i in dict.fromkeys(reversed(matches))
|
||||||
]
|
]
|
||||||
# highlight importance of first add-on:
|
# highlight importance of first add-on:
|
||||||
addons[0] = "<b>{}</b>".format(addons[0])
|
addons[0] = f"<b>{addons[0]}</b>"
|
||||||
addons_str = ", ".join(addons)
|
addons_str = ", ".join(addons)
|
||||||
return tr(TR.ADDONS_POSSIBLY_INVOLVED, addons=addons_str) + "\n"
|
return f"{tr(TR.ADDONS_POSSIBLY_INVOLVED, addons=addons_str)}\n"
|
||||||
|
|
|
@ -60,7 +60,7 @@ class FieldDialog(QDialog):
|
||||||
self.currentIdx = None
|
self.currentIdx = None
|
||||||
self.form.fieldList.clear()
|
self.form.fieldList.clear()
|
||||||
for c, f in enumerate(self.model["flds"]):
|
for c, f in enumerate(self.model["flds"]):
|
||||||
self.form.fieldList.addItem("{}: {}".format(c + 1, f["name"]))
|
self.form.fieldList.addItem(f"{c + 1}: {f['name']}")
|
||||||
|
|
||||||
def setupSignals(self) -> None:
|
def setupSignals(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
|
@ -244,7 +244,7 @@ class FieldDialog(QDialog):
|
||||||
fut.result()
|
fut.result()
|
||||||
except TemplateError as e:
|
except TemplateError as e:
|
||||||
# fixme: i18n
|
# fixme: i18n
|
||||||
showWarning("Unable to save changes: " + str(e))
|
showWarning(f"Unable to save changes: {str(e)}")
|
||||||
return
|
return
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
tooltip("Changes saved.", parent=self.mw)
|
tooltip("Changes saved.", parent=self.mw)
|
||||||
|
|
|
@ -194,7 +194,7 @@ class ImportDialog(QDialog):
|
||||||
showUnicodeWarning()
|
showUnicodeWarning()
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n"
|
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n"
|
||||||
err = repr(str(e))
|
err = repr(str(e))
|
||||||
if "1-character string" in err:
|
if "1-character string" in err:
|
||||||
msg += err
|
msg += err
|
||||||
|
@ -205,7 +205,7 @@ class ImportDialog(QDialog):
|
||||||
showText(msg)
|
showText(msg)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
txt = tr(TR.IMPORTING_IMPORTING_COMPLETE) + "\n"
|
txt = f"{tr(TR.IMPORTING_IMPORTING_COMPLETE)}\n"
|
||||||
if self.importer.log:
|
if self.importer.log:
|
||||||
txt += "\n".join(self.importer.log)
|
txt += "\n".join(self.importer.log)
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -326,7 +326,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
for mext in re.findall(r"[( ]?\*\.(.+?)[) ]", i[0]):
|
for mext in re.findall(r"[( ]?\*\.(.+?)[) ]", i[0]):
|
||||||
if file.endswith("." + mext):
|
if file.endswith(f".{mext}"):
|
||||||
importerClass = i[1]
|
importerClass = i[1]
|
||||||
done = True
|
done = True
|
||||||
break
|
break
|
||||||
|
@ -352,7 +352,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
if msg == "'unknownFormat'":
|
if msg == "'unknownFormat'":
|
||||||
showWarning(tr(TR.IMPORTING_UNKNOWN_FILE_FORMAT))
|
showWarning(tr(TR.IMPORTING_UNKNOWN_FILE_FORMAT))
|
||||||
else:
|
else:
|
||||||
msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n"
|
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n"
|
||||||
msg += str(traceback.format_exc())
|
msg += str(traceback.format_exc())
|
||||||
showText(msg)
|
showText(msg)
|
||||||
return
|
return
|
||||||
|
@ -392,7 +392,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
elif "readonly" in err:
|
elif "readonly" in err:
|
||||||
showWarning(tr(TR.IMPORTING_UNABLE_TO_IMPORT_FROM_A_READONLY))
|
showWarning(tr(TR.IMPORTING_UNABLE_TO_IMPORT_FROM_A_READONLY))
|
||||||
else:
|
else:
|
||||||
msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n"
|
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n"
|
||||||
msg += str(traceback.format_exc())
|
msg += str(traceback.format_exc())
|
||||||
showText(msg)
|
showText(msg)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -397,7 +397,7 @@ class AnkiQt(QMainWindow):
|
||||||
restoreGeom(self, "mainWindow")
|
restoreGeom(self, "mainWindow")
|
||||||
restoreState(self, "mainWindow")
|
restoreState(self, "mainWindow")
|
||||||
# titlebar
|
# titlebar
|
||||||
self.setWindowTitle(self.pm.name + " - Anki")
|
self.setWindowTitle(f"{self.pm.name} - Anki")
|
||||||
# show and raise window for osx
|
# show and raise window for osx
|
||||||
self.show()
|
self.show()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
|
@ -489,7 +489,7 @@ class AnkiQt(QMainWindow):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
showWarning(
|
showWarning(
|
||||||
tr(TR.ERRORS_UNABLE_OPEN_COLLECTION) + "\n" + traceback.format_exc()
|
f"{tr(TR.ERRORS_UNABLE_OPEN_COLLECTION)}\n{traceback.format_exc()}"
|
||||||
)
|
)
|
||||||
# clean up open collection if possible
|
# clean up open collection if possible
|
||||||
try:
|
try:
|
||||||
|
@ -643,14 +643,14 @@ class AnkiQt(QMainWindow):
|
||||||
def moveToState(self, state: str, *args: Any) -> None:
|
def moveToState(self, state: str, *args: Any) -> None:
|
||||||
# print("-> move from", self.state, "to", state)
|
# print("-> move from", self.state, "to", state)
|
||||||
oldState = self.state or "dummy"
|
oldState = self.state or "dummy"
|
||||||
cleanup = getattr(self, "_" + oldState + "Cleanup", None)
|
cleanup = getattr(self, f"_{oldState}Cleanup", None)
|
||||||
if cleanup:
|
if cleanup:
|
||||||
# pylint: disable=not-callable
|
# pylint: disable=not-callable
|
||||||
cleanup(state)
|
cleanup(state)
|
||||||
self.clearStateShortcuts()
|
self.clearStateShortcuts()
|
||||||
self.state = state
|
self.state = state
|
||||||
gui_hooks.state_will_change(state, oldState)
|
gui_hooks.state_will_change(state, oldState)
|
||||||
getattr(self, "_" + state + "State")(oldState, *args)
|
getattr(self, f"_{state}State")(oldState, *args)
|
||||||
if state != "resetRequired":
|
if state != "resetRequired":
|
||||||
self.bottomWeb.show()
|
self.bottomWeb.show()
|
||||||
gui_hooks.state_did_change(state, oldState)
|
gui_hooks.state_did_change(state, oldState)
|
||||||
|
@ -730,14 +730,13 @@ class AnkiQt(QMainWindow):
|
||||||
i = tr(TR.QT_MISC_WAITING_FOR_EDITING_TO_FINISH)
|
i = tr(TR.QT_MISC_WAITING_FOR_EDITING_TO_FINISH)
|
||||||
b = self.button("refresh", tr(TR.QT_MISC_RESUME_NOW), id="resume")
|
b = self.button("refresh", tr(TR.QT_MISC_RESUME_NOW), id="resume")
|
||||||
self.web.stdHtml(
|
self.web.stdHtml(
|
||||||
"""
|
f"""
|
||||||
<center><div style="height: 100%%">
|
<center><div style="height: 100%">
|
||||||
<div style="position:relative; vertical-align: middle;">
|
<div style="position:relative; vertical-align: middle;">
|
||||||
%s<br><br>
|
{i}<br><br>
|
||||||
%s</div></div></center>
|
{b}</div></div></center>
|
||||||
<script>$('#resume').focus()</script>
|
<script>$('#resume').focus()</script>
|
||||||
"""
|
""",
|
||||||
% (i, b),
|
|
||||||
context=web_context,
|
context=web_context,
|
||||||
)
|
)
|
||||||
self.bottomWeb.hide()
|
self.bottomWeb.hide()
|
||||||
|
@ -755,7 +754,7 @@ class AnkiQt(QMainWindow):
|
||||||
id: str = "",
|
id: str = "",
|
||||||
extra: str = "",
|
extra: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
class_ = "but " + class_
|
class_ = f"but {class_}"
|
||||||
if key:
|
if key:
|
||||||
key = tr(TR.ACTIONS_SHORTCUT_KEY, val=key)
|
key = tr(TR.ACTIONS_SHORTCUT_KEY, val=key)
|
||||||
else:
|
else:
|
||||||
|
@ -989,7 +988,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
def setStateShortcuts(self, shortcuts: List[Tuple[str, Callable]]) -> None:
|
def setStateShortcuts(self, shortcuts: List[Tuple[str, Callable]]) -> None:
|
||||||
gui_hooks.state_shortcuts_will_change(self.state, shortcuts)
|
gui_hooks.state_shortcuts_will_change(self.state, shortcuts)
|
||||||
# legacy hook
|
# legacy hook
|
||||||
runHook(self.state + "StateShortcuts", shortcuts)
|
runHook(f"{self.state}StateShortcuts", shortcuts)
|
||||||
self.stateShortcuts = self.applyShortcuts(shortcuts)
|
self.stateShortcuts = self.applyShortcuts(shortcuts)
|
||||||
|
|
||||||
def clearStateShortcuts(self) -> None:
|
def clearStateShortcuts(self) -> None:
|
||||||
|
@ -1285,7 +1284,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
if not existed:
|
if not existed:
|
||||||
f.write(b"nid\tmid\tfields\n")
|
f.write(b"nid\tmid\tfields\n")
|
||||||
for id, mid, flds in col.db.execute(
|
for id, mid, flds in col.db.execute(
|
||||||
"select id, mid, flds from notes where id in %s" % ids2str(nids)
|
f"select id, mid, flds from notes where id in {ids2str(nids)}"
|
||||||
):
|
):
|
||||||
fields = splitFields(flds)
|
fields = splitFields(flds)
|
||||||
f.write(("\t".join([str(id), str(mid)] + fields)).encode("utf8"))
|
f.write(("\t".join([str(id), str(mid)] + fields)).encode("utf8"))
|
||||||
|
@ -1471,9 +1470,9 @@ title="%s" %s>%s</button>""" % (
|
||||||
buf = ""
|
buf = ""
|
||||||
for c, line in enumerate(text.strip().split("\n")):
|
for c, line in enumerate(text.strip().split("\n")):
|
||||||
if c == 0:
|
if c == 0:
|
||||||
buf += ">>> %s\n" % line
|
buf += f">>> {line}\n"
|
||||||
else:
|
else:
|
||||||
buf += "... %s\n" % line
|
buf += f"... {line}\n"
|
||||||
try:
|
try:
|
||||||
to_append = buf + (self._output or "<no output>")
|
to_append = buf + (self._output or "<no output>")
|
||||||
to_append = gui_hooks.debug_console_did_evaluate_python(
|
to_append = gui_hooks.debug_console_did_evaluate_python(
|
||||||
|
@ -1616,7 +1615,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
self.mediaServer.start()
|
self.mediaServer.start()
|
||||||
|
|
||||||
def baseHTML(self) -> str:
|
def baseHTML(self) -> str:
|
||||||
return '<base href="%s">' % self.serverURL()
|
return f'<base href="{self.serverURL()}">'
|
||||||
|
|
||||||
def serverURL(self) -> str:
|
def serverURL(self) -> str:
|
||||||
return "http://127.0.0.1:%d/" % self.mediaServer.getPort()
|
return "http://127.0.0.1:%d/" % self.mediaServer.getPort()
|
||||||
|
|
|
@ -33,7 +33,7 @@ def _getExportFolder() -> str:
|
||||||
return webInSrcFolder
|
return webInSrcFolder
|
||||||
elif isMac:
|
elif isMac:
|
||||||
dir = os.path.dirname(os.path.abspath(__file__))
|
dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
return os.path.abspath(dir + "/../../Resources/web")
|
return os.path.abspath(f"{dir}/../../Resources/web")
|
||||||
else:
|
else:
|
||||||
if os.environ.get("TEST_TARGET"):
|
if os.environ.get("TEST_TARGET"):
|
||||||
# running tests in bazel; we have no data
|
# running tests in bazel; we have no data
|
||||||
|
@ -110,7 +110,7 @@ def allroutes(pathin: str) -> Response:
|
||||||
isdir = os.path.isdir(os.path.join(directory, path))
|
isdir = os.path.isdir(os.path.join(directory, path))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return flask.make_response(
|
return flask.make_response(
|
||||||
"Path for '%s - %s' is too long!" % (directory, path),
|
f"Path for '{directory} - {path}' is too long!",
|
||||||
HTTPStatus.BAD_REQUEST,
|
HTTPStatus.BAD_REQUEST,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,13 +121,13 @@ def allroutes(pathin: str) -> Response:
|
||||||
# protect against directory transversal: https://security.openstack.org/guidelines/dg_using-file-paths.html
|
# protect against directory transversal: https://security.openstack.org/guidelines/dg_using-file-paths.html
|
||||||
if not fullpath.startswith(directory):
|
if not fullpath.startswith(directory):
|
||||||
return flask.make_response(
|
return flask.make_response(
|
||||||
"Path for '%s - %s' is a security leak!" % (directory, path),
|
f"Path for '{directory} - {path}' is a security leak!",
|
||||||
HTTPStatus.FORBIDDEN,
|
HTTPStatus.FORBIDDEN,
|
||||||
)
|
)
|
||||||
|
|
||||||
if isdir:
|
if isdir:
|
||||||
return flask.make_response(
|
return flask.make_response(
|
||||||
"Path for '%s - %s' is a directory (not supported)!" % (directory, path),
|
f"Path for '{directory} - {path}' is a directory (not supported)!",
|
||||||
HTTPStatus.FORBIDDEN,
|
HTTPStatus.FORBIDDEN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ def _redirectWebExports(path: str) -> Tuple[str, str]:
|
||||||
addMgr = aqt.mw.addonManager
|
addMgr = aqt.mw.addonManager
|
||||||
except AttributeError as error:
|
except AttributeError as error:
|
||||||
if devMode:
|
if devMode:
|
||||||
print("_redirectWebExports: %s" % error)
|
print(f"_redirectWebExports: {error}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -128,7 +128,7 @@ class Models(QDialog):
|
||||||
self.models = notetypes
|
self.models = notetypes
|
||||||
for m in self.models:
|
for m in self.models:
|
||||||
mUse = tr(TR.BROWSING_NOTE_COUNT, count=m.use_count)
|
mUse = tr(TR.BROWSING_NOTE_COUNT, count=m.use_count)
|
||||||
item = QListWidgetItem("%s [%s]" % (m.name, mUse))
|
item = QListWidgetItem(f"{m.name} [{mUse}]")
|
||||||
self.form.modelsList.addItem(item)
|
self.form.modelsList.addItem(item)
|
||||||
self.form.modelsList.setCurrentRow(row)
|
self.form.modelsList.setCurrentRow(row)
|
||||||
|
|
||||||
|
|
|
@ -119,9 +119,9 @@ class MPVBase:
|
||||||
"""Prepare the argument list for the mpv process."""
|
"""Prepare the argument list for the mpv process."""
|
||||||
self.argv = [self.executable]
|
self.argv = [self.executable]
|
||||||
self.argv += self.default_argv
|
self.argv += self.default_argv
|
||||||
self.argv += ["--input-ipc-server=" + self._sock_filename]
|
self.argv += [f"--input-ipc-server={self._sock_filename}"]
|
||||||
if self.window_id is not None:
|
if self.window_id is not None:
|
||||||
self.argv += ["--wid=" + str(self.window_id)]
|
self.argv += [f"--wid={str(self.window_id)}"]
|
||||||
|
|
||||||
def _start_process(self):
|
def _start_process(self):
|
||||||
"""Start the mpv process."""
|
"""Start the mpv process."""
|
||||||
|
@ -258,7 +258,7 @@ class MPVBase:
|
||||||
buf = buf[newline + 1 :]
|
buf = buf[newline + 1 :]
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
sys.stdout.write("<<< " + data.decode("utf8", "replace"))
|
sys.stdout.write(f"<<< {data.decode('utf8', 'replace')}")
|
||||||
|
|
||||||
message = self._parse_message(data)
|
message = self._parse_message(data)
|
||||||
self._handle_message(message)
|
self._handle_message(message)
|
||||||
|
@ -298,7 +298,7 @@ class MPVBase:
|
||||||
self._event_queue.put(message)
|
self._event_queue.put(message)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise MPVCommunicationError("invalid message %r" % message)
|
raise MPVCommunicationError(f"invalid message {message!r}")
|
||||||
|
|
||||||
def _send_message(self, message, timeout=None):
|
def _send_message(self, message, timeout=None):
|
||||||
"""Send a message/command to the mpv process, message must be a
|
"""Send a message/command to the mpv process, message must be a
|
||||||
|
@ -308,7 +308,7 @@ class MPVBase:
|
||||||
data = self._compose_message(message)
|
data = self._compose_message(message)
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
sys.stdout.write(">>> " + data.decode("utf8", "replace"))
|
sys.stdout.write(f">>> {data.decode('utf8', 'replace')}")
|
||||||
|
|
||||||
# Request/response cycles are coordinated across different threads, so
|
# Request/response cycles are coordinated across different threads, so
|
||||||
# that they don't get mixed up. This makes it possible to use commands
|
# that they don't get mixed up. This makes it possible to use commands
|
||||||
|
@ -371,7 +371,7 @@ class MPVBase:
|
||||||
self._send_message(message, timeout)
|
self._send_message(message, timeout)
|
||||||
return self._get_response(timeout)
|
return self._get_response(timeout)
|
||||||
except MPVCommandError as e:
|
except MPVCommandError as e:
|
||||||
raise MPVCommandError("%r: %s" % (message["command"], e))
|
raise MPVCommandError(f"{message['command']!r}: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if _retry:
|
if _retry:
|
||||||
print("mpv timed out, restarting")
|
print("mpv timed out, restarting")
|
||||||
|
@ -512,7 +512,7 @@ class MPV(MPVBase):
|
||||||
return
|
return
|
||||||
|
|
||||||
if message["event"] == "property-change":
|
if message["event"] == "property-change":
|
||||||
name = "property-" + message["name"]
|
name = f"property-{message['name']}"
|
||||||
else:
|
else:
|
||||||
name = message["event"]
|
name = message["event"]
|
||||||
|
|
||||||
|
@ -527,7 +527,7 @@ class MPV(MPVBase):
|
||||||
try:
|
try:
|
||||||
self.command("enable_event", name)
|
self.command("enable_event", name)
|
||||||
except MPVCommandError:
|
except MPVCommandError:
|
||||||
raise MPVError("no such event %r" % name)
|
raise MPVError(f"no such event {name!r}")
|
||||||
|
|
||||||
self._callbacks.setdefault(name, []).append(callback)
|
self._callbacks.setdefault(name, []).append(callback)
|
||||||
|
|
||||||
|
@ -538,12 +538,12 @@ class MPV(MPVBase):
|
||||||
try:
|
try:
|
||||||
callbacks = self._callbacks[name]
|
callbacks = self._callbacks[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MPVError("no callbacks registered for event %r" % name)
|
raise MPVError(f"no callbacks registered for event {name!r}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
callbacks.remove(callback)
|
callbacks.remove(callback)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise MPVError("callback %r not registered for event %r" % (callback, name))
|
raise MPVError(f"callback {callback!r} not registered for event {name!r}")
|
||||||
|
|
||||||
def register_property_callback(self, name, callback):
|
def register_property_callback(self, name, callback):
|
||||||
"""Register a function `callback` for the property-change event on
|
"""Register a function `callback` for the property-change event on
|
||||||
|
@ -556,9 +556,9 @@ class MPV(MPVBase):
|
||||||
# Apparently observe_property does not check it :-(
|
# Apparently observe_property does not check it :-(
|
||||||
proplist = self.command("get_property", "property-list")
|
proplist = self.command("get_property", "property-list")
|
||||||
if name not in proplist:
|
if name not in proplist:
|
||||||
raise MPVError("no such property %r" % name)
|
raise MPVError(f"no such property {name!r}")
|
||||||
|
|
||||||
self._callbacks.setdefault("property-" + name, []).append(callback)
|
self._callbacks.setdefault(f"property-{name}", []).append(callback)
|
||||||
|
|
||||||
# 'observe_property' expects some kind of id which can be used later
|
# 'observe_property' expects some kind of id which can be used later
|
||||||
# for unregistering with 'unobserve_property'.
|
# for unregistering with 'unobserve_property'.
|
||||||
|
@ -572,15 +572,15 @@ class MPV(MPVBase):
|
||||||
property-change event on property `name`.
|
property-change event on property `name`.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
callbacks = self._callbacks["property-" + name]
|
callbacks = self._callbacks[f"property-{name}"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MPVError("no callbacks registered for property %r" % name)
|
raise MPVError(f"no callbacks registered for property {name!r}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
callbacks.remove(callback)
|
callbacks.remove(callback)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise MPVError(
|
raise MPVError(
|
||||||
"callback %r not registered for property %r" % (callback, name)
|
f"callback {callback!r} not registered for property {name!r}"
|
||||||
)
|
)
|
||||||
|
|
||||||
serial = self._property_serials.pop((name, callback))
|
serial = self._property_serials.pop((name, callback))
|
||||||
|
|
|
@ -80,7 +80,7 @@ class Overview:
|
||||||
elif url == "decks":
|
elif url == "decks":
|
||||||
self.mw.moveToState("deckBrowser")
|
self.mw.moveToState("deckBrowser")
|
||||||
elif url == "review":
|
elif url == "review":
|
||||||
openLink(aqt.appShared + "info/%s?v=%s" % (self.sid, self.sidVer))
|
openLink(f"{aqt.appShared}info/{self.sid}?v={self.sidVer}")
|
||||||
elif url == "studymore" or url == "customStudy":
|
elif url == "studymore" or url == "customStudy":
|
||||||
self.onStudyMore()
|
self.onStudyMore()
|
||||||
elif url == "unbury":
|
elif url == "unbury":
|
||||||
|
@ -180,8 +180,8 @@ class Overview:
|
||||||
def _desc(self, deck: Dict[str, Any]) -> str:
|
def _desc(self, deck: Dict[str, Any]) -> str:
|
||||||
if deck["dyn"]:
|
if deck["dyn"]:
|
||||||
desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
|
desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
|
||||||
desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)
|
desc += f" {tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)}"
|
||||||
desc += " " + tr(TR.STUDYING_DELETING_THIS_DECK_FROM_THE_DECK)
|
desc += f" {tr(TR.STUDYING_DELETING_THIS_DECK_FROM_THE_DECK)}"
|
||||||
else:
|
else:
|
||||||
desc = deck.get("desc", "")
|
desc = deck.get("desc", "")
|
||||||
if deck.get("md", False):
|
if deck.get("md", False):
|
||||||
|
@ -192,7 +192,7 @@ class Overview:
|
||||||
dyn = "dyn"
|
dyn = "dyn"
|
||||||
else:
|
else:
|
||||||
dyn = ""
|
dyn = ""
|
||||||
return '<div class="descfont descmid description %s">%s</div>' % (dyn, desc)
|
return f'<div class="descfont descmid description {dyn}">{desc}</div>'
|
||||||
|
|
||||||
def _table(self) -> Optional[str]:
|
def _table(self) -> Optional[str]:
|
||||||
counts = list(self.mw.col.sched.counts())
|
counts = list(self.mw.col.sched.counts())
|
||||||
|
|
|
@ -214,9 +214,9 @@ class Previewer(QDialog):
|
||||||
av_player.clear_queue_and_maybe_interrupt()
|
av_player.clear_queue_and_maybe_interrupt()
|
||||||
|
|
||||||
txt = self.mw.prepare_card_text_for_display(txt)
|
txt = self.mw.prepare_card_text_for_display(txt)
|
||||||
txt = gui_hooks.card_will_show(txt, c, "preview" + self._state.capitalize())
|
txt = gui_hooks.card_will_show(txt, c, f"preview{self._state.capitalize()}")
|
||||||
self._last_state = self._state_and_mod()
|
self._last_state = self._state_and_mod()
|
||||||
self._web.eval("{}({},'{}');".format(func, json.dumps(txt), bodyclass))
|
self._web.eval(f"{func}({json.dumps(txt)},'{bodyclass}');")
|
||||||
self._card_changed = False
|
self._card_changed = False
|
||||||
|
|
||||||
def _on_show_both_sides(self, toggle: bool) -> None:
|
def _on_show_both_sides(self, toggle: bool) -> None:
|
||||||
|
|
|
@ -522,7 +522,7 @@ create table if not exists profiles
|
||||||
without_unicode_isolation(
|
without_unicode_isolation(
|
||||||
tr(
|
tr(
|
||||||
TR.PROFILES_FOLDER_README,
|
TR.PROFILES_FOLDER_README,
|
||||||
link=appHelpSite + "files?id=startup-options",
|
link=f"{appHelpSite}files?id=startup-options",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ProgressManager:
|
||||||
def handler() -> None:
|
def handler() -> None:
|
||||||
if requiresCollection and not self.mw.col:
|
if requiresCollection and not self.mw.col:
|
||||||
# no current collection; timer is no longer valid
|
# no current collection; timer is no longer valid
|
||||||
print("Ignored progress func as collection unloaded: %s" % repr(func))
|
print(f"Ignored progress func as collection unloaded: {repr(func)}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self._levels:
|
if not self._levels:
|
||||||
|
|
|
@ -97,9 +97,7 @@ class Reviewer:
|
||||||
mins = int(round(elapsed[0] / 60))
|
mins = int(round(elapsed[0] / 60))
|
||||||
part2 = tr(TR.STUDYING_MINUTE, count=mins)
|
part2 = tr(TR.STUDYING_MINUTE, count=mins)
|
||||||
fin = tr(TR.STUDYING_FINISH)
|
fin = tr(TR.STUDYING_FINISH)
|
||||||
diag = askUserDialog(
|
diag = askUserDialog(f"{part1} {part2}", [tr(TR.STUDYING_CONTINUE), fin])
|
||||||
"%s %s" % (part1, part2), [tr(TR.STUDYING_CONTINUE), fin]
|
|
||||||
)
|
|
||||||
diag.setIcon(QMessageBox.Information)
|
diag.setIcon(QMessageBox.Information)
|
||||||
if diag.run() == fin:
|
if diag.run() == fin:
|
||||||
return self.mw.moveToState("deckBrowser")
|
return self.mw.moveToState("deckBrowser")
|
||||||
|
@ -142,15 +140,13 @@ class Reviewer:
|
||||||
fade = ""
|
fade = ""
|
||||||
if self.mw.pm.video_driver() == VideoDriver.Software:
|
if self.mw.pm.video_driver() == VideoDriver.Software:
|
||||||
fade = "<script>qFade=0;</script>"
|
fade = "<script>qFade=0;</script>"
|
||||||
return """
|
return f"""
|
||||||
<div id=_mark>★</div>
|
<div id=_mark>★</div>
|
||||||
<div id=_flag>⚑</div>
|
<div id=_flag>⚑</div>
|
||||||
{}
|
{fade}
|
||||||
<div id=qa></div>
|
<div id=qa></div>
|
||||||
{}
|
{extra}
|
||||||
""".format(
|
"""
|
||||||
fade, extra
|
|
||||||
)
|
|
||||||
|
|
||||||
def _initWeb(self) -> None:
|
def _initWeb(self) -> None:
|
||||||
self._reps = 0
|
self._reps = 0
|
||||||
|
@ -207,7 +203,7 @@ class Reviewer:
|
||||||
|
|
||||||
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
|
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
|
||||||
|
|
||||||
self.web.eval("_showQuestion(%s,'%s');" % (json.dumps(q), bodyclass))
|
self.web.eval(f"_showQuestion({json.dumps(q)},'{bodyclass}');")
|
||||||
self._drawFlag()
|
self._drawFlag()
|
||||||
self._drawMark()
|
self._drawMark()
|
||||||
self._showAnswerButton()
|
self._showAnswerButton()
|
||||||
|
@ -220,10 +216,10 @@ class Reviewer:
|
||||||
return card.autoplay()
|
return card.autoplay()
|
||||||
|
|
||||||
def _drawFlag(self) -> None:
|
def _drawFlag(self) -> None:
|
||||||
self.web.eval("_drawFlag(%s);" % self.card.userFlag())
|
self.web.eval(f"_drawFlag({self.card.userFlag()});")
|
||||||
|
|
||||||
def _drawMark(self) -> None:
|
def _drawMark(self) -> None:
|
||||||
self.web.eval("_drawMark(%s);" % json.dumps(self.card.note().hasTag("marked")))
|
self.web.eval(f"_drawMark({json.dumps(self.card.note().hasTag('marked'))});")
|
||||||
|
|
||||||
# Showing the answer
|
# Showing the answer
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -248,7 +244,7 @@ class Reviewer:
|
||||||
a = self._mungeQA(a)
|
a = self._mungeQA(a)
|
||||||
a = gui_hooks.card_will_show(a, c, "reviewAnswer")
|
a = gui_hooks.card_will_show(a, c, "reviewAnswer")
|
||||||
# render and update bottom
|
# render and update bottom
|
||||||
self.web.eval("_showAnswer(%s);" % json.dumps(a))
|
self.web.eval(f"_showAnswer({json.dumps(a)});")
|
||||||
self._showEaseButtons()
|
self._showEaseButtons()
|
||||||
self.mw.web.setFocus()
|
self.mw.web.setFocus()
|
||||||
# user hook
|
# user hook
|
||||||
|
@ -399,13 +395,12 @@ class Reviewer:
|
||||||
return re.sub(self.typeAnsPat, "", buf)
|
return re.sub(self.typeAnsPat, "", buf)
|
||||||
return re.sub(
|
return re.sub(
|
||||||
self.typeAnsPat,
|
self.typeAnsPat,
|
||||||
"""
|
f"""
|
||||||
<center>
|
<center>
|
||||||
<input type=text id=typeans onkeypress="_typeAnsPress();"
|
<input type=text id=typeans onkeypress="_typeAnsPress();"
|
||||||
style="font-family: '%s'; font-size: %spx;">
|
style="font-family: '{self.typeFont}'; font-size: {self.typeSize}px;">
|
||||||
</center>
|
</center>
|
||||||
"""
|
""",
|
||||||
% (self.typeFont, self.typeSize),
|
|
||||||
buf,
|
buf,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -440,7 +435,7 @@ class Reviewer:
|
||||||
if hadHR:
|
if hadHR:
|
||||||
# a hack to ensure the q/a separator falls before the answer
|
# a hack to ensure the q/a separator falls before the answer
|
||||||
# comparison when user is using {{FrontSide}}
|
# comparison when user is using {{FrontSide}}
|
||||||
s = "<hr id=answer>" + s
|
s = f"<hr id=answer>{s}"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
return re.sub(self.typeAnsPat, repl, buf)
|
return re.sub(self.typeAnsPat, repl, buf)
|
||||||
|
@ -506,13 +501,13 @@ class Reviewer:
|
||||||
givenElems, correctElems = self.tokenizeComparison(given, correct)
|
givenElems, correctElems = self.tokenizeComparison(given, correct)
|
||||||
|
|
||||||
def good(s: str) -> str:
|
def good(s: str) -> str:
|
||||||
return "<span class=typeGood>" + html.escape(s) + "</span>"
|
return f"<span class=typeGood>{html.escape(s)}</span>"
|
||||||
|
|
||||||
def bad(s: str) -> str:
|
def bad(s: str) -> str:
|
||||||
return "<span class=typeBad>" + html.escape(s) + "</span>"
|
return f"<span class=typeBad>{html.escape(s)}</span>"
|
||||||
|
|
||||||
def missed(s: str) -> str:
|
def missed(s: str) -> str:
|
||||||
return "<span class=typeMissed>" + html.escape(s) + "</span>"
|
return f"<span class=typeMissed>{html.escape(s)}</span>"
|
||||||
|
|
||||||
if given == correct:
|
if given == correct:
|
||||||
res = good(given)
|
res = good(given)
|
||||||
|
@ -531,14 +526,14 @@ class Reviewer:
|
||||||
res += good(txt)
|
res += good(txt)
|
||||||
else:
|
else:
|
||||||
res += missed(txt)
|
res += missed(txt)
|
||||||
res = "<div><code id=typeans>" + res + "</code></div>"
|
res = f"<div><code id=typeans>{res}</code></div>"
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _noLoneMarks(self, s: str) -> str:
|
def _noLoneMarks(self, s: str) -> str:
|
||||||
# ensure a combining character at the start does not join to
|
# ensure a combining character at the start does not join to
|
||||||
# previous text
|
# previous text
|
||||||
if s and ucd.category(s[0]).startswith("M"):
|
if s and ucd.category(s[0]).startswith("M"):
|
||||||
return "\xa0" + s
|
return f"\xa0{s}"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def _getTypedAnswer(self) -> None:
|
def _getTypedAnswer(self) -> None:
|
||||||
|
@ -602,7 +597,7 @@ time = %(time)d;
|
||||||
|
|
||||||
def _showEaseButtons(self) -> None:
|
def _showEaseButtons(self) -> None:
|
||||||
middle = self._answerButtons()
|
middle = self._answerButtons()
|
||||||
self.bottom.web.eval("showAnswer(%s);" % json.dumps(middle))
|
self.bottom.web.eval(f"showAnswer({json.dumps(middle)});")
|
||||||
|
|
||||||
def _remaining(self) -> str:
|
def _remaining(self) -> str:
|
||||||
if not self.mw.col.conf["dueCounts"]:
|
if not self.mw.col.conf["dueCounts"]:
|
||||||
|
@ -613,11 +608,11 @@ time = %(time)d;
|
||||||
else:
|
else:
|
||||||
counts = list(self.mw.col.sched.counts(self.card))
|
counts = list(self.mw.col.sched.counts(self.card))
|
||||||
idx = self.mw.col.sched.countIdx(self.card)
|
idx = self.mw.col.sched.countIdx(self.card)
|
||||||
counts[idx] = "<u>%s</u>" % (counts[idx])
|
counts[idx] = f"<u>{counts[idx]}</u>"
|
||||||
space = " + "
|
space = " + "
|
||||||
ctxt = "<span class=new-count>%s</span>" % counts[0]
|
ctxt = f"<span class=new-count>{counts[0]}</span>"
|
||||||
ctxt += space + "<span class=learn-count>%s</span>" % counts[1]
|
ctxt += f"{space}<span class=learn-count>{counts[1]}</span>"
|
||||||
ctxt += space + "<span class=review-count>%s</span>" % counts[2]
|
ctxt += f"{space}<span class=review-count>{counts[2]}</span>"
|
||||||
return ctxt
|
return ctxt
|
||||||
|
|
||||||
def _defaultEase(self) -> int:
|
def _defaultEase(self) -> int:
|
||||||
|
@ -683,7 +678,7 @@ time = %(time)d;
|
||||||
if not self.mw.col.conf["estTimes"]:
|
if not self.mw.col.conf["estTimes"]:
|
||||||
return "<div class=spacer></div>"
|
return "<div class=spacer></div>"
|
||||||
txt = self.mw.col.sched.nextIvlStr(self.card, i, True) or " "
|
txt = self.mw.col.sched.nextIvlStr(self.card, i, True) or " "
|
||||||
return "<span class=nobold>%s</span><br>" % txt
|
return f"<span class=nobold>{txt}</span><br>"
|
||||||
|
|
||||||
# Leeches
|
# Leeches
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -692,7 +687,7 @@ time = %(time)d;
|
||||||
# for now
|
# for now
|
||||||
s = tr(TR.STUDYING_CARD_WAS_A_LEECH)
|
s = tr(TR.STUDYING_CARD_WAS_A_LEECH)
|
||||||
if card.queue < 0:
|
if card.queue < 0:
|
||||||
s += " " + tr(TR.STUDYING_IT_HAS_BEEN_SUSPENDED)
|
s += f" {tr(TR.STUDYING_IT_HAS_BEEN_SUSPENDED)}"
|
||||||
tooltip(s)
|
tooltip(s)
|
||||||
|
|
||||||
# Context menu
|
# Context menu
|
||||||
|
|
|
@ -805,7 +805,7 @@ class SidebarTreeView(QTreeView):
|
||||||
full_name=head + node.name,
|
full_name=head + node.name,
|
||||||
)
|
)
|
||||||
root.add_child(item)
|
root.add_child(item)
|
||||||
newhead = head + node.name + "::"
|
newhead = f"{head + node.name}::"
|
||||||
render(item, node.children, newhead)
|
render(item, node.children, newhead)
|
||||||
|
|
||||||
tree = self.col.tags.tree()
|
tree = self.col.tags.tree()
|
||||||
|
@ -854,7 +854,7 @@ class SidebarTreeView(QTreeView):
|
||||||
full_name=head + node.name,
|
full_name=head + node.name,
|
||||||
)
|
)
|
||||||
root.add_child(item)
|
root.add_child(item)
|
||||||
newhead = head + node.name + "::"
|
newhead = f"{head + node.name}::"
|
||||||
render(item, node.children, newhead)
|
render(item, node.children, newhead)
|
||||||
|
|
||||||
tree = self.col.decks.deck_tree()
|
tree = self.col.decks.deck_tree()
|
||||||
|
@ -906,7 +906,7 @@ class SidebarTreeView(QTreeView):
|
||||||
SearchTerm(note=nt["name"]), SearchTerm(template=c)
|
SearchTerm(note=nt["name"]), SearchTerm(template=c)
|
||||||
),
|
),
|
||||||
item_type=SidebarItemType.NOTETYPE_TEMPLATE,
|
item_type=SidebarItemType.NOTETYPE_TEMPLATE,
|
||||||
full_name=nt["name"] + "::" + tmpl["name"],
|
full_name=f"{nt['name']}::{tmpl['name']}",
|
||||||
)
|
)
|
||||||
item.add_child(child)
|
item.add_child(child)
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,7 @@ def _packagedCmd(cmd: List[str]) -> Tuple[Any, Dict[str, str]]:
|
||||||
del env["LD_LIBRARY_PATH"]
|
del env["LD_LIBRARY_PATH"]
|
||||||
if isMac:
|
if isMac:
|
||||||
dir = os.path.dirname(os.path.abspath(__file__))
|
dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
exeDir = os.path.abspath(dir + "/../../Resources/audio")
|
exeDir = os.path.abspath(f"{dir}/../../Resources/audio")
|
||||||
else:
|
else:
|
||||||
exeDir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
exeDir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
if isWin and not cmd[0].endswith(".exe"):
|
if isWin and not cmd[0].endswith(".exe"):
|
||||||
|
@ -353,7 +353,7 @@ class SimpleMpvPlayer(SimpleProcessPlayer, VideoPlayer):
|
||||||
|
|
||||||
def __init__(self, taskman: TaskManager, base_folder: str) -> None:
|
def __init__(self, taskman: TaskManager, base_folder: str) -> None:
|
||||||
super().__init__(taskman)
|
super().__init__(taskman)
|
||||||
self.args += ["--config-dir=" + base_folder]
|
self.args += [f"--config-dir={base_folder}"]
|
||||||
|
|
||||||
|
|
||||||
class SimpleMplayerPlayer(SimpleProcessPlayer, SoundOrVideoPlayer):
|
class SimpleMplayerPlayer(SimpleProcessPlayer, SoundOrVideoPlayer):
|
||||||
|
@ -377,7 +377,7 @@ class MpvManager(MPV, SoundOrVideoPlayer):
|
||||||
mpvPath, self.popenEnv = _packagedCmd(["mpv"])
|
mpvPath, self.popenEnv = _packagedCmd(["mpv"])
|
||||||
self.executable = mpvPath[0]
|
self.executable = mpvPath[0]
|
||||||
self._on_done: Optional[OnDoneCallback] = None
|
self._on_done: Optional[OnDoneCallback] = None
|
||||||
self.default_argv += ["--config-dir=" + base_path]
|
self.default_argv += [f"--config-dir={base_path}"]
|
||||||
super().__init__(window_id=None, debug=False)
|
super().__init__(window_id=None, debug=False)
|
||||||
|
|
||||||
def on_init(self) -> None:
|
def on_init(self) -> None:
|
||||||
|
@ -764,7 +764,7 @@ class RecordDialog(QDialog):
|
||||||
def _on_timer(self) -> None:
|
def _on_timer(self) -> None:
|
||||||
self._recorder.on_timer()
|
self._recorder.on_timer()
|
||||||
duration = self._recorder.duration()
|
duration = self._recorder.duration()
|
||||||
self.label.setText(tr(TR.MEDIA_RECORDINGTIME, secs="%0.1f" % duration))
|
self.label.setText(tr(TR.MEDIA_RECORDINGTIME, secs=f"{duration:0.1f}"))
|
||||||
|
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
|
|
|
@ -66,7 +66,7 @@ class NewDeckStats(QDialog):
|
||||||
|
|
||||||
def _imagePath(self) -> str:
|
def _imagePath(self) -> str:
|
||||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
name = f"anki-{tr(TR.STATISTICS_STATS)}{name}"
|
||||||
file = getSaveFile(
|
file = getSaveFile(
|
||||||
self,
|
self,
|
||||||
title=tr(TR.STATISTICS_SAVE_PDF),
|
title=tr(TR.STATISTICS_SAVE_PDF),
|
||||||
|
@ -156,7 +156,7 @@ class DeckStats(QDialog):
|
||||||
|
|
||||||
def _imagePath(self) -> str:
|
def _imagePath(self) -> str:
|
||||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
name = f"anki-{tr(TR.STATISTICS_STATS)}{name}"
|
||||||
file = getSaveFile(
|
file = getSaveFile(
|
||||||
self,
|
self,
|
||||||
title=tr(TR.STATISTICS_SAVE_PDF),
|
title=tr(TR.STATISTICS_SAVE_PDF),
|
||||||
|
@ -189,7 +189,7 @@ class DeckStats(QDialog):
|
||||||
self.report = stats.report(type=self.period)
|
self.report = stats.report(type=self.period)
|
||||||
self.form.web.title = "deck stats"
|
self.form.web.title = "deck stats"
|
||||||
self.form.web.stdHtml(
|
self.form.web.stdHtml(
|
||||||
"<html><body>" + self.report + "</body></html>",
|
f"<html><body>{self.report}</body></html>",
|
||||||
js=["js/vendor/jquery.min.js", "js/vendor/plot.js"],
|
js=["js/vendor/jquery.min.js", "js/vendor/plot.js"],
|
||||||
context=self,
|
context=self,
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class StudyDeck(QDialog):
|
||||||
self.form.filter.installEventFilter(self)
|
self.form.filter.installEventFilter(self)
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
gui_hooks.state_did_reset.append(self.onReset)
|
gui_hooks.state_did_reset.append(self.onReset)
|
||||||
self.geomKey = "studyDeck-" + geomKey
|
self.geomKey = f"studyDeck-{geomKey}"
|
||||||
restoreGeom(self, self.geomKey)
|
restoreGeom(self, self.geomKey)
|
||||||
disable_help_button(self)
|
disable_help_button(self)
|
||||||
if not cancel:
|
if not cancel:
|
||||||
|
|
|
@ -137,4 +137,4 @@ class TagCompleter(QCompleter):
|
||||||
self.tags.remove("")
|
self.tags.remove("")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
return " ".join(self.tags) + " "
|
return f"{' '.join(self.tags)} "
|
||||||
|
|
|
@ -98,12 +98,12 @@ class TagLimit(QDialog):
|
||||||
if yes:
|
if yes:
|
||||||
arr = []
|
arr = []
|
||||||
for req in yes:
|
for req in yes:
|
||||||
arr.append('tag:"%s"' % req)
|
arr.append(f'tag:"{req}"')
|
||||||
self.tags += "(" + " or ".join(arr) + ")"
|
self.tags += f"({' or '.join(arr)})"
|
||||||
if no:
|
if no:
|
||||||
arr = []
|
arr = []
|
||||||
for req in no:
|
for req in no:
|
||||||
arr.append('-tag:"%s"' % req)
|
arr.append(f'-tag:"{req}"')
|
||||||
self.tags += " " + " ".join(arr)
|
self.tags += f" {' '.join(arr)}"
|
||||||
saveGeom(self, "tagLimit")
|
saveGeom(self, "tagLimit")
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
|
@ -141,7 +141,7 @@ def on_tts_voices(
|
||||||
f"{{{{tts {v.lang} voices={v.name}}}}}" # pylint: disable=no-member
|
f"{{{{tts {v.lang} voices={v.name}}}}}" # pylint: disable=no-member
|
||||||
for v in voices
|
for v in voices
|
||||||
)
|
)
|
||||||
return buf + "</div>"
|
return f"{buf}</div>"
|
||||||
|
|
||||||
|
|
||||||
hooks.field_filter.append(on_tts_voices)
|
hooks.field_filter.append(on_tts_voices)
|
||||||
|
@ -199,7 +199,7 @@ class MacTTSPlayer(TTSProcessPlayer):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
original_name = m.group(1).strip()
|
original_name = m.group(1).strip()
|
||||||
tidy_name = "Apple_" + original_name.replace(" ", "_")
|
tidy_name = f"Apple_{original_name.replace(' ', '_')}"
|
||||||
return MacVoice(name=tidy_name, original_name=original_name, lang=m.group(2))
|
return MacVoice(name=tidy_name, original_name=original_name, lang=m.group(2))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -479,7 +479,7 @@ def getFile(
|
||||||
"Ask the user for a file."
|
"Ask the user for a file."
|
||||||
assert not dir or not key
|
assert not dir or not key
|
||||||
if not dir:
|
if not dir:
|
||||||
dirkey = key + "Directory"
|
dirkey = f"{key}Directory"
|
||||||
dir = aqt.mw.pm.profile.get(dirkey, "")
|
dir = aqt.mw.pm.profile.get(dirkey, "")
|
||||||
else:
|
else:
|
||||||
dirkey = None
|
dirkey = None
|
||||||
|
@ -521,7 +521,7 @@ def getSaveFile(
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Ask the user for a file to save. Use DIR_DESCRIPTION as config
|
"""Ask the user for a file to save. Use DIR_DESCRIPTION as config
|
||||||
variable. The file dialog will default to open with FNAME."""
|
variable. The file dialog will default to open with FNAME."""
|
||||||
config_key = dir_description + "Directory"
|
config_key = f"{dir_description}Directory"
|
||||||
|
|
||||||
defaultPath = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
defaultPath = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
||||||
base = aqt.mw.pm.profile.get(config_key, defaultPath)
|
base = aqt.mw.pm.profile.get(config_key, defaultPath)
|
||||||
|
@ -644,8 +644,8 @@ def restore_is_checked(widget: QWidget, key: str) -> None:
|
||||||
|
|
||||||
|
|
||||||
def save_combo_index_for_session(widget: QComboBox, key: str) -> None:
|
def save_combo_index_for_session(widget: QComboBox, key: str) -> None:
|
||||||
textKey = key + "ComboActiveText"
|
textKey = f"{key}ComboActiveText"
|
||||||
indexKey = key + "ComboActiveIndex"
|
indexKey = f"{key}ComboActiveIndex"
|
||||||
aqt.mw.pm.session[textKey] = widget.currentText()
|
aqt.mw.pm.session[textKey] = widget.currentText()
|
||||||
aqt.mw.pm.session[indexKey] = widget.currentIndex()
|
aqt.mw.pm.session[indexKey] = widget.currentIndex()
|
||||||
|
|
||||||
|
@ -653,8 +653,8 @@ def save_combo_index_for_session(widget: QComboBox, key: str) -> None:
|
||||||
def restore_combo_index_for_session(
|
def restore_combo_index_for_session(
|
||||||
widget: QComboBox, history: List[str], key: str
|
widget: QComboBox, history: List[str], key: str
|
||||||
) -> None:
|
) -> None:
|
||||||
textKey = key + "ComboActiveText"
|
textKey = f"{key}ComboActiveText"
|
||||||
indexKey = key + "ComboActiveIndex"
|
indexKey = f"{key}ComboActiveIndex"
|
||||||
text = aqt.mw.pm.session.get(textKey)
|
text = aqt.mw.pm.session.get(textKey)
|
||||||
index = aqt.mw.pm.session.get(indexKey)
|
index = aqt.mw.pm.session.get(indexKey)
|
||||||
if text is not None and index is not None:
|
if text is not None and index is not None:
|
||||||
|
@ -696,10 +696,10 @@ def mungeQA(col: Collection, txt: str) -> str:
|
||||||
|
|
||||||
def openFolder(path: str) -> None:
|
def openFolder(path: str) -> None:
|
||||||
if isWin:
|
if isWin:
|
||||||
subprocess.Popen(["explorer", "file://" + path])
|
subprocess.Popen(["explorer", f"file://{path}"])
|
||||||
else:
|
else:
|
||||||
with noBundledLibs():
|
with noBundledLibs():
|
||||||
QDesktopServices.openUrl(QUrl("file://" + path))
|
QDesktopServices.openUrl(QUrl(f"file://{path}"))
|
||||||
|
|
||||||
|
|
||||||
def shortcut(key: str) -> str:
|
def shortcut(key: str) -> str:
|
||||||
|
@ -755,13 +755,11 @@ def tooltip(
|
||||||
closeTooltip()
|
closeTooltip()
|
||||||
aw = parent or aqt.mw.app.activeWindow() or aqt.mw
|
aw = parent or aqt.mw.app.activeWindow() or aqt.mw
|
||||||
lab = CustomLabel(
|
lab = CustomLabel(
|
||||||
"""\
|
f"""<table cellpadding=10>
|
||||||
<table cellpadding=10>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>%s</td>
|
<td>{msg}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>"""
|
</table>""",
|
||||||
% msg,
|
|
||||||
aw,
|
aw,
|
||||||
)
|
)
|
||||||
lab.setFrameStyle(QFrame.Panel)
|
lab.setFrameStyle(QFrame.Panel)
|
||||||
|
@ -886,9 +884,9 @@ def supportText() -> str:
|
||||||
from aqt import mw
|
from aqt import mw
|
||||||
|
|
||||||
if isWin:
|
if isWin:
|
||||||
platname = "Windows " + platform.win32_ver()[0]
|
platname = f"Windows {platform.win32_ver()[0]}"
|
||||||
elif isMac:
|
elif isMac:
|
||||||
platname = "Mac " + platform.mac_ver()[0]
|
platname = f"Mac {platform.mac_ver()[0]}"
|
||||||
else:
|
else:
|
||||||
platname = "Linux"
|
platname = "Linux"
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
else:
|
else:
|
||||||
level_str = str(level)
|
level_str = str(level)
|
||||||
buf = "JS %(t)s %(f)s:%(a)d %(b)s" % dict(
|
buf = "JS %(t)s %(f)s:%(a)d %(b)s" % dict(
|
||||||
t=level_str, a=line, f=srcID, b=msg + "\n"
|
t=level_str, a=line, f=srcID, b=f"{msg}\n"
|
||||||
)
|
)
|
||||||
if "MathJax localStorage" in buf:
|
if "MathJax localStorage" in buf:
|
||||||
# silence localStorage noise
|
# silence localStorage noise
|
||||||
|
@ -392,10 +392,10 @@ class AnkiWebView(QWebEngineView):
|
||||||
family = tr(TR.QT_MISC_SEGOE_UI)
|
family = tr(TR.QT_MISC_SEGOE_UI)
|
||||||
button_style = "button { font-family:%s; }" % family
|
button_style = "button { font-family:%s; }" % family
|
||||||
button_style += "\n:focus { outline: 1px solid %s; }" % color_hl
|
button_style += "\n:focus { outline: 1px solid %s; }" % color_hl
|
||||||
font = "font-size:12px;font-family:%s;" % family
|
font = f"font-size:12px;font-family:{family};"
|
||||||
elif isMac:
|
elif isMac:
|
||||||
family = "Helvetica"
|
family = "Helvetica"
|
||||||
font = 'font-size:15px;font-family:"%s";' % family
|
font = f'font-size:15px;font-family:"{family}";'
|
||||||
button_style = """
|
button_style = """
|
||||||
button { -webkit-appearance: none; background: #fff; border: 1px solid #ccc;
|
button { -webkit-appearance: none; background: #fff; border: 1px solid #ccc;
|
||||||
border-radius:5px; font-family: Helvetica }"""
|
border-radius:5px; font-family: Helvetica }"""
|
||||||
|
@ -403,7 +403,7 @@ border-radius:5px; font-family: Helvetica }"""
|
||||||
family = self.font().family()
|
family = self.font().family()
|
||||||
color_hl_txt = palette.color(QPalette.HighlightedText).name()
|
color_hl_txt = palette.color(QPalette.HighlightedText).name()
|
||||||
color_btn = palette.color(QPalette.Button).name()
|
color_btn = palette.color(QPalette.Button).name()
|
||||||
font = 'font-size:14px;font-family:"%s";' % family
|
font = f'font-size:14px;font-family:"{family}";'
|
||||||
button_style = """
|
button_style = """
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
button{
|
button{
|
||||||
|
@ -503,7 +503,7 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
|
||||||
return f"http://127.0.0.1:{mw.mediaServer.getPort()}{subpath}{path}"
|
return f"http://127.0.0.1:{mw.mediaServer.getPort()}{subpath}{path}"
|
||||||
|
|
||||||
def bundledScript(self, fname: str) -> str:
|
def bundledScript(self, fname: str) -> str:
|
||||||
return '<script src="%s"></script>' % self.webBundlePath(fname)
|
return f'<script src="{self.webBundlePath(fname)}"></script>'
|
||||||
|
|
||||||
def bundledCSS(self, fname: str) -> str:
|
def bundledCSS(self, fname: str) -> str:
|
||||||
return '<link rel="stylesheet" type="text/css" href="%s">' % self.webBundlePath(
|
return '<link rel="stylesheet" type="text/css" href="%s">' % self.webBundlePath(
|
||||||
|
@ -641,5 +641,5 @@ document.head.appendChild(style);
|
||||||
else:
|
else:
|
||||||
extra = ""
|
extra = ""
|
||||||
self.hide_while_preserving_layout()
|
self.hide_while_preserving_layout()
|
||||||
self.load(QUrl(f"{mw.serverURL()}_anki/pages/{name}.html" + extra))
|
self.load(QUrl(f"{mw.serverURL()}_anki/pages/{name}.html{extra}"))
|
||||||
self.inject_dynamic_style_and_show()
|
self.inject_dynamic_style_and_show()
|
||||||
|
|
|
@ -86,7 +86,7 @@ def _err_unless_zero(result):
|
||||||
if result == 0:
|
if result == 0:
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
raise WinPathsException("Failed to retrieve windows path: %s" % result)
|
raise WinPathsException(f"Failed to retrieve windows path: {result}")
|
||||||
|
|
||||||
|
|
||||||
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
|
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
|
||||||
|
|
Loading…
Reference in a new issue