From 63afb0f8c67edbf2cbaf31dc4f0c0de2c176a958 Mon Sep 17 00:00:00 2001 From: David Culley <6276049+davidculley@users.noreply.github.com> Date: Sun, 21 Jul 2024 09:00:52 +0200 Subject: [PATCH] Update type annotation syntax (#3283) * chore: add myself to CONTRIBUTORS file * refactor: use newer type hints for Union/Optional * refactor: fix deprecated type annotations use collections.abc rather than typing * refactor: use lower letter type annotations * style: reformat with black * refactor: remove unused imports * refactor: add missing imports for type hints * fixup! refactor: use newer type hints for Union/Optional * fix: add missing imports for type annotations * fixup! refactor: use newer type hints for Union/Optional * fixup! style: reformat with black * refactor: fix remaining imports re: type hints --- pylib/anki/_backend.py | 3 ++- pylib/anki/collection.py | 3 ++- pylib/anki/dbproxy.py | 3 ++- pylib/anki/decks.py | 3 ++- pylib/anki/exporting.py | 15 ++++++++------- pylib/anki/foreign_data/__init__.py | 6 +++--- pylib/anki/foreign_data/mnemosyne.py | 11 +++++------ pylib/anki/hooks.py | 3 +++ pylib/anki/importing/__init__.py | 3 ++- pylib/anki/importing/anki2.py | 2 +- pylib/anki/importing/csvfile.py | 10 +++++----- pylib/anki/importing/noteimp.py | 12 +++++------- pylib/anki/media.py | 3 ++- pylib/anki/models.py | 3 ++- pylib/anki/notes.py | 3 ++- pylib/anki/scheduler/base.py | 3 ++- pylib/anki/scheduler/legacy.py | 6 ++---- pylib/anki/scheduler/v3.py | 7 ++++--- pylib/anki/stats.py | 3 ++- pylib/anki/tags.py | 3 ++- pylib/anki/template.py | 3 ++- pylib/anki/utils.py | 3 ++- pylib/tests/test_schedv3.py | 2 +- qt/aqt/__init__.py | 19 ++++++++++--------- qt/aqt/about.py | 1 + qt/aqt/addcards.py | 8 ++++---- qt/aqt/addons.py | 3 ++- qt/aqt/browser/browser.py | 3 ++- qt/aqt/browser/find_and_replace.py | 2 +- qt/aqt/browser/sidebar/item.py | 3 ++- qt/aqt/browser/sidebar/toolbar.py | 1 + qt/aqt/browser/sidebar/tree.py | 7 ++++--- qt/aqt/browser/table/__init__.py | 3 ++- qt/aqt/browser/table/model.py | 3 ++- qt/aqt/browser/table/state.py | 3 ++- qt/aqt/browser/table/table.py | 3 ++- qt/aqt/changenotetype.py | 2 +- qt/aqt/clayout.py | 9 +++++---- qt/aqt/customstudy.py | 6 ++---- qt/aqt/debug_console.py | 1 + qt/aqt/deckchooser.py | 2 ++ qt/aqt/deckconf.py | 4 ++-- qt/aqt/editcurrent.py | 1 + qt/aqt/errors.py | 4 ++-- qt/aqt/exporting.py | 3 +-- qt/aqt/fields.py | 10 ++++------ qt/aqt/import_export/exporting.py | 6 +++--- qt/aqt/import_export/importing.py | 4 ++-- qt/aqt/importing.py | 1 + qt/aqt/main.py | 3 ++- qt/aqt/mediacheck.py | 3 ++- qt/aqt/modelchooser.py | 1 + qt/aqt/models.py | 15 +++++++-------- qt/aqt/notetypechooser.py | 2 ++ qt/aqt/operations/card.py | 2 +- qt/aqt/operations/deck.py | 2 +- qt/aqt/operations/note.py | 2 +- qt/aqt/operations/scheduling.py | 2 +- qt/aqt/operations/tag.py | 2 +- qt/aqt/preferences.py | 1 + qt/aqt/profiles.py | 4 ++-- qt/aqt/progress.py | 1 + qt/aqt/qt/qt5_audio.py | 1 + qt/aqt/reviewer.py | 9 +++++---- qt/aqt/stats.py | 1 + qt/aqt/tagedit.py | 2 +- qt/aqt/taglimit.py | 2 +- qt/aqt/theme.py | 4 ++-- qt/aqt/toolbar.py | 5 +++-- qt/aqt/utils.py | 3 ++- qt/aqt/webview.py | 13 +++++++------ 71 files changed, 171 insertions(+), 134 deletions(-) diff --git a/pylib/anki/_backend.py b/pylib/anki/_backend.py index 70e294e77..c3ac2a114 100644 --- a/pylib/anki/_backend.py +++ b/pylib/anki/_backend.py @@ -6,8 +6,9 @@ from __future__ import annotations import sys import time import traceback +from collections.abc import Iterable, Sequence from threading import current_thread, main_thread -from typing import TYPE_CHECKING, Any, Iterable, Sequence +from typing import TYPE_CHECKING, Any from weakref import ref from markdown import markdown diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index a8d5d62b4..e2fa0e1d5 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -3,7 +3,8 @@ from __future__ import annotations -from typing import Any, Generator, Iterable, Literal, Sequence, Union, cast +from collections.abc import Generator, Iterable, Sequence +from typing import Any, Literal, Union, cast from anki import ( ankiweb_pb2, diff --git a/pylib/anki/dbproxy.py b/pylib/anki/dbproxy.py index 331598aa4..ad2154355 100644 --- a/pylib/anki/dbproxy.py +++ b/pylib/anki/dbproxy.py @@ -4,8 +4,9 @@ from __future__ import annotations import re +from collections.abc import Iterable, Sequence from re import Match -from typing import TYPE_CHECKING, Any, Callable, Iterable, Sequence, Union +from typing import TYPE_CHECKING, Any, Callable, Union if TYPE_CHECKING: import anki._backend diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 462806028..e61721dd8 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -4,7 +4,8 @@ from __future__ import annotations import copy -from typing import TYPE_CHECKING, Any, Iterable, NewType, Sequence +from collections.abc import Iterable, Sequence +from typing import TYPE_CHECKING, Any, NewType if TYPE_CHECKING: import anki diff --git a/pylib/anki/exporting.py b/pylib/anki/exporting.py index 1e75adfae..43713d8b2 100644 --- a/pylib/anki/exporting.py +++ b/pylib/anki/exporting.py @@ -13,8 +13,9 @@ import threading import time import unicodedata import zipfile +from collections.abc import Sequence from io import BufferedWriter -from typing import Any, Optional, Sequence +from typing import Any from zipfile import ZipFile from anki import hooks @@ -26,16 +27,16 @@ from anki.utils import ids2str, namedtmp, split_fields, strip_html class Exporter: includeHTML: bool | None = None - ext: Optional[str] = None - includeTags: Optional[bool] = None - includeSched: Optional[bool] = None - includeMedia: Optional[bool] = None + ext: str | None = None + includeTags: bool | None = None + includeSched: bool | None = None + includeMedia: bool | None = None def __init__( self, col: Collection, - did: Optional[DeckId] = None, - cids: Optional[list[CardId]] = None, + did: DeckId | None = None, + cids: list[CardId] | None = None, ) -> None: self.col = col.weakref() self.did = did diff --git a/pylib/anki/foreign_data/__init__.py b/pylib/anki/foreign_data/__init__.py index 50992487b..afcaf685e 100644 --- a/pylib/anki/foreign_data/__init__.py +++ b/pylib/anki/foreign_data/__init__.py @@ -94,8 +94,8 @@ class ForeignCard: class ForeignNote: fields: list[str] = field(default_factory=list) tags: list[str] = field(default_factory=list) - notetype: Union[str, NotetypeId] = "" - deck: Union[str, DeckId] = "" + notetype: str | NotetypeId = "" + deck: str | DeckId = "" cards: list[ForeignCard] = field(default_factory=list) @@ -103,7 +103,7 @@ class ForeignNote: class ForeignData: notes: list[ForeignNote] = field(default_factory=list) notetypes: list[ForeignNotetype] = field(default_factory=list) - default_deck: Union[str, DeckId] = "" + default_deck: str | DeckId = "" def serialize(self) -> str: return json.dumps(self, cls=ForeignDataEncoder, separators=(",", ":")) diff --git a/pylib/anki/foreign_data/mnemosyne.py b/pylib/anki/foreign_data/mnemosyne.py index 4ae3d7f5b..078355571 100644 --- a/pylib/anki/foreign_data/mnemosyne.py +++ b/pylib/anki/foreign_data/mnemosyne.py @@ -17,7 +17,6 @@ Notetype | Card Type import re from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import Tuple, Type from anki.db import DB from anki.decks import DeckId @@ -38,7 +37,7 @@ def serialize(db_path: str, deck_id: DeckId) -> str: def gather_data(db: DB, deck_id: DeckId) -> ForeignData: facts = gather_facts(db) gather_cards_into_facts(db, facts) - used_fact_views: dict[Type[MnemoFactView], bool] = {} + used_fact_views: dict[type[MnemoFactView], bool] = {} notes = [fact.foreign_note(used_fact_views) for fact in facts.values()] notetypes = [fact_view.foreign_notetype() for fact_view in used_fact_views] return ForeignData(notes, notetypes, deck_id) @@ -54,7 +53,7 @@ def open_mnemosyne_db(db_path: str) -> DB: class MnemoFactView(ABC): notetype: str - field_keys: Tuple[str, ...] + field_keys: tuple[str, ...] @classmethod @abstractmethod @@ -162,7 +161,7 @@ class MnemoFact: cards: list[MnemoCard] = field(default_factory=list) def foreign_note( - self, used_fact_views: dict[Type[MnemoFactView], bool] + self, used_fact_views: dict[type[MnemoFactView], bool] ) -> ForeignNote: fact_view = self.fact_view() used_fact_views[fact_view] = True @@ -173,7 +172,7 @@ class MnemoFact: cards=self.foreign_cards(), ) - def fact_view(self) -> Type[MnemoFactView]: + def fact_view(self) -> type[MnemoFactView]: try: fact_view = self.cards[0].fact_view_id except IndexError as err: @@ -190,7 +189,7 @@ class MnemoFact: raise Exception(f"Fact {id} has unknown fact view: {fact_view}") - def anki_fields(self, fact_view: Type[MnemoFactView]) -> list[str]: + def anki_fields(self, fact_view: type[MnemoFactView]) -> list[str]: return [munge_field(self.fields.get(k, "")) for k in fact_view.field_keys] def anki_tags(self) -> list[str]: diff --git a/pylib/anki/hooks.py b/pylib/anki/hooks.py index 9e360ebfa..de2b0d2ea 100644 --- a/pylib/anki/hooks.py +++ b/pylib/anki/hooks.py @@ -14,6 +14,9 @@ modifying it. from __future__ import annotations +from collections.abc import Callable +from typing import Any + import decorator # You can find the definitions in ../tools/genhooks.py diff --git a/pylib/anki/importing/__init__.py b/pylib/anki/importing/__init__.py index 9bd01b0e2..6eb93d9a5 100644 --- a/pylib/anki/importing/__init__.py +++ b/pylib/anki/importing/__init__.py @@ -1,7 +1,8 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -from typing import Any, Callable, Sequence, Type, Union +from collections.abc import Sequence +from typing import Any, Callable, Type, Union import anki from anki.collection import Collection diff --git a/pylib/anki/importing/anki2.py b/pylib/anki/importing/anki2.py index 004fff06b..ba829c412 100644 --- a/pylib/anki/importing/anki2.py +++ b/pylib/anki/importing/anki2.py @@ -5,7 +5,7 @@ import os import unicodedata -from typing import Optional +from typing import Any, Optional from anki.cards import CardId from anki.collection import Collection diff --git a/pylib/anki/importing/csvfile.py b/pylib/anki/importing/csvfile.py index bebbdf5b2..6826ddecf 100644 --- a/pylib/anki/importing/csvfile.py +++ b/pylib/anki/importing/csvfile.py @@ -7,7 +7,7 @@ from __future__ import annotations import csv import re -from typing import Any, Optional, TextIO +from typing import Any, TextIO from anki.collection import Collection from anki.importing.noteimp import ForeignNote, NoteImporter @@ -20,12 +20,12 @@ class TextImporter(NoteImporter): def __init__(self, col: Collection, file: str) -> None: NoteImporter.__init__(self, col, file) self.lines = None - self.fileobj: Optional[TextIO] = None - self.delimiter: Optional[str] = None + self.fileobj: TextIO | None = None + self.delimiter: str | None = None self.tagsToAdd: list[str] = [] self.numFields = 0 - self.dialect: Optional[Any] - self.data: Optional[str | list[str]] + self.dialect: Any | None + self.data: str | list[str] | None def foreignNotes(self) -> list[ForeignNote]: self.open() diff --git a/pylib/anki/importing/noteimp.py b/pylib/anki/importing/noteimp.py index 688e75eca..f69696ef8 100644 --- a/pylib/anki/importing/noteimp.py +++ b/pylib/anki/importing/noteimp.py @@ -7,7 +7,7 @@ from __future__ import annotations import html import unicodedata -from typing import Optional, Union +from typing import Union from anki.collection import Collection from anki.config import Config @@ -76,8 +76,8 @@ class NoteImporter(Importer): needDelimiter = False allowHTML = False importMode = UPDATE_MODE - mapping: Optional[list[str]] - tagModified: Optional[str] + mapping: list[str] | None + tagModified: str | None def __init__(self, col: Collection, file: str) -> None: Importer.__init__(self, col, file) @@ -268,7 +268,7 @@ class NoteImporter(Importer): def updateData( self, n: ForeignNote, id: NoteId, sflds: list[str] - ) -> Optional[Updates]: + ) -> Updates | None: self._ids.append(id) self.processFields(n, sflds) if self._tagsMapped: @@ -316,9 +316,7 @@ where id = ? and flds != ?""", changes2 = self.col.db.scalar("select total_changes()") self.updateCount = changes2 - changes - def processFields( - self, note: ForeignNote, fields: Optional[list[str]] = None - ) -> None: + def processFields(self, note: ForeignNote, fields: list[str] | None = None) -> None: if not fields: fields = [""] * len(self.model["flds"]) for c, f in enumerate(self.mapping): diff --git a/pylib/anki/media.py b/pylib/anki/media.py index 49d2a9d1f..cb7c1ac5f 100644 --- a/pylib/anki/media.py +++ b/pylib/anki/media.py @@ -8,7 +8,8 @@ import pprint import re import sys import time -from typing import Callable, Sequence +from collections.abc import Sequence +from typing import Callable from anki import media_pb2 from anki._legacy import DeprecatedNamesMixin, deprecated_keywords diff --git a/pylib/anki/models.py b/pylib/anki/models.py index 9301ca025..09035b30a 100644 --- a/pylib/anki/models.py +++ b/pylib/anki/models.py @@ -7,7 +7,8 @@ import copy import pprint import sys import time -from typing import Any, NewType, Sequence, Union +from collections.abc import Sequence +from typing import Any, NewType, Union import anki # pylint: disable=unused-import import anki.collection diff --git a/pylib/anki/notes.py b/pylib/anki/notes.py index e0147ac3a..aab8a1b63 100644 --- a/pylib/anki/notes.py +++ b/pylib/anki/notes.py @@ -4,7 +4,8 @@ from __future__ import annotations import copy -from typing import NewType, Sequence +from collections.abc import Sequence +from typing import NewType import anki # pylint: disable=unused-import import anki.cards diff --git a/pylib/anki/scheduler/base.py b/pylib/anki/scheduler/base.py index f1498ef7c..83ef9d393 100644 --- a/pylib/anki/scheduler/base.py +++ b/pylib/anki/scheduler/base.py @@ -22,7 +22,8 @@ ScheduleCardsAsNewDefaults = scheduler_pb2.ScheduleCardsAsNewDefaultsResponse FilteredDeckForUpdate = decks_pb2.FilteredDeckForUpdate RepositionDefaults = scheduler_pb2.RepositionDefaultsResponse -from typing import Sequence, overload +from collections.abc import Sequence +from typing import overload from anki import config_pb2 from anki.cards import CardId diff --git a/pylib/anki/scheduler/legacy.py b/pylib/anki/scheduler/legacy.py index a5e90a677..58bed7933 100644 --- a/pylib/anki/scheduler/legacy.py +++ b/pylib/anki/scheduler/legacy.py @@ -5,8 +5,6 @@ from __future__ import annotations -from typing import Optional - from anki._legacy import deprecated from anki.cards import Card, CardId from anki.consts import ( @@ -54,7 +52,7 @@ class SchedulerBaseWithLegacy(SchedulerBase): print("_nextDueMsg() is obsolete") return "" - def rebuildDyn(self, did: Optional[DeckId] = None) -> Optional[int]: + def rebuildDyn(self, did: DeckId | None = None) -> int | None: did = did or self.col.decks.selected() count = self.rebuild_filtered_deck(did).count or None if not count: @@ -63,7 +61,7 @@ class SchedulerBaseWithLegacy(SchedulerBase): self.col.decks.select(did) return count - def emptyDyn(self, did: Optional[DeckId], lim: Optional[str] = None) -> None: + def emptyDyn(self, did: DeckId | None, lim: str | None = None) -> None: if lim is None: self.empty_filtered_deck(did) return diff --git a/pylib/anki/scheduler/v3.py b/pylib/anki/scheduler/v3.py index d7d9e1837..2a18ee021 100644 --- a/pylib/anki/scheduler/v3.py +++ b/pylib/anki/scheduler/v3.py @@ -14,7 +14,8 @@ as '2' internally. from __future__ import annotations -from typing import Literal, Optional, Sequence +from collections.abc import Sequence +from typing import Any, Literal from anki import frontend_pb2, scheduler_pb2 from anki._legacy import deprecated @@ -109,7 +110,7 @@ class Scheduler(SchedulerBaseWithLegacy): # backend automatically resets queues as operations are performed pass - def getCard(self) -> Optional[Card]: + def getCard(self) -> Card | None: """Fetch the next card from the queue. None if finished.""" try: queued_card = self.get_queued_cards().cards[0] @@ -125,7 +126,7 @@ class Scheduler(SchedulerBaseWithLegacy): "Don't use this, it is a stop-gap until this code is refactored." return not self.get_queued_cards().cards - def counts(self, card: Optional[Card] = None) -> tuple[int, int, int]: + def counts(self, card: Card | None = None) -> tuple[int, int, int]: info = self.get_queued_cards() return (info.new_count, info.learning_count, info.review_count) diff --git a/pylib/anki/stats.py b/pylib/anki/stats.py index dc8997606..4fbc47e07 100644 --- a/pylib/anki/stats.py +++ b/pylib/anki/stats.py @@ -8,7 +8,8 @@ from __future__ import annotations import json import random import time -from typing import Sequence +from collections.abc import Sequence +from typing import Any import anki.cards import anki.collection diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 3f75ca793..a54aa7901 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -13,7 +13,8 @@ from __future__ import annotations import pprint import re -from typing import Collection, Match, Sequence +from collections.abc import Collection, Sequence +from typing import Match import anki # pylint: disable=unused-import import anki.collection diff --git a/pylib/anki/template.py b/pylib/anki/template.py index c4a31c2ef..deda8c819 100644 --- a/pylib/anki/template.py +++ b/pylib/anki/template.py @@ -28,8 +28,9 @@ template_legacy.py file, using the legacy addHook() system. from __future__ import annotations +from collections.abc import Sequence from dataclasses import dataclass -from typing import Any, Sequence, Union +from typing import Any, Union import anki import anki.cards diff --git a/pylib/anki/utils.py b/pylib/anki/utils.py index 150a210fb..929ca3ce1 100644 --- a/pylib/anki/utils.py +++ b/pylib/anki/utils.py @@ -13,9 +13,10 @@ import subprocess import sys import tempfile import time +from collections.abc import Iterable, Iterator from contextlib import contextmanager from hashlib import sha1 -from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator +from typing import TYPE_CHECKING, Any, Callable from anki._legacy import DeprecatedNamesMixinForModule from anki.dbproxy import DBProxy diff --git a/pylib/tests/test_schedv3.py b/pylib/tests/test_schedv3.py index 2a1f79213..d4d4bfd4c 100644 --- a/pylib/tests/test_schedv3.py +++ b/pylib/tests/test_schedv3.py @@ -385,7 +385,7 @@ def test_reviews(): assert "leech" in c.note().tags -def review_limits_setup() -> tuple[anki.collection.Collection, Dict]: +def review_limits_setup() -> tuple[anki.collection.Collection, dict]: col = getEmptyCol() parent = col.decks.get(col.decks.id("parent")) diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index 42e02e1c2..0591b95ff 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -5,6 +5,8 @@ from __future__ import annotations import logging import sys +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Union, cast try: import pip_system_certs.wrapt_requests @@ -50,7 +52,6 @@ import os import tempfile import traceback from pathlib import Path -from typing import TYPE_CHECKING, Any, Callable, Optional, cast import anki.lang from anki._backend import RustBackend @@ -92,8 +93,8 @@ appHelpSite = HELP_SITE from aqt.main import AnkiQt # isort:skip from aqt.profiles import ProfileManager, VideoDriver # isort:skip -profiler: Optional[cProfile.Profile] = None -mw: Optional[AnkiQt] = None # set on init +profiler: cProfile.Profile | None = None +mw: AnkiQt | None = None # set on init import aqt.forms @@ -154,7 +155,7 @@ class DialogManager: def allClosed(self) -> bool: return not any(x[1] for x in self._dialogs.values()) - def closeAll(self, onsuccess: Callable[[], None]) -> Optional[bool]: + def closeAll(self, onsuccess: Callable[[], None]) -> bool | None: # can we close immediately? if self.allClosed(): onsuccess() @@ -181,7 +182,7 @@ class DialogManager: return True def register_dialog( - self, name: str, creator: Union[Callable, type], instance: Optional[Any] = None + self, name: str, creator: Callable | type, instance: Any | None = None ) -> None: """Allows add-ons to register a custom dialog to be managed by Anki's dialog manager, which ensures that only one copy of the window is open at once, @@ -219,13 +220,13 @@ dialogs = DialogManager() # A reference to the Qt translator needs to be held to prevent it from # being immediately deallocated. -_qtrans: Optional[QTranslator] = None +_qtrans: QTranslator | None = None def setupLangAndBackend( pm: ProfileManager, app: QApplication, - force: Optional[str] = None, + force: str | None = None, firstTime: bool = False, ) -> RustBackend: global _qtrans @@ -288,7 +289,7 @@ def setupLangAndBackend( class NativeEventFilter(QAbstractNativeEventFilter): def nativeEventFilter( self, eventType: Any, message: Any - ) -> tuple[bool, Optional[sip.voidptr]]: + ) -> tuple[bool, sip.voidptr | None]: if eventType == "windows_generic_MSG": import ctypes @@ -563,7 +564,7 @@ def run() -> None: ) -def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiApp]: +def _run(argv: list[str] | None = None, exec: bool = True) -> AnkiApp | None: """Start AnkiQt application or reuse an existing instance if one exists. If the function is invoked with exec=False, the AnkiQt will not enter diff --git a/qt/aqt/about.py b/qt/aqt/about.py index 2a3e29224..ec2a71f99 100644 --- a/qt/aqt/about.py +++ b/qt/aqt/about.py @@ -2,6 +2,7 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import platform +from collections.abc import Callable import aqt.forms from anki.lang import without_unicode_isolation diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index 34bfb10c5..bf11e5894 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Callable, Optional +from typing import Callable import aqt.editor import aqt.forms @@ -54,7 +54,7 @@ class AddCards(QMainWindow): self.setupButtons() self.col.add_image_occlusion_notetype() self.history: list[NoteId] = [] - self._last_added_note: Optional[Note] = None + self._last_added_note: Note | None = None gui_hooks.operation_did_execute.append(self.on_operation_did_execute) restoreGeom(self, "add") gui_hooks.add_cards_did_init(self) @@ -195,7 +195,7 @@ class AddCards(QMainWindow): self, old_note.note_type(), new_note.note_type() ) - def _load_new_note(self, sticky_fields_from: Optional[Note] = None) -> None: + def _load_new_note(self, sticky_fields_from: Note | None = None) -> None: note = self._new_note() if old_note := sticky_fields_from: flds = note.note_type()["flds"] @@ -209,7 +209,7 @@ class AddCards(QMainWindow): self.setAndFocusNote(note) def on_operation_did_execute( - self, changes: OpChanges, handler: Optional[object] + self, changes: OpChanges, handler: object | None ) -> None: if (changes.notetype or changes.deck) and handler is not self.editor: self.on_notetype_change( diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index 70561b9a0..313f63b69 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -11,11 +11,12 @@ import os import re import zipfile from collections import defaultdict +from collections.abc import Iterable, Sequence from concurrent.futures import Future from dataclasses import dataclass from datetime import datetime from pathlib import Path -from typing import IO, Any, Callable, Iterable, Sequence, Union +from typing import IO, Any, Callable, Union from urllib.parse import parse_qs, urlparse from zipfile import ZipFile diff --git a/qt/aqt/browser/browser.py b/qt/aqt/browser/browser.py index e8dcff326..f8a673410 100644 --- a/qt/aqt/browser/browser.py +++ b/qt/aqt/browser/browser.py @@ -6,7 +6,8 @@ from __future__ import annotations import json import math import re -from typing import Callable, Sequence +from collections.abc import Sequence +from typing import Any, Callable import aqt import aqt.browser diff --git a/qt/aqt/browser/find_and_replace.py b/qt/aqt/browser/find_and_replace.py index a68c75dbc..c1d51e43c 100644 --- a/qt/aqt/browser/find_and_replace.py +++ b/qt/aqt/browser/find_and_replace.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence import aqt import aqt.forms diff --git a/qt/aqt/browser/sidebar/item.py b/qt/aqt/browser/sidebar/item.py index 6a32097da..e7e4e931b 100644 --- a/qt/aqt/browser/sidebar/item.py +++ b/qt/aqt/browser/sidebar/item.py @@ -2,8 +2,9 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import annotations +from collections.abc import Iterable from enum import Enum, auto -from typing import Callable, Iterable +from typing import Callable from anki.collection import SearchNode from aqt.theme import ColoredIcon diff --git a/qt/aqt/browser/sidebar/toolbar.py b/qt/aqt/browser/sidebar/toolbar.py index a111fe3e4..78906b580 100644 --- a/qt/aqt/browser/sidebar/toolbar.py +++ b/qt/aqt/browser/sidebar/toolbar.py @@ -3,6 +3,7 @@ from __future__ import annotations +from collections.abc import Callable from enum import Enum, auto import aqt diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index ef03cc91e..75fb1a711 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -2,8 +2,9 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import annotations +from collections.abc import Callable, Iterable from enum import Enum, auto -from typing import Iterable, cast +from typing import cast import aqt import aqt.browser @@ -266,7 +267,7 @@ class SidebarTreeView(QTreeView): def update_search( self, - *terms: Union[str, SearchNode], + *terms: str | SearchNode, joiner: SearchJoiner = "AND", ) -> None: """Modify the current search string based on modifier keys, then refresh.""" @@ -524,7 +525,7 @@ class SidebarTreeView(QTreeView): *, root: SidebarItem, name: str, - icon: Union[str, ColoredIcon], + icon: str | ColoredIcon, collapse_key: Config.Bool.V, type: SidebarItemType | None = None, ) -> SidebarItem: diff --git a/qt/aqt/browser/table/__init__.py b/qt/aqt/browser/table/__init__.py index 7be9f1fcb..dc3ed7d5d 100644 --- a/qt/aqt/browser/table/__init__.py +++ b/qt/aqt/browser/table/__init__.py @@ -4,8 +4,9 @@ from __future__ import annotations import copy import time +from collections.abc import Generator, Sequence from dataclasses import dataclass -from typing import TYPE_CHECKING, Generator, Sequence, Union +from typing import TYPE_CHECKING, Union import aqt import aqt.browser diff --git a/qt/aqt/browser/table/model.py b/qt/aqt/browser/table/model.py index 956c51c19..99e2bbb73 100644 --- a/qt/aqt/browser/table/model.py +++ b/qt/aqt/browser/table/model.py @@ -3,7 +3,8 @@ from __future__ import annotations import time -from typing import Any, Callable, Sequence +from collections.abc import Sequence +from typing import Any, Callable import aqt import aqt.browser diff --git a/qt/aqt/browser/table/state.py b/qt/aqt/browser/table/state.py index 91f368844..75ee69ccb 100644 --- a/qt/aqt/browser/table/state.py +++ b/qt/aqt/browser/table/state.py @@ -3,7 +3,8 @@ from __future__ import annotations from abc import ABC, abstractmethod, abstractproperty -from typing import Sequence, cast +from collections.abc import Sequence +from typing import cast from anki.browser import BrowserConfig from anki.cards import Card, CardId diff --git a/qt/aqt/browser/table/table.py b/qt/aqt/browser/table/table.py index 384a28e67..0be52243b 100644 --- a/qt/aqt/browser/table/table.py +++ b/qt/aqt/browser/table/table.py @@ -2,7 +2,8 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import annotations -from typing import Any, Callable, Sequence +from collections.abc import Sequence +from typing import Any, Callable import aqt import aqt.browser diff --git a/qt/aqt/changenotetype.py b/qt/aqt/changenotetype.py index 3f637eabf..0484c2ff8 100644 --- a/qt/aqt/changenotetype.py +++ b/qt/aqt/changenotetype.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence import aqt import aqt.deckconf diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index 19fa0fa22..bdd7f02d3 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -5,8 +5,9 @@ from __future__ import annotations import json import re +from collections.abc import Callable from concurrent.futures import Future -from typing import Any, Match, Optional, cast +from typing import Any, Match, cast import aqt import aqt.forms @@ -50,7 +51,7 @@ class CardLayout(QDialog): mw: AnkiQt, note: Note, ord: int = 0, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, fill_empty: bool = False, ) -> None: QDialog.__init__(self, parent or mw, Qt.WindowType.Window) @@ -509,7 +510,7 @@ class CardLayout(QDialog): # Preview ########################################################################## - _previewTimer: Optional[QTimer] = None + _previewTimer: QTimer | None = None def renderPreview(self) -> None: # schedule a preview when timing stops @@ -590,7 +591,7 @@ class CardLayout(QDialog): return res type_filter = r"\[\[type:.+?\]\]" - repl: Union[str, Callable] + repl: str | Callable if type == "q": repl = "" diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py index d499ae7b3..730f3843b 100644 --- a/qt/aqt/customstudy.py +++ b/qt/aqt/customstudy.py @@ -3,8 +3,6 @@ from __future__ import annotations -from typing import Tuple - import aqt import aqt.forms import aqt.operations @@ -37,12 +35,12 @@ class CustomStudy(QDialog): def fetch_data_and_show(mw: aqt.AnkiQt) -> None: def fetch_data( col: Collection, - ) -> Tuple[DeckId, CustomStudyDefaults]: + ) -> tuple[DeckId, CustomStudyDefaults]: deck_id = mw.col.decks.get_current_id() defaults = col.sched.custom_study_defaults(deck_id) return (deck_id, defaults) - def show_dialog(data: Tuple[DeckId, CustomStudyDefaults]) -> None: + def show_dialog(data: tuple[DeckId, CustomStudyDefaults]) -> None: deck_id, defaults = data CustomStudy(mw=mw, deck_id=deck_id, defaults=defaults) diff --git a/qt/aqt/debug_console.py b/qt/aqt/debug_console.py index a24ade4fc..3ad96fcbf 100644 --- a/qt/aqt/debug_console.py +++ b/qt/aqt/debug_console.py @@ -4,6 +4,7 @@ from __future__ import annotations import os +from collections.abc import Callable from dataclasses import dataclass from functools import partial from pathlib import Path diff --git a/qt/aqt/deckchooser.py b/qt/aqt/deckchooser.py index 6b089d8b2..83af93971 100644 --- a/qt/aqt/deckchooser.py +++ b/qt/aqt/deckchooser.py @@ -3,6 +3,8 @@ from __future__ import annotations +from collections.abc import Callable + from anki.collection import OpChanges from anki.decks import DEFAULT_DECK_ID, DeckId from aqt import AnkiQt, gui_hooks diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py index b28813196..8626f0a6a 100644 --- a/qt/aqt/deckconf.py +++ b/qt/aqt/deckconf.py @@ -173,8 +173,8 @@ class DeckConf(QDialog): # Loading ################################################## - def listToUser(self, l: list[Union[int, float]]) -> str: - def num_to_user(n: Union[int, float]) -> str: + def listToUser(self, l: list[int | float]) -> str: + def num_to_user(n: int | float) -> str: if n == round(n): return str(int(n)) else: diff --git a/qt/aqt/editcurrent.py b/qt/aqt/editcurrent.py index 48140d789..e3e8ab517 100644 --- a/qt/aqt/editcurrent.py +++ b/qt/aqt/editcurrent.py @@ -1,5 +1,6 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +from collections.abc import Callable from typing import Optional import aqt.editor diff --git a/qt/aqt/errors.py b/qt/aqt/errors.py index 41701d372..b1e729dd9 100644 --- a/qt/aqt/errors.py +++ b/qt/aqt/errors.py @@ -5,7 +5,7 @@ from __future__ import annotations import re import time -from typing import TYPE_CHECKING, Optional, TextIO, cast +from typing import TYPE_CHECKING, TextIO, cast from markdown import markdown @@ -169,7 +169,7 @@ class ErrorHandler(QObject): def __init__(self, mw: AnkiQt) -> None: QObject.__init__(self, mw) self.mw = mw - self.timer: Optional[QTimer] = None + self.timer: QTimer | None = None qconnect(self.errorTimer, self._setTimer) self.pool = "" self._oldstderr = sys.stderr diff --git a/qt/aqt/exporting.py b/qt/aqt/exporting.py index 149d486e6..ee41030f7 100644 --- a/qt/aqt/exporting.py +++ b/qt/aqt/exporting.py @@ -7,7 +7,6 @@ import os import re import time from concurrent.futures import Future -from typing import Optional import aqt import aqt.forms @@ -35,7 +34,7 @@ class ExportDialog(QDialog): mw: aqt.main.AnkiQt, did: DeckId | None = None, cids: list[CardId] | None = None, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): QDialog.__init__(self, parent or mw, Qt.WindowType.Window) self.mw = mw diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index 7044e0e85..da81c9ff7 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -3,8 +3,6 @@ from __future__ import annotations -from typing import Optional - import aqt import aqt.forms import aqt.operations @@ -32,7 +30,7 @@ class FieldDialog(QDialog): self, mw: AnkiQt, nt: NotetypeDict, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, open_at: int = 0, ) -> None: QDialog.__init__(self, parent or mw) @@ -62,7 +60,7 @@ class FieldDialog(QDialog): self.form.buttonBox.button(QDialogButtonBox.StandardButton.Save).setAutoDefault( False ) - self.currentIdx: Optional[int] = None + self.currentIdx: int | None = None self.fillFields() self.setupSignals() self.form.fieldList.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) @@ -125,8 +123,8 @@ class FieldDialog(QDialog): self.loadField(idx) def _uniqueName( - self, prompt: str, ignoreOrd: Optional[int] = None, old: str = "" - ) -> Optional[str]: + self, prompt: str, ignoreOrd: int | None = None, old: str = "" + ) -> str | None: txt = getOnlyText(prompt, default=old).replace('"', "").strip() if not txt: return None diff --git a/qt/aqt/import_export/exporting.py b/qt/aqt/import_export/exporting.py index f06d7a47a..a33395f98 100644 --- a/qt/aqt/import_export/exporting.py +++ b/qt/aqt/import_export/exporting.py @@ -7,8 +7,8 @@ import os import re import time from abc import ABC, abstractmethod +from collections.abc import Sequence from dataclasses import dataclass -from typing import Optional, Sequence, Type import aqt.forms import aqt.main @@ -42,7 +42,7 @@ class ExportDialog(QDialog): mw: aqt.main.AnkiQt, did: DeckId | None = None, nids: Sequence[NoteId] | None = None, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): QDialog.__init__(self, parent or mw, Qt.WindowType.Window) self.mw = mw @@ -56,7 +56,7 @@ class ExportDialog(QDialog): self.open() def setup(self, did: DeckId | None) -> None: - self.exporter_classes: list[Type[Exporter]] = [ + self.exporter_classes: list[type[Exporter]] = [ ApkgExporter, ColpkgExporter, NoteCsvExporter, diff --git a/qt/aqt/import_export/importing.py b/qt/aqt/import_export/importing.py index 05a37aece..e7174533e 100644 --- a/qt/aqt/import_export/importing.py +++ b/qt/aqt/import_export/importing.py @@ -5,8 +5,8 @@ from __future__ import annotations import re from abc import ABC, abstractmethod +from collections.abc import Callable from itertools import chain -from typing import Type import aqt.main from anki.collection import Collection, Progress @@ -124,7 +124,7 @@ class JsonImporter(Importer): ImportDialog(mw, JsonFileArgs(path=path)) -IMPORTERS: list[Type[Importer]] = [ +IMPORTERS: list[type[Importer]] = [ ColpkgImporter, ApkgImporter, MnemosyneImporter, diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py index 8ba173f91..a78e4a8d2 100644 --- a/qt/aqt/importing.py +++ b/qt/aqt/importing.py @@ -4,6 +4,7 @@ import os import re import traceback import zipfile +from collections.abc import Callable from concurrent.futures import Future from typing import Any, Optional diff --git a/qt/aqt/main.py b/qt/aqt/main.py index e7159977d..fad9c5829 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -10,8 +10,9 @@ import re import signal import weakref from argparse import Namespace +from collections.abc import Callable, Sequence from concurrent.futures import Future -from typing import Any, Literal, Sequence, TypeVar, cast +from typing import Any, Literal, TypeVar, cast import anki import anki.cards diff --git a/qt/aqt/mediacheck.py b/qt/aqt/mediacheck.py index d9691c500..ec47550d8 100644 --- a/qt/aqt/mediacheck.py +++ b/qt/aqt/mediacheck.py @@ -5,8 +5,9 @@ from __future__ import annotations import itertools import time +from collections.abc import Iterable, Sequence from concurrent.futures import Future -from typing import Iterable, Sequence, TypeVar +from typing import TypeVar import aqt import aqt.progress diff --git a/qt/aqt/modelchooser.py b/qt/aqt/modelchooser.py index f886c65af..f2fceccc2 100644 --- a/qt/aqt/modelchooser.py +++ b/qt/aqt/modelchooser.py @@ -1,6 +1,7 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +from collections.abc import Callable from typing import Optional from aqt import AnkiQt, gui_hooks diff --git a/qt/aqt/models.py b/qt/aqt/models.py index 2ad890616..43b33dabd 100644 --- a/qt/aqt/models.py +++ b/qt/aqt/models.py @@ -3,9 +3,10 @@ from __future__ import annotations +from collections.abc import Callable, Sequence from concurrent.futures import Future from operator import itemgetter -from typing import Any, Optional, Sequence +from typing import Any import aqt.clayout from anki import stdmodels @@ -40,9 +41,9 @@ class Models(QDialog): def __init__( self, mw: AnkiQt, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, fromMain: bool = False, - selected_notetype_id: Optional[NotetypeId] = None, + selected_notetype_id: NotetypeId | None = None, ): self.mw = mw parent = parent or mw @@ -231,13 +232,13 @@ class Models(QDialog): class AddModel(QDialog): - model: Optional[NotetypeDict] + model: NotetypeDict | None def __init__( self, mw: AnkiQt, on_success: Callable[[NotetypeDict], None], - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ) -> None: self.parent_ = parent or mw self.mw = mw @@ -249,9 +250,7 @@ class AddModel(QDialog): self.setWindowModality(Qt.WindowModality.ApplicationModal) disable_help_button(self) # standard models - self.notetypes: list[ - Union[NotetypeDict, Callable[[Collection], NotetypeDict]] - ] = [] + self.notetypes: list[NotetypeDict | Callable[[Collection], NotetypeDict]] = [] for name, func in stdmodels.get_stock_notetypes(self.col): item = QListWidgetItem(tr.notetypes_add(val=name)) self.dialog.models.addItem(item) diff --git a/qt/aqt/notetypechooser.py b/qt/aqt/notetypechooser.py index e8d614ac3..395af193b 100644 --- a/qt/aqt/notetypechooser.py +++ b/qt/aqt/notetypechooser.py @@ -3,6 +3,8 @@ from __future__ import annotations +from collections.abc import Callable + from anki.collection import OpChanges from anki.models import NotetypeId from aqt import AnkiQt, gui_hooks diff --git a/qt/aqt/operations/card.py b/qt/aqt/operations/card.py index 6071336ee..e8b4b23a6 100644 --- a/qt/aqt/operations/card.py +++ b/qt/aqt/operations/card.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from anki.cards import CardId from anki.collection import OpChangesWithCount diff --git a/qt/aqt/operations/deck.py b/qt/aqt/operations/deck.py index bddf07fc2..327f9ab52 100644 --- a/qt/aqt/operations/deck.py +++ b/qt/aqt/operations/deck.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId from anki.decks import DeckCollapseScope, DeckDict, DeckId, UpdateDeckConfigs diff --git a/qt/aqt/operations/note.py b/qt/aqt/operations/note.py index 42b2bc950..4a27c1e21 100644 --- a/qt/aqt/operations/note.py +++ b/qt/aqt/operations/note.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from anki.collection import OpChanges, OpChangesWithCount from anki.decks import DeckId diff --git a/qt/aqt/operations/scheduling.py b/qt/aqt/operations/scheduling.py index c30fdecb8..61d7cc9d4 100644 --- a/qt/aqt/operations/scheduling.py +++ b/qt/aqt/operations/scheduling.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence import aqt import aqt.forms diff --git a/qt/aqt/operations/tag.py b/qt/aqt/operations/tag.py index bf3d25945..2ac4504d0 100644 --- a/qt/aqt/operations/tag.py +++ b/qt/aqt/operations/tag.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from anki.collection import OpChanges, OpChangesWithCount from anki.notes import NoteId diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index f1dab502d..777c32cd4 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -5,6 +5,7 @@ from __future__ import annotations import functools import re +from collections.abc import Callable import anki.lang import aqt diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 185fe4fd3..7da170408 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -10,7 +10,7 @@ import shutil import traceback from enum import Enum from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import anki.lang import aqt.forms @@ -544,7 +544,7 @@ create table if not exists profiles def set_spacebar_rates_card(self, on: bool) -> None: self.meta["spacebar_rates_card"] = on - def get_answer_key(self, ease: int) -> Optional[str]: + def get_answer_key(self, ease: int) -> str | None: return self.meta.setdefault("answer_keys", self.default_answer_keys).get(ease) def set_answer_key(self, ease: int, key: str): diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py index 692268a79..f4f17fb6c 100644 --- a/qt/aqt/progress.py +++ b/qt/aqt/progress.py @@ -3,6 +3,7 @@ from __future__ import annotations import time +from collections.abc import Callable from concurrent.futures import Future from dataclasses import dataclass diff --git a/qt/aqt/qt/qt5_audio.py b/qt/aqt/qt/qt5_audio.py index ffab7477e..cc8426a6e 100644 --- a/qt/aqt/qt/qt5_audio.py +++ b/qt/aqt/qt/qt5_audio.py @@ -8,6 +8,7 @@ PyQt5-only audio code """ import wave +from collections.abc import Callable from concurrent.futures import Future from typing import cast diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index 70afc54cf..5058e5177 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -7,9 +7,10 @@ import functools import json import random import re +from collections.abc import Callable, Sequence from dataclasses import dataclass from enum import Enum, auto -from typing import Any, Literal, Match, Sequence, cast +from typing import Any, Literal, Match, Union, cast import aqt import aqt.browser @@ -568,7 +569,7 @@ class Reviewer: def korean_shortcuts( self, - ) -> Sequence[Union[tuple[str, Callable], tuple[Qt.Key, Callable]]]: + ) -> Sequence[tuple[str, Callable] | tuple[Qt.Key, Callable]]: return [ ("ㄷ", self.mw.onEditCurrent), ("ㅡ", self.showContextMenu), @@ -588,7 +589,7 @@ class Reviewer: def _shortcutKeys( self, - ) -> Sequence[Union[tuple[str, Callable], tuple[Qt.Key, Callable]]]: + ) -> Sequence[tuple[str, Callable] | tuple[Qt.Key, Callable]]: return [ ("e", self.mw.onEditCurrent), (" ", self.onEnterKey), @@ -839,7 +840,7 @@ timerStopped = false; if not self.mw.col.conf["dueCounts"]: return "" - counts: list[Union[int, str]] + counts: list[int | str] idx, counts_ = self._v3.counts() counts = cast(list[Union[int, str]], counts_) counts[idx] = f"{counts[idx]}" diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 388f2d89e..8116f1b2c 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -3,6 +3,7 @@ from __future__ import annotations import time +from collections.abc import Callable from typing import Any import aqt diff --git a/qt/aqt/tagedit.py b/qt/aqt/tagedit.py index 90cbf56ed..c88fc1845 100644 --- a/qt/aqt/tagedit.py +++ b/qt/aqt/tagedit.py @@ -4,7 +4,7 @@ from __future__ import annotations import re -from typing import Iterable +from collections.abc import Iterable from anki.collection import Collection from aqt import gui_hooks diff --git a/qt/aqt/taglimit.py b/qt/aqt/taglimit.py index 5cc172a66..4132deafa 100644 --- a/qt/aqt/taglimit.py +++ b/qt/aqt/taglimit.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Callable, Sequence import aqt import aqt.customstudy diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 6acd5463d..fbbbcda96 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -8,7 +8,7 @@ import os import re import subprocess from dataclasses import dataclass -from typing import Callable, List, Tuple +from typing import Callable import anki.lang import aqt @@ -386,7 +386,7 @@ def get_linux_dark_mode() -> bool: return dbus_response[-1] == PREFER_DARK - dark_mode_detection_strategies: List[Tuple[str, Callable[[str], bool]]] = [ + dark_mode_detection_strategies: list[tuple[str, Callable[[str], bool]]] = [ ( "dbus-send --session --print-reply=literal --reply-timeout=1000 " "--dest=org.freedesktop.portal.Desktop /org/freedesktop/portal/desktop " diff --git a/qt/aqt/toolbar.py b/qt/aqt/toolbar.py index 34b7fa2d3..7313f2a39 100644 --- a/qt/aqt/toolbar.py +++ b/qt/aqt/toolbar.py @@ -4,7 +4,8 @@ from __future__ import annotations import enum import re -from typing import Any, Callable, Optional, cast +from collections.abc import Callable +from typing import Any, cast import aqt from anki.sync import SyncStatus @@ -86,7 +87,7 @@ class TopWebView(ToolbarWebView): self.show() - def _onHeight(self, qvar: Optional[int]) -> None: + def _onHeight(self, qvar: int | None) -> None: super()._onHeight(qvar) if qvar: self.web_height = int(qvar) diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index d89c9fbf6..500306c6e 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -9,9 +9,10 @@ import re import shutil import subprocess import sys +from collections.abc import Sequence from functools import partial, wraps from pathlib import Path -from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence, Union +from typing import TYPE_CHECKING, Any, Callable, Literal, Union from send2trash import send2trash diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 71cb585bc..e711ec01a 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -7,8 +7,9 @@ import dataclasses import json import re import sys +from collections.abc import Sequence from enum import Enum -from typing import TYPE_CHECKING, Any, Callable, Optional, Sequence, cast +from typing import TYPE_CHECKING, Any, Callable, cast import anki import anki.lang @@ -524,10 +525,10 @@ html {{ {font} }} def stdHtml( self, body: str, - css: Optional[list[str]] = None, - js: Optional[list[str]] = None, + css: list[str] | None = None, + js: list[str] | None = None, head: str = "", - context: Optional[Any] = None, + context: Any | None = None, default_css: bool = True, ) -> None: css = (["css/webview.css"] if default_css else []) + ( @@ -705,7 +706,7 @@ html {{ {font} }} def adjustHeightToFit(self) -> None: self.evalWithCallback("document.documentElement.offsetHeight", self._onHeight) - def _onHeight(self, qvar: Optional[int]) -> None: + def _onHeight(self, qvar: int | None) -> None: from aqt import mw if qvar is None: @@ -842,5 +843,5 @@ html {{ {font} }} ) @deprecated(info="use theme_manager.qcolor() instead") - def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor: + def get_window_bg_color(self, night_mode: bool | None = None) -> QColor: return theme_manager.qcolor(colors.CANVAS)