Compare commits

..

No commits in common. "2996476e03a86ea56fd8148e9a434d6f65af890a" and "29260d6a00c36ec79f877f30ebe8e209f9ac5192" have entirely different histories.

View File

@ -190,14 +190,14 @@ class AnkiConnect:
def getModel(self, modelName): def getModel(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
return model return model
def getField(self, model, fieldName): def getField(self, model, fieldName):
fieldMap = self.collection().models.field_map(model) fieldMap = self.collection().models.fieldMap(model)
if fieldName not in fieldMap: if fieldName not in fieldMap:
raise Exception('field was not found in {}: {}'.format(model['name'], fieldName)) raise Exception('field was not found in {}: {}'.format(model['name'], fieldName))
return fieldMap[fieldName][1] return fieldMap[fieldName][1]
@ -214,19 +214,24 @@ class AnkiConnect:
self.window().requireReset() self.window().requireReset()
def stopEditing(self):
if self.collection() is not None:
self.window().maybeReset()
def createNote(self, note): def createNote(self, note):
collection = self.collection() collection = self.collection()
model = collection.models.by_name(note['modelName']) model = collection.models.byName(note['modelName'])
if model is None: if model is None:
raise Exception('model was not found: {}'.format(note['modelName'])) raise Exception('model was not found: {}'.format(note['modelName']))
deck = collection.decks.by_name(note['deckName']) deck = collection.decks.byName(note['deckName'])
if deck is None: if deck is None:
raise Exception('deck was not found: {}'.format(note['deckName'])) raise Exception('deck was not found: {}'.format(note['deckName']))
ankiNote = anki.notes.Note(collection, model) ankiNote = anki.notes.Note(collection, model)
ankiNote.note_type()['did'] = deck['id'] ankiNote.model()['did'] = deck['id']
if 'tags' in note: if 'tags' in note:
ankiNote.tags = note['tags'] ankiNote.tags = note['tags']
@ -316,7 +321,7 @@ class AnkiConnect:
if duplicateScope == 'deck': if duplicateScope == 'deck':
did = deck['id'] did = deck['id']
if duplicateScopeDeckName is not None: if duplicateScopeDeckName is not None:
deck2 = collection.decks.by_name(duplicateScopeDeckName) deck2 = collection.decks.byName(duplicateScopeDeckName)
if deck2 is None: if deck2 is None:
# Invalid deck, so cannot be duplicate # Invalid deck, so cannot be duplicate
return 0 return 0
@ -512,7 +517,7 @@ class AnkiConnect:
@util.api() @util.api()
def deckNames(self): def deckNames(self):
return [x.name for x in self.decks().all_names_and_ids()] return self.decks().allNames()
@util.api() @util.api()
@ -540,8 +545,13 @@ class AnkiConnect:
@util.api() @util.api()
def createDeck(self, deck): def createDeck(self, deck):
self.startEditing() try:
return self.decks().id(deck) self.startEditing()
did = self.decks().id(deck)
finally:
self.stopEditing()
return did
@util.api() @util.api()
@ -559,6 +569,7 @@ class AnkiConnect:
# then move into new deck # then move into new deck
self.collection().db.execute('update cards set usn=?, mod=?, did=? where id in ' + scids, usn, mod, did) self.collection().db.execute('update cards set usn=?, mod=?, did=? where id in ' + scids, usn, mod, did)
self.stopEditing()
@util.api() @util.api()
@ -572,11 +583,14 @@ class AnkiConnect:
# this is dangerous, so let's raise our own exception # this is dangerous, so let's raise our own exception
raise Exception("Since Anki 2.1.28 it's not possible " raise Exception("Since Anki 2.1.28 it's not possible "
"to delete decks without deleting cards as well") "to delete decks without deleting cards as well")
self.startEditing() try:
decks = filter(lambda d: d in self.deckNames(), decks) self.startEditing()
for deck in decks: decks = filter(lambda d: d in self.deckNames(), decks)
did = self.decks().id(deck) for deck in decks:
self.decks().remove([did]) did = self.decks().id(deck)
self.decks().rem(did, cardsToo=cardsToo)
finally:
self.stopEditing()
@util.api() @util.api()
@ -586,7 +600,7 @@ class AnkiConnect:
collection = self.collection() collection = self.collection()
did = collection.decks.id(deck) did = collection.decks.id(deck)
return collection.decks.config_dict_for_deck_id(did) return collection.decks.confForDid(did)
@util.api() @util.api()
@ -600,7 +614,7 @@ class AnkiConnect:
return False return False
try: try:
collection.decks.save(config) collection.decks.save(config)
collection.decks.update_config(config) collection.decks.updateConf(config)
except: except:
return False return False
return True return True
@ -634,8 +648,8 @@ class AnkiConnect:
if configId not in [c['id'] for c in collection.decks.all_config()]: if configId not in [c['id'] for c in collection.decks.all_config()]:
return False return False
config = collection.decks.get_config(configId) config = collection.decks.getConf(configId)
return collection.decks.add_config_returning_id(name, config) return collection.decks.confId(name, config)
@util.api() @util.api()
@ -644,7 +658,7 @@ class AnkiConnect:
if int(configId) not in [c['id'] for c in collection.decks.all_config()]: if int(configId) not in [c['id'] for c in collection.decks.all_config()]:
return False return False
collection.decks.remove_config(configId) collection.decks.remConf(configId)
return True return True
@util.api() @util.api()
@ -708,7 +722,10 @@ class AnkiConnect:
@util.api() @util.api()
def deleteMediaFile(self, filename): def deleteMediaFile(self, filename):
self.media().trash_files([filename]) try:
self.media().syncDelete(filename)
except AttributeError:
self.media().trash_files([filename])
@util.api() @util.api()
def getMediaDirPath(self): def getMediaDirPath(self):
@ -724,6 +741,7 @@ class AnkiConnect:
if nCardsAdded < 1: if nCardsAdded < 1:
raise Exception('The field values you have provided would make an empty question on all cards.') raise Exception('The field values you have provided would make an empty question on all cards.')
collection.autosave() collection.autosave()
self.stopEditing()
return ankiNote.id return ankiNote.id
@ -803,6 +821,7 @@ class AnkiConnect:
ankiNote.flush() ankiNote.flush()
self.collection().autosave() self.collection().autosave()
self.stopEditing()
@util.api() @util.api()
@ -840,6 +859,7 @@ class AnkiConnect:
def addTags(self, notes, tags, add=True): def addTags(self, notes, tags, add=True):
self.startEditing() self.startEditing()
self.collection().tags.bulkAdd(notes, tags, add) self.collection().tags.bulkAdd(notes, tags, add)
self.stopEditing()
@util.api() @util.api()
@ -867,9 +887,9 @@ class AnkiConnect:
except NotFoundError: except NotFoundError:
continue continue
if note.has_tag(tag_to_replace): if note.hasTag(tag_to_replace):
note.remove_tag(tag_to_replace) note.delTag(tag_to_replace)
note.add_tag(replace_with_tag) note.addTag(replace_with_tag)
note.flush() note.flush()
self.window().requireReset() self.window().requireReset()
@ -884,9 +904,9 @@ class AnkiConnect:
collection = self.collection() collection = self.collection()
for nid in collection.db.list('select id from notes'): for nid in collection.db.list('select id from notes'):
note = self.getNote(nid) note = self.getNote(nid)
if note.has_tag(tag_to_replace): if note.hasTag(tag_to_replace):
note.remove_tag(tag_to_replace) note.delTag(tag_to_replace)
note.add_tag(replace_with_tag) note.addTag(replace_with_tag)
note.flush() note.flush()
self.window().requireReset() self.window().requireReset()
@ -973,6 +993,7 @@ class AnkiConnect:
scheduler.suspendCards(cards) scheduler.suspendCards(cards)
else: else:
scheduler.unsuspendCards(cards) scheduler.unsuspendCards(cards)
self.stopEditing()
return True return True
@ -1034,7 +1055,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelNames(self): def modelNames(self):
return [n.name for n in self.collection().models.all_names_and_ids()] return self.collection().models.allNames()
@util.api() @util.api()
@ -1044,7 +1065,7 @@ class AnkiConnect:
raise Exception('Must provide at least one field for inOrderFields') raise Exception('Must provide at least one field for inOrderFields')
if len(cardTemplates) == 0: if len(cardTemplates) == 0:
raise Exception('Must provide at least one card for cardTemplates') raise Exception('Must provide at least one card for cardTemplates')
if modelName in [n.name for n in self.collection().models.all_names_and_ids()]: if modelName in self.collection().models.allNames():
raise Exception('Model name already exists') raise Exception('Model name already exists')
collection = self.collection() collection = self.collection()
@ -1057,7 +1078,7 @@ class AnkiConnect:
# Create fields and add them to Note # Create fields and add them to Note
for field in inOrderFields: for field in inOrderFields:
fm = mm.new_field(field) fm = mm.newField(field)
mm.addField(m, fm) mm.addField(m, fm)
# Add shared css to model if exists. Use default otherwise # Add shared css to model if exists. Use default otherwise
@ -1071,7 +1092,7 @@ class AnkiConnect:
if 'Name' in card: if 'Name' in card:
cardName = card['Name'] cardName = card['Name']
t = mm.new_template(cardName) t = mm.newTemplate(cardName)
cardCount += 1 cardCount += 1
t['qfmt'] = card['Front'] t['qfmt'] = card['Front']
t['afmt'] = card['Back'] t['afmt'] = card['Back']
@ -1085,7 +1106,7 @@ class AnkiConnect:
def modelNamesAndIds(self): def modelNamesAndIds(self):
models = {} models = {}
for model in self.modelNames(): for model in self.modelNames():
models[model] = int(self.collection().models.by_name(model)['id']) models[model] = int(self.collection().models.byName(model)['id'])
return models return models
@ -1105,7 +1126,7 @@ class AnkiConnect:
def findModelsByName(self, modelNames): def findModelsByName(self, modelNames):
models = [] models = []
for name in modelNames: for name in modelNames:
model = self.collection().models.by_name(name) model = self.collection().models.byName(name)
if model is None: if model is None:
raise Exception("model was not found: {}".format(name)) raise Exception("model was not found: {}".format(name))
else: else:
@ -1123,7 +1144,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelFieldNames(self, modelName): def modelFieldNames(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
else: else:
@ -1132,7 +1153,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelFieldDescriptions(self, modelName): def modelFieldDescriptions(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
else: else:
@ -1160,7 +1181,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelFieldsOnTemplates(self, modelName): def modelFieldsOnTemplates(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
@ -1191,7 +1212,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelTemplates(self, modelName): def modelTemplates(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
@ -1204,7 +1225,7 @@ class AnkiConnect:
@util.api() @util.api()
def modelStyling(self, modelName): def modelStyling(self, modelName):
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
@ -1214,7 +1235,7 @@ class AnkiConnect:
@util.api() @util.api()
def updateModelTemplates(self, model): def updateModelTemplates(self, model):
models = self.collection().models models = self.collection().models
ankiModel = models.by_name(model['name']) ankiModel = models.byName(model['name'])
if ankiModel is None: if ankiModel is None:
raise Exception('model was not found: {}'.format(model['name'])) raise Exception('model was not found: {}'.format(model['name']))
@ -1236,7 +1257,7 @@ class AnkiConnect:
@util.api() @util.api()
def updateModelStyling(self, model): def updateModelStyling(self, model):
models = self.collection().models models = self.collection().models
ankiModel = models.by_name(model['name']) ankiModel = models.byName(model['name'])
if ankiModel is None: if ankiModel is None:
raise Exception('model was not found: {}'.format(model['name'])) raise Exception('model was not found: {}'.format(model['name']))
@ -1250,13 +1271,13 @@ class AnkiConnect:
if not modelName: if not modelName:
ankiModel = self.collection().models.allNames() ankiModel = self.collection().models.allNames()
else: else:
model = self.collection().models.by_name(modelName) model = self.collection().models.byName(modelName)
if model is None: if model is None:
raise Exception('model was not found: {}'.format(modelName)) raise Exception('model was not found: {}'.format(modelName))
ankiModel = [modelName] ankiModel = [modelName]
updatedModels = 0 updatedModels = 0
for model in ankiModel: for model in ankiModel:
model = self.collection().models.by_name(model) model = self.collection().models.byName(model)
checkForText = False checkForText = False
if css and findText in model['css']: if css and findText in model['css']:
checkForText = True checkForText = True
@ -1345,7 +1366,7 @@ class AnkiConnect:
model = self.getModel(modelName) model = self.getModel(modelName)
field = self.getField(model, fieldName) field = self.getField(model, fieldName)
mm.reposition_field(model, field, index) mm.repositionField(model, field, index)
self.save_model(mm, model) self.save_model(mm, model)
@ -1356,16 +1377,16 @@ class AnkiConnect:
model = self.getModel(modelName) model = self.getModel(modelName)
# only adds the field if it doesn't already exist # only adds the field if it doesn't already exist
fieldMap = mm.field_map(model) fieldMap = mm.fieldMap(model)
if fieldName not in fieldMap: if fieldName not in fieldMap:
field = mm.new_field(fieldName) field = mm.newField(fieldName)
mm.addField(model, field) mm.addField(model, field)
# repositions, even if the field already exists # repositions, even if the field already exists
if index is not None: if index is not None:
fieldMap = mm.field_map(model) fieldMap = mm.fieldMap(model)
newField = fieldMap[fieldName][1] newField = fieldMap[fieldName][1]
mm.reposition_field(model, newField, index) mm.repositionField(model, newField, index)
self.save_model(mm, model) self.save_model(mm, model)
@ -1376,7 +1397,7 @@ class AnkiConnect:
model = self.getModel(modelName) model = self.getModel(modelName)
field = self.getField(model, fieldName) field = self.getField(model, fieldName)
mm.remove_field(model, field) mm.removeField(model, field)
self.save_model(mm, model) self.save_model(mm, model)
@ -1439,7 +1460,7 @@ class AnkiConnect:
if query is None: if query is None:
return [] return []
return list(map(int, self.collection().find_notes(query))) return list(map(int, self.collection().findNotes(query)))
@util.api() @util.api()
@ -1447,7 +1468,7 @@ class AnkiConnect:
if query is None: if query is None:
return [] return []
return list(map(int, self.collection().find_cards(query))) return list(map(int, self.collection().findCards(query)))
@util.api() @util.api()
@ -1456,7 +1477,7 @@ class AnkiConnect:
for cid in cards: for cid in cards:
try: try:
card = self.getCard(cid) card = self.getCard(cid)
model = card.note_type() model = card.model()
note = card.note() note = card.note()
fields = {} fields = {}
for info in model['flds']: for info in model['flds']:
@ -1520,6 +1541,7 @@ class AnkiConnect:
self.startEditing() self.startEditing()
scids = anki.utils.ids2str(cards) scids = anki.utils.ids2str(cards)
self.collection().db.execute('update cards set type=0, queue=0, left=0, ivl=0, due=0, odue=0, factor=0 where id in ' + scids) self.collection().db.execute('update cards set type=0, queue=0, left=0, ivl=0, due=0, odue=0, factor=0 where id in ' + scids)
self.stopEditing()
@util.api() @util.api()
@ -1527,6 +1549,7 @@ class AnkiConnect:
self.startEditing() self.startEditing()
scids = anki.utils.ids2str(cards) scids = anki.utils.ids2str(cards)
self.collection().db.execute('update cards set type=3, queue=1 where id in ' + scids) self.collection().db.execute('update cards set type=3, queue=1 where id in ' + scids)
self.stopEditing()
@util.api() @util.api()
@ -1599,7 +1622,7 @@ class AnkiConnect:
for nid in notes: for nid in notes:
try: try:
note = self.getNote(nid) note = self.getNote(nid)
model = note.note_type() model = note.model()
fields = {} fields = {}
for info in model['flds']: for info in model['flds']:
@ -1626,14 +1649,17 @@ class AnkiConnect:
@util.api() @util.api()
def deleteNotes(self, notes): def deleteNotes(self, notes):
self.collection().remove_notes(notes) try:
self.collection().remNotes(notes)
finally:
self.stopEditing()
@util.api() @util.api()
def removeEmptyNotes(self): def removeEmptyNotes(self):
for model in self.collection().models.all(): for model in self.collection().models.all():
if self.collection().models.use_count(model) == 0: if self.collection().models.useCount(model) == 0:
self.collection().models.remove(model["id"]) self.collection().models.rem(model)
self.window().requireReset() self.window().requireReset()
@ -1699,18 +1725,18 @@ class AnkiConnect:
if note is not None: if note is not None:
collection = self.collection() collection = self.collection()
deck = collection.decks.by_name(note['deckName']) deck = collection.decks.byName(note['deckName'])
if deck is None: if deck is None:
raise Exception('deck was not found: {}'.format(note['deckName'])) raise Exception('deck was not found: {}'.format(note['deckName']))
collection.decks.select(deck['id']) collection.decks.select(deck['id'])
savedMid = deck.pop('mid', None) savedMid = deck.pop('mid', None)
model = collection.models.by_name(note['modelName']) model = collection.models.byName(note['modelName'])
if model is None: if model is None:
raise Exception('model was not found: {}'.format(note['modelName'])) raise Exception('model was not found: {}'.format(note['modelName']))
collection.models.set_current(model) collection.models.setCurrent(model)
collection.models.update(model) collection.models.update(model)
ankiNote = anki.notes.Note(collection, model) ankiNote = anki.notes.Note(collection, model)
@ -1769,7 +1795,7 @@ class AnkiConnect:
reviewer = self.reviewer() reviewer = self.reviewer()
card = reviewer.card card = reviewer.card
model = card.note_type() model = card.model()
note = card.note() note = card.note()
fields = {} fields = {}
@ -1850,7 +1876,7 @@ class AnkiConnect:
def guiDeckOverview(self, name): def guiDeckOverview(self, name):
collection = self.collection() collection = self.collection()
if collection is not None: if collection is not None:
deck = collection.decks.by_name(name) deck = collection.decks.byName(name)
if deck is not None: if deck is not None:
collection.decks.select(deck['id']) collection.decks.select(deck['id'])
self.window().onOverview() self.window().onOverview()
@ -1953,7 +1979,7 @@ class AnkiConnect:
def exportPackage(self, deck, path, includeSched=False): def exportPackage(self, deck, path, includeSched=False):
collection = self.collection() collection = self.collection()
if collection is not None: if collection is not None:
deck = collection.decks.by_name(deck) deck = collection.decks.byName(deck)
if deck is not None: if deck is not None:
exporter = AnkiPackageExporter(collection) exporter = AnkiPackageExporter(collection)
exporter.did = deck['id'] exporter.did = deck['id']
@ -1973,8 +1999,10 @@ class AnkiConnect:
importer = AnkiPackageImporter(collection, path) importer = AnkiPackageImporter(collection, path)
importer.run() importer.run()
except: except:
self.stopEditing()
raise raise
else: else:
self.stopEditing()
return True return True
return False return False