Enable strict_optional for aqt/tagedit, utils, sync (#3578)

* Enable strict_optional for tagedit

* Fix mypy errors

* Enable strict_optional for utils

* Fix mypy errors

* Enable strict_optional for sync

* Fix mypy errors

---------

Co-authored-by: Abdo <abdo@abdnh.net>
This commit is contained in:
Ben Nguyen 2024-11-15 05:29:19 -08:00 committed by GitHub
parent 29f714d973
commit 9d09c32ece
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 111 additions and 49 deletions

View file

@ -104,6 +104,12 @@ strict_optional = True
strict_optional = True strict_optional = True
[mypy-aqt.progress] [mypy-aqt.progress]
strict_optional = True strict_optional = True
[mypy-aqt.tagedit]
strict_optional = True
[mypy-aqt.utils]
strict_optional = True
[mypy-aqt.sync]
strict_optional = True
[mypy-anki.scheduler.base] [mypy-anki.scheduler.base]
strict_optional = True strict_optional = True
[mypy-anki._backend.rsbridge] [mypy-anki._backend.rsbridge]

View file

@ -1128,7 +1128,7 @@ class Collection(DeprecatedNamesMixin):
self._backend.abort_sync() self._backend.abort_sync()
def full_upload_or_download( def full_upload_or_download(
self, *, auth: SyncAuth, server_usn: int | None, upload: bool self, *, auth: SyncAuth | None, server_usn: int | None, upload: bool
) -> None: ) -> None:
self._backend.full_upload_or_download( self._backend.full_upload_or_download(
sync_pb2.FullUploadOrDownloadRequest( sync_pb2.FullUploadOrDownloadRequest(

View file

@ -94,7 +94,7 @@ class NewDeckStats(QDialog):
lambda _: self.refresh() lambda _: self.refresh()
).run_in_background() ).run_in_background()
def _imagePath(self) -> str: def _imagePath(self) -> str | None:
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 = f"anki-{tr.statistics_stats()}{name}" name = f"anki-{tr.statistics_stats()}{name}"
file = getSaveFile( file = getSaveFile(
@ -196,7 +196,7 @@ class DeckStats(QDialog):
self.reject() self.reject()
callback() callback()
def _imagePath(self) -> str: def _imagePath(self) -> str | None:
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 = f"anki-{tr.statistics_stats()}{name}" name = f"anki-{tr.statistics_stats()}{name}"
file = getSaveFile( file = getSaveFile(

View file

@ -168,7 +168,7 @@ def full_sync(
def confirm_full_download( def confirm_full_download(
mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None]
) -> None: ) -> None:
# confirmation step required, as some users customize their notetypes # confirmation step required, as some users customize their notetypes
# in an empty collection, then want to upload them # in an empty collection, then want to upload them
@ -184,7 +184,7 @@ def confirm_full_download(
def confirm_full_upload( def confirm_full_upload(
mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None]
) -> None: ) -> None:
# confirmation step required, as some users have reported an upload # confirmation step required, as some users have reported an upload
# happening despite having their AnkiWeb collection not being empty # happening despite having their AnkiWeb collection not being empty
@ -220,7 +220,7 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt, label: str) -> None:
def full_download( def full_download(
mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None]
) -> None: ) -> None:
label = tr.sync_downloading_from_ankiweb() label = tr.sync_downloading_from_ankiweb()
@ -372,7 +372,9 @@ def get_id_and_pass_from_user(
l2.setBuddy(passwd) l2.setBuddy(passwd)
vbox.addLayout(g) vbox.addLayout(g)
bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore
bb.button(QDialogButtonBox.StandardButton.Ok).setAutoDefault(True) ok_button = bb.button(QDialogButtonBox.StandardButton.Ok)
assert ok_button is not None
ok_button.setAutoDefault(True)
qconnect(bb.accepted, diag.accept) qconnect(bb.accepted, diag.accept)
qconnect(bb.rejected, diag.reject) qconnect(bb.rejected, diag.reject)
vbox.addWidget(bb) vbox.addWidget(bb)

View file

@ -42,13 +42,17 @@ class TagEdit(QLineEdit):
l = (d.name for d in self.col.decks.all_names_and_ids()) l = (d.name for d in self.col.decks.all_names_and_ids())
self.model.setStringList(l) self.model.setStringList(l)
def focusInEvent(self, evt: QFocusEvent) -> None: def focusInEvent(self, evt: QFocusEvent | None) -> None:
QLineEdit.focusInEvent(self, evt) QLineEdit.focusInEvent(self, evt)
def keyPressEvent(self, evt: QKeyEvent) -> None: def keyPressEvent(self, evt: QKeyEvent | None) -> None:
assert evt is not None
popup = self._completer.popup()
assert popup is not None
if evt.key() in (Qt.Key.Key_Up, Qt.Key.Key_Down): if evt.key() in (Qt.Key.Key_Up, Qt.Key.Key_Down):
# show completer on arrow key up/down # show completer on arrow key up/down
if not self._completer.popup().isVisible(): if not popup.isVisible():
self.showCompleter() self.showCompleter()
return return
if ( if (
@ -56,24 +60,21 @@ class TagEdit(QLineEdit):
and evt.modifiers() & Qt.KeyboardModifier.ControlModifier and evt.modifiers() & Qt.KeyboardModifier.ControlModifier
): ):
# select next completion # select next completion
if not self._completer.popup().isVisible(): if not popup.isVisible():
self.showCompleter() self.showCompleter()
index = self._completer.currentIndex() index = self._completer.currentIndex()
self._completer.popup().setCurrentIndex(index) popup.setCurrentIndex(index)
cur_row = index.row() cur_row = index.row()
if not self._completer.setCurrentRow(cur_row + 1): if not self._completer.setCurrentRow(cur_row + 1):
self._completer.setCurrentRow(0) self._completer.setCurrentRow(0)
return return
if ( if evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) and popup.isVisible():
evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return)
and self._completer.popup().isVisible()
):
# apply first completion if no suggestion selected # apply first completion if no suggestion selected
selected_row = self._completer.popup().currentIndex().row() selected_row = popup.currentIndex().row()
if selected_row == -1: if selected_row == -1:
self._completer.setCurrentRow(0) self._completer.setCurrentRow(0)
index = self._completer.currentIndex() index = self._completer.currentIndex()
self._completer.popup().setCurrentIndex(index) popup.setCurrentIndex(index)
self.hideCompleter() self.hideCompleter()
QWidget.keyPressEvent(self, evt) QWidget.keyPressEvent(self, evt)
return return
@ -97,15 +98,19 @@ class TagEdit(QLineEdit):
self._completer.setCompletionPrefix(self.text()) self._completer.setCompletionPrefix(self.text())
self._completer.complete() self._completer.complete()
def focusOutEvent(self, evt: QFocusEvent) -> None: def focusOutEvent(self, evt: QFocusEvent | None) -> None:
QLineEdit.focusOutEvent(self, evt) QLineEdit.focusOutEvent(self, evt)
self.lostFocus.emit() # type: ignore self.lostFocus.emit() # type: ignore
self._completer.popup().hide() popup = self._completer.popup()
assert popup is not None
popup.hide()
def hideCompleter(self) -> None: def hideCompleter(self) -> None:
if sip.isdeleted(self._completer): # type: ignore if sip.isdeleted(self._completer): # type: ignore
return return
self._completer.popup().hide() popup = self._completer.popup()
assert popup is not None
popup.hide()
class TagCompleter(QCompleter): class TagCompleter(QCompleter):
@ -120,7 +125,9 @@ class TagCompleter(QCompleter):
self.edit = edit self.edit = edit
self.cursor: int | None = None self.cursor: int | None = None
def splitPath(self, tags: str) -> list[str]: def splitPath(self, tags: str | None) -> list[str]:
assert tags is not None
assert self.edit.col is not None
stripped_tags = tags.strip() stripped_tags = tags.strip()
stripped_tags = re.sub(" +", " ", stripped_tags) stripped_tags = re.sub(" +", " ", stripped_tags)
self.tags = self.edit.col.tags.split(stripped_tags) self.tags = self.edit.col.tags.split(stripped_tags)

View file

@ -118,10 +118,13 @@ HelpPageArgument = Union["HelpPage.V", str]
def openHelp(section: HelpPageArgument) -> None: def openHelp(section: HelpPageArgument) -> None:
assert tr.backend is not None
backend = tr.backend()
assert backend is not None
if isinstance(section, str): if isinstance(section, str):
link = tr.backend().help_page_link(page=HelpPage.INDEX) + section link = backend.help_page_link(page=HelpPage.INDEX) + section
else: else:
link = tr.backend().help_page_link(page=section) link = backend.help_page_link(page=section)
openLink(link) openLink(link)
@ -170,17 +173,20 @@ class MessageBox(QMessageBox):
b = self.addButton(button) b = self.addButton(button)
# a translator has complained the default Qt translation is inappropriate, so we override it # a translator has complained the default Qt translation is inappropriate, so we override it
if button == QMessageBox.StandardButton.Discard: if button == QMessageBox.StandardButton.Discard:
assert b is not None
b.setText(tr.actions_discard()) b.setText(tr.actions_discard())
elif isinstance(button, tuple): elif isinstance(button, tuple):
b = self.addButton(button[0], button[1]) b = self.addButton(button[0], button[1])
else: else:
continue continue
if callback is not None: if callback is not None:
assert b is not None
qconnect(b.clicked, partial(callback, i)) qconnect(b.clicked, partial(callback, i))
if i == default_button: if i == default_button:
self.setDefaultButton(b) self.setDefaultButton(b)
if help is not None: if help is not None:
b = self.addButton(QMessageBox.StandardButton.Help) b = self.addButton(QMessageBox.StandardButton.Help)
assert b is not None
qconnect(b.clicked, lambda: openHelp(help)) qconnect(b.clicked, lambda: openHelp(help))
self.open() self.open()
@ -316,9 +322,11 @@ def showInfo(
mb.setDefaultButton(default) mb.setDefaultButton(default)
else: else:
b = mb.addButton(QMessageBox.StandardButton.Ok) b = mb.addButton(QMessageBox.StandardButton.Ok)
assert b is not None
b.setDefault(True) b.setDefault(True)
if help is not None: if help is not None:
b = mb.addButton(QMessageBox.StandardButton.Help) b = mb.addButton(QMessageBox.StandardButton.Help)
assert b is not None
qconnect(b.clicked, lambda: openHelp(help)) qconnect(b.clicked, lambda: openHelp(help))
b.setAutoDefault(False) b.setAutoDefault(False)
return mb.exec() return mb.exec()
@ -363,7 +371,9 @@ def showText(
if copyBtn: if copyBtn:
def onCopy() -> None: def onCopy() -> None:
QApplication.clipboard().setText(text.toPlainText()) clipboard = QApplication.clipboard()
assert clipboard is not None
clipboard.setText(text.toPlainText())
btn = QPushButton(tr.qt_misc_copy_to_clipboard()) btn = QPushButton(tr.qt_misc_copy_to_clipboard())
qconnect(btn.clicked, onCopy) qconnect(btn.clicked, onCopy)
@ -415,6 +425,7 @@ def askUser(
default = QMessageBox.StandardButton.Yes default = QMessageBox.StandardButton.Yes
r = msgfunc(parent, title, text, sb, default) r = msgfunc(parent, title, text, sb, default)
if r == QMessageBox.StandardButton.Help: if r == QMessageBox.StandardButton.Help:
assert help is not None
openHelp(help) openHelp(help)
else: else:
break break
@ -431,7 +442,7 @@ class ButtonedDialog(QMessageBox):
title: str = "Anki", title: str = "Anki",
): ):
QMessageBox.__init__(self, parent) QMessageBox.__init__(self, parent)
self._buttons: list[QPushButton] = [] self._buttons: list[QPushButton | None] = []
self.setWindowTitle(title) self.setWindowTitle(title)
self.help = help self.help = help
self.setIcon(QMessageBox.Icon.Warning) self.setIcon(QMessageBox.Icon.Warning)
@ -444,11 +455,13 @@ class ButtonedDialog(QMessageBox):
def run(self) -> str: def run(self) -> str:
self.exec() self.exec()
but = self.clickedButton().text() clicked_button = self.clickedButton()
if but == "Help": assert clicked_button is not None
txt = clicked_button.text()
if txt == "Help":
# FIXME stop dialog closing? # FIXME stop dialog closing?
assert self.help is not None
openHelp(self.help) openHelp(self.help)
txt = self.clickedButton().text()
# work around KDE 'helpfully' adding accelerators to button text of Qt apps # work around KDE 'helpfully' adding accelerators to button text of Qt apps
return txt.replace("&", "") return txt.replace("&", "")
@ -504,13 +517,18 @@ class GetTextDialog(QDialog):
b = QDialogButtonBox(buts) # type: ignore b = QDialogButtonBox(buts) # type: ignore
v.addWidget(b) v.addWidget(b)
self.setLayout(v) self.setLayout(v)
qconnect(b.button(QDialogButtonBox.StandardButton.Ok).clicked, self.accept) ok_button = b.button(QDialogButtonBox.StandardButton.Ok)
qconnect(b.button(QDialogButtonBox.StandardButton.Cancel).clicked, self.reject) assert ok_button is not None
qconnect(ok_button.clicked, self.accept)
cancel_button = b.button(QDialogButtonBox.StandardButton.Cancel)
assert cancel_button is not None
qconnect(cancel_button.clicked, self.reject)
if help: if help:
qconnect( help_button = b.button(QDialogButtonBox.StandardButton.Help)
b.button(QDialogButtonBox.StandardButton.Help).clicked, assert help_button is not None
self.helpRequested, qconnect(help_button.clicked, self.helpRequested)
)
self.l.setFocus() self.l.setFocus()
def accept(self) -> None: def accept(self) -> None:
@ -520,6 +538,7 @@ class GetTextDialog(QDialog):
return QDialog.reject(self) return QDialog.reject(self)
def helpRequested(self) -> None: def helpRequested(self) -> None:
if self.help is not None:
openHelp(self.help) openHelp(self.help)
@ -624,6 +643,7 @@ def getFile(
if dir and key: if dir and key:
raise Exception("expected dir or key") raise Exception("expected dir or key")
if not dir: if not dir:
assert aqt.mw.pm.profile is not None
dirkey = f"{key}Directory" dirkey = f"{key}Directory"
dir = aqt.mw.pm.profile.get(dirkey, "") dir = aqt.mw.pm.profile.get(dirkey, "")
else: else:
@ -635,6 +655,7 @@ def getFile(
else QFileDialog.FileMode.ExistingFile else QFileDialog.FileMode.ExistingFile
) )
d.setFileMode(mode) d.setFileMode(mode)
assert dir is not None
if os.path.exists(dir): if os.path.exists(dir):
d.setDirectory(dir) d.setDirectory(dir)
d.setWindowTitle(title) d.setWindowTitle(title)
@ -644,6 +665,7 @@ def getFile(
def accept() -> None: def accept() -> None:
files = list(d.selectedFiles()) files = list(d.selectedFiles())
if dirkey: if dirkey:
assert aqt.mw.pm.profile is not None
dir = os.path.dirname(files[0]) dir = os.path.dirname(files[0])
aqt.mw.pm.profile[dirkey] = dir aqt.mw.pm.profile[dirkey] = dir
result = files if multi else files[0] result = files if multi else files[0]
@ -683,10 +705,11 @@ def getSaveFile(
dir_description: str, dir_description: str,
key: str, key: str,
ext: str, ext: str,
fname: str | None = None, fname: str = "",
) -> str: ) -> str | None:
"""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."""
assert aqt.mw.pm.profile is not None
config_key = f"{dir_description}Directory" config_key = f"{dir_description}Directory"
defaultPath = QStandardPaths.writableLocation( defaultPath = QStandardPaths.writableLocation(
@ -709,8 +732,9 @@ def getSaveFile(
dir = os.path.dirname(file) dir = os.path.dirname(file)
aqt.mw.pm.profile[config_key] = dir aqt.mw.pm.profile[config_key] = dir
# check if it exists # check if it exists
if os.path.exists(file): if os.path.exists(file) and not askUser(
if not askUser(tr.qt_misc_this_file_exists_are_you_sure(), parent): tr.qt_misc_this_file_exists_are_you_sure(), parent
):
return None return None
return file return file
@ -735,6 +759,7 @@ def _qt_state_key(kind: _QtStateKeyKind, key: str) -> str:
def saveGeom(widget: QWidget, key: str) -> None: def saveGeom(widget: QWidget, key: str) -> None:
# restoring a fullscreen window breaks the tab functionality of 5.15 # restoring a fullscreen window breaks the tab functionality of 5.15
if not widget.isFullScreen() or qtmajor == 6: if not widget.isFullScreen() or qtmajor == 6:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key) key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key)
aqt.mw.pm.profile[key] = widget.saveGeometry() aqt.mw.pm.profile[key] = widget.saveGeometry()
@ -745,6 +770,7 @@ def restoreGeom(
adjustSize: bool = False, adjustSize: bool = False,
default_size: tuple[int, int] | None = None, default_size: tuple[int, int] | None = None,
) -> None: ) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key) key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key)
if existing_geom := aqt.mw.pm.profile.get(key): if existing_geom := aqt.mw.pm.profile.get(key):
widget.restoreGeometry(existing_geom) widget.restoreGeometry(existing_geom)
@ -756,7 +782,9 @@ def restoreGeom(
def ensureWidgetInScreenBoundaries(widget: QWidget) -> None: def ensureWidgetInScreenBoundaries(widget: QWidget) -> None:
handle = widget.window().windowHandle() window = widget.window()
assert window is not None
handle = window.windowHandle()
if not handle: if not handle:
# window has not yet been shown, retry later # window has not yet been shown, retry later
aqt.mw.progress.timer( aqt.mw.progress.timer(
@ -765,7 +793,9 @@ def ensureWidgetInScreenBoundaries(widget: QWidget) -> None:
return return
# ensure widget is smaller than screen bounds # ensure widget is smaller than screen bounds
geom = handle.screen().availableGeometry() screen = handle.screen()
assert screen is not None
geom = screen.availableGeometry()
wsize = widget.size() wsize = widget.size()
cappedWidth = min(geom.width(), wsize.width()) cappedWidth = min(geom.width(), wsize.width())
cappedHeight = min(geom.height(), wsize.height()) cappedHeight = min(geom.height(), wsize.height())
@ -784,44 +814,52 @@ def ensureWidgetInScreenBoundaries(widget: QWidget) -> None:
def saveState(widget: QFileDialog | QMainWindow, key: str) -> None: def saveState(widget: QFileDialog | QMainWindow, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.STATE, key) key = _qt_state_key(_QtStateKeyKind.STATE, key)
aqt.mw.pm.profile[key] = widget.saveState() aqt.mw.pm.profile[key] = widget.saveState()
def restoreState(widget: QFileDialog | QMainWindow, key: str) -> None: def restoreState(widget: QFileDialog | QMainWindow, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.STATE, key) key = _qt_state_key(_QtStateKeyKind.STATE, key)
if data := aqt.mw.pm.profile.get(key): if data := aqt.mw.pm.profile.get(key):
widget.restoreState(data) widget.restoreState(data)
def saveSplitter(widget: QSplitter, key: str) -> None: def saveSplitter(widget: QSplitter, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.SPLITTER, key) key = _qt_state_key(_QtStateKeyKind.SPLITTER, key)
aqt.mw.pm.profile[key] = widget.saveState() aqt.mw.pm.profile[key] = widget.saveState()
def restoreSplitter(widget: QSplitter, key: str) -> None: def restoreSplitter(widget: QSplitter, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.SPLITTER, key) key = _qt_state_key(_QtStateKeyKind.SPLITTER, key)
if data := aqt.mw.pm.profile.get(key): if data := aqt.mw.pm.profile.get(key):
widget.restoreState(data) widget.restoreState(data)
def saveHeader(widget: QHeaderView, key: str) -> None: def saveHeader(widget: QHeaderView, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.HEADER, key) key = _qt_state_key(_QtStateKeyKind.HEADER, key)
aqt.mw.pm.profile[key] = widget.saveState() aqt.mw.pm.profile[key] = widget.saveState()
def restoreHeader(widget: QHeaderView, key: str) -> None: def restoreHeader(widget: QHeaderView, key: str) -> None:
assert aqt.mw.pm.profile is not None
key = _qt_state_key(_QtStateKeyKind.HEADER, key) key = _qt_state_key(_QtStateKeyKind.HEADER, key)
if state := aqt.mw.pm.profile.get(key): if state := aqt.mw.pm.profile.get(key):
widget.restoreState(state) widget.restoreState(state)
def save_is_checked(widget: QCheckBox, key: str) -> None: def save_is_checked(widget: QCheckBox, key: str) -> None:
assert aqt.mw.pm.profile is not None
key += "IsChecked" key += "IsChecked"
aqt.mw.pm.profile[key] = widget.isChecked() aqt.mw.pm.profile[key] = widget.isChecked()
def restore_is_checked(widget: QCheckBox, key: str) -> None: def restore_is_checked(widget: QCheckBox, key: str) -> None:
assert aqt.mw.pm.profile is not None
key += "IsChecked" key += "IsChecked"
if aqt.mw.pm.profile.get(key) is not None: if aqt.mw.pm.profile.get(key) is not None:
widget.setChecked(aqt.mw.pm.profile[key]) widget.setChecked(aqt.mw.pm.profile[key])
@ -847,8 +885,11 @@ def restore_combo_index_for_session(
def save_combo_history(comboBox: QComboBox, history: list[str], name: str) -> str: def save_combo_history(comboBox: QComboBox, history: list[str], name: str) -> str:
assert aqt.mw.pm.profile is not None
name += "BoxHistory" name += "BoxHistory"
text_input = comboBox.lineEdit().text() line_edit = comboBox.lineEdit()
assert line_edit is not None
text_input = line_edit.text()
if text_input in history: if text_input in history:
history.remove(text_input) history.remove(text_input)
history.insert(0, text_input) history.insert(0, text_input)
@ -861,14 +902,17 @@ def save_combo_history(comboBox: QComboBox, history: list[str], name: str) -> st
def restore_combo_history(comboBox: QComboBox, name: str) -> list[str]: def restore_combo_history(comboBox: QComboBox, name: str) -> list[str]:
assert aqt.mw.pm.profile is not None
name += "BoxHistory" name += "BoxHistory"
history = aqt.mw.pm.profile.get(name, []) history = aqt.mw.pm.profile.get(name, [])
comboBox.addItems([""] + history) comboBox.addItems([""] + history)
if history: if history:
session_input = aqt.mw.pm.session.get(name) session_input = aqt.mw.pm.session.get(name)
if session_input and session_input == history[0]: if session_input and session_input == history[0]:
comboBox.lineEdit().setText(session_input) line_edit = comboBox.lineEdit()
comboBox.lineEdit().selectAll() assert line_edit is not None
line_edit.setText(session_input)
line_edit.selectAll()
return history return history
@ -980,7 +1024,7 @@ def send_to_trash(path: Path) -> None:
except Exception as exc: except Exception as exc:
# Linux users may not have a trash folder set up # Linux users may not have a trash folder set up
print("trash failure:", path, exc) print("trash failure:", path, exc)
if path.is_dir: if path.is_dir():
shutil.rmtree(path) shutil.rmtree(path)
else: else:
path.unlink() path.unlink()
@ -1005,7 +1049,8 @@ def tooltip(
class CustomLabel(QLabel): class CustomLabel(QLabel):
silentlyClose = True silentlyClose = True
def mousePressEvent(self, evt: QMouseEvent) -> None: def mousePressEvent(self, evt: QMouseEvent | None) -> None:
assert evt is not None
evt.accept() evt.accept()
self.hide() self.hide()
@ -1074,7 +1119,7 @@ class MenuList:
print( print(
"MenuList will be removed; please copy it into your add-on's code if you need it." "MenuList will be removed; please copy it into your add-on's code if you need it."
) )
self.children: list[MenuListChild] = [] self.children: list[MenuListChild | None] = []
def addItem(self, title: str, func: Callable) -> MenuItem: def addItem(self, title: str, func: Callable) -> MenuItem:
item = MenuItem(title, func) item = MenuItem(title, func)
@ -1114,6 +1159,7 @@ class SubMenu(MenuList):
def renderTo(self, menu: QMenu) -> None: def renderTo(self, menu: QMenu) -> None:
submenu = menu.addMenu(self.title) submenu = menu.addMenu(self.title)
assert submenu is not None
super().renderTo(submenu) super().renderTo(submenu)
@ -1124,6 +1170,7 @@ class MenuItem:
def renderTo(self, qmenu: QMenu) -> None: def renderTo(self, qmenu: QMenu) -> None:
a = qmenu.addAction(self.title) a = qmenu.addAction(self.title)
assert a is not None
qconnect(a.triggered, self.func) qconnect(a.triggered, self.func)