add a bunch of extra hints for mypy

This commit is contained in:
Damien Elmes 2019-12-20 16:34:09 +10:00
parent d8d7e78b6b
commit 12093f2f2e
7 changed files with 46 additions and 51 deletions

View file

@ -8,10 +8,9 @@ from anki.storage import Collection
from anki.utils import intTime, splitFields, joinFields
from anki.importing.base import Importer
from anki.lang import _
from typing import Any, Optional
from typing import Any, Optional, Dict, Tuple, List
from anki.collection import _Collection
from typing import List, Union
GUID = 1
MID = 2
MOD = 3
@ -19,15 +18,16 @@ MOD = 3
class Anki2Importer(Importer):
needMapper = False
deckPrefix = None
deckPrefix: Optional[str] = None
allowUpdate = True
src: _Collection
dst: _Collection
def __init__(self, col: _Collection, file: str) -> None:
super().__init__(col, file)
# set later, defined here for typechecking
self.src = None
self._decks = {}
self._decks: Dict[int,int] = {}
self.mustResetLearning = False
def run(self, media: None = None) -> None:
@ -79,7 +79,7 @@ class Anki2Importer(Importer):
def _importNotes(self) -> None:
# build guid -> (id,mod,mid) hash & map of existing note ids
self._notes = {}
self._notes: Dict[str, Tuple[int,int,int]] = {}
existing = {}
for id, guid, mod, mid in self.dst.db.execute(
"select id, guid, mod, mid from notes"):
@ -87,10 +87,10 @@ class Anki2Importer(Importer):
existing[id] = True
# we may need to rewrite the guid if the model schemas don't match,
# so we need to keep track of the changes for the card import stage
self._changedGuids = {}
self._changedGuids: Dict[str, bool] = {}
# we ignore updates to changed schemas. we need to note the ignored
# guids, so we avoid importing invalid cards
self._ignoredGuids = {}
self._ignoredGuids: Dict[str, bool] = {}
# iterate over source collection
add = []
update = []
@ -188,7 +188,7 @@ class Anki2Importer(Importer):
# determine if note is a duplicate, and adjust mid and/or guid as required
# returns true if note should be added
def _uniquifyNote(self, note: List[Union[int, str]]) -> bool:
def _uniquifyNote(self, note: List[Any]) -> bool:
origGuid = note[GUID]
srcMid = note[MID]
dstMid = self._mid(srcMid)
@ -212,7 +212,7 @@ class Anki2Importer(Importer):
def _prepareModels(self) -> None:
"Prepare index of schema hashes."
self._modelMap = {}
self._modelMap: Dict[int, int] = {}
def _mid(self, srcMid: int) -> Any:
"Return local id for remote MID."
@ -302,7 +302,7 @@ class Anki2Importer(Importer):
if self.mustResetLearning:
self.src.changeSchedulerVer(2)
# build map of (guid, ord) -> cid and used id cache
self._cards = {}
self._cards: Dict[Tuple[str,int], int] = {}
existing = {}
for guid, ord, cid in self.dst.db.execute(
"select f.guid, c.ord, c.id from cards c, notes f "
@ -403,7 +403,7 @@ insert or ignore into revlog values (?,?,?,?,?,?,?,?,?)""", revlog)
with open(path, "rb") as f:
return f.read()
except (IOError, OSError):
return
return b''
def _srcMediaData(self, fname: str) -> bytes:
"Data for FNAME in src collection."
@ -423,8 +423,8 @@ insert or ignore into revlog values (?,?,?,?,?,?,?,?,?)""", revlog)
# the user likely used subdirectories
pass
def _mungeMedia(self, mid: int, fields: str) -> str:
fields = splitFields(fields)
def _mungeMedia(self, mid: int, fieldsStr: str) -> str:
fields = splitFields(fieldsStr)
def repl(match):
fname = match.group("fname")
srcData = self._srcMediaData(fname)

View file

@ -7,18 +7,13 @@ import unicodedata
import json
from anki.utils import tmpfile
from anki.importing.anki2 import Anki2Importer
from typing import Any
from typing import Any, Dict, Optional
from anki.collection import _Collection
class AnkiPackageImporter(Anki2Importer):
nameToNum: Dict[str, str]
zip: Optional[zipfile.ZipFile]
def __init__(self, col: _Collection, file: str) -> None:
super().__init__(col, file)
# set later; set here for typechecking
self.nameToNum = {}
self.zip = None
def run(self) -> None:
def run(self) -> None: # type: ignore
# extract the deck from the zip file
self.zip = z = zipfile.ZipFile(self.file)
# v2 scheduler?
@ -56,5 +51,5 @@ class AnkiPackageImporter(Anki2Importer):
def _srcMediaData(self, fname: str) -> Any:
if fname in self.nameToNum:
return self.zip.read(self.nameToNum[fname])
return self.zip.read(self.nameToNum[fname]) # pytype: disable=attribute-error
return None

View file

@ -3,20 +3,21 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from anki.utils import maxID
from typing import Any
from typing import Any, Optional, List
from anki.collection import _Collection
# Base importer
##########################################################################
from anki.collection import _Collection
class Importer:
needMapper = False
needDelimiter = False
dst: Optional[_Collection]
def __init__(self, col: _Collection, file: str) -> None:
self.file = file
self.log = []
self.log: List[str] = []
self.col = col
self.total = 0
self.dst = None

View file

@ -7,8 +7,7 @@ import re
from anki.importing.noteimp import NoteImporter, ForeignNote
from anki.lang import _
from typing import List
from typing import List, Optional, Any, TextIO, Union
from anki.collection import _Collection
class TextImporter(NoteImporter):
@ -19,10 +18,12 @@ class TextImporter(NoteImporter):
def __init__(self, col: _Collection, file: str) -> None:
NoteImporter.__init__(self, col, file)
self.lines = None
self.fileobj = None
self.delimiter = None
self.tagsToAdd = []
self.fileobj: Optional[TextIO] = None
self.delimiter: Optional[str] = None
self.tagsToAdd: List[str] = []
self.numFields = 0
self.dialect: Optional[Any]
self.data: Optional[Union[str, List[str]]]
def foreignNotes(self) -> List[ForeignNote]:
self.open()

View file

@ -12,20 +12,19 @@ from anki.utils import fieldChecksum, guid64, timestampID, \
joinFields, intTime, splitFields
from anki.importing.base import Importer
from anki.lang import ngettext
from typing import Any, List, Optional
from typing import Any, List, Optional, Tuple, Dict, Union
from anki.collection import _Collection
# Stores a list of fields, tags and deck
######################################################################
from anki.collection import _Collection
from typing import List, Optional, Union
class ForeignNote:
"An temporary object storing fields and attributes."
def __init__(self) -> None:
self.fields = []
self.tags = []
self.fields: List[str] = []
self.tags: List[str] = []
self.deck = None
self.cards = {} # map of ord -> card
self.cards: Dict[int,ForeignCard] = {} # map of ord -> card
self.fieldsStr = ""
class ForeignCard:
@ -56,12 +55,12 @@ class NoteImporter(Importer):
needDelimiter = False
allowHTML = False
importMode = 0
mapping: Optional[List[str]]
def __init__(self, col: _Collection, file: str) -> None:
Importer.__init__(self, col, file)
self.model = col.models.current()
self.mapping = None
self._deckMap = {}
self._tagsMapped = False
def run(self) -> None:
@ -105,14 +104,14 @@ class NoteImporter(Importer):
if f == "_tags":
self._tagsMapped = True
# gather checks for duplicate comparison
csums = {}
csums: Dict[str, List[int]] = {}
for csum, id in self.col.db.execute(
"select csum, id from notes where mid = ?", self.model['id']):
if csum in csums:
csums[csum].append(id)
else:
csums[csum] = [id]
firsts = {}
firsts: Dict[str, bool] = {}
fld0idx = self.mapping.index(self.model['flds'][0]['name'])
self._fmap = self.col.models.fieldMap(self.model)
self._nextID = timestampID(self.col.db, "notes")
@ -122,11 +121,11 @@ class NoteImporter(Importer):
updateLogTxt = _("First field matched: %s")
dupeLogTxt = _("Added duplicate with first field: %s")
new = []
self._ids = []
self._cards = []
self._ids: List[int] = []
self._cards: List[Tuple] = []
self._emptyNotes = False
dupeCount = 0
dupes = []
dupes: List[str] = []
for n in notes:
for c in range(len(n.fields)):
if not self.allowHTML:
@ -228,7 +227,7 @@ content in the text file to the correct fields."""))
self._nextID += 1
self._ids.append(id)
if not self.processFields(n):
return
return None
# note id for card updates later
for ord, c in list(n.cards.items()):
self._cards.append((id, ord, c))
@ -245,7 +244,7 @@ content in the text file to the correct fields."""))
def updateData(self, n: ForeignNote, id: int, sflds: List[str]) -> Optional[list]:
self._ids.append(id)
if not self.processFields(n, sflds):
return
return None
if self._tagsMapped:
self.col.tags.register(n.tags)
tags = self.col.tags.join(n.tags)

View file

@ -6,7 +6,6 @@ import gzip, math, random, time, html
import xml.etree.ElementTree as ET
from anki.importing.noteimp import NoteImporter, ForeignNote, ForeignCard
from anki.stdmodels import addForwardReverse
from typing import List
ONE_DAY = 60*60*24
@ -29,7 +28,7 @@ class PaukerImporter(NoteImporter):
'''Pauker is Front/Back'''
return 2
def foreignNotes(self) -> List[ForeignNote]:
def foreignNotes(self):
'''Build and return a list of notes.'''
notes = []
@ -67,7 +66,7 @@ class PaukerImporter(NoteImporter):
return notes
def _learnedCard(self, batch, timestamp) -> ForeignCard:
def _learnedCard(self, batch, timestamp):
ivl = math.exp(batch)
now = time.time()
due = ivl - (now - timestamp/1000.0)/ONE_DAY

View file

@ -276,7 +276,7 @@ def _incGuid(guid) -> str:
def joinFields(list: List[str]) -> str:
return "\x1f".join(list)
def splitFields(string: str) -> Any:
def splitFields(string: str) -> List[str]:
return string.split("\x1f")
# Checksums