use keyword args for calls with more than one argument

This commit is contained in:
Damien Elmes 2020-05-24 09:05:48 +10:00
parent 89dde3aeb0
commit 38508c3ad7
21 changed files with 89 additions and 90 deletions

View file

@ -723,7 +723,7 @@ message GetChangedTagsOut {
message SetConfigJsonIn {
string key = 1;
bytes val = 2;
bytes value_json = 2;
}
enum StockNoteType {

View file

@ -46,12 +46,12 @@ PROTODEPS := ../proto/backend.proto ../proto/fluent.proto
perl -i'' -pe 's/from fluent_pb2/from anki.fluent_pb2/' anki/backend_pb2.pyi
perl -i'' -pe 's/import fluent_pb2/import anki.fluent_pb2/' anki/backend_pb2.py
python tools/genbackend.py
python -m black anki/rsbackend.py
python -m black -t py36 anki/rsbackend.py
@touch $@
.build/hooks: tools/genhooks.py tools/hookslib.py
python tools/genhooks.py
python -m black anki/hooks.py
python -m black -t py36 anki/hooks.py
@touch $@
BUILD_STEPS := .build/vernum .build/run-deps .build/dev-deps anki/buildinfo.py .build/py-proto .build/hooks

View file

@ -26,13 +26,7 @@ from anki.lang import _
from anki.media import MediaManager, media_paths_from_col_path
from anki.models import ModelManager
from anki.notes import Note
from anki.rsbackend import (
TR,
DBError,
FormatTimeSpanContext,
RustBackend,
pb,
)
from anki.rsbackend import TR, DBError, FormatTimeSpanContext, RustBackend, pb
from anki.sched import Scheduler as V1Scheduler
from anki.schedv2 import Scheduler as V2Scheduler
from anki.tags import TagManager
@ -86,7 +80,7 @@ class Collection:
seconds: float,
context: FormatTimeSpanContext = FormatTimeSpanContext.INTERVALS,
) -> str:
return self.backend.format_timespan(seconds, context)
return self.backend.format_timespan(seconds=seconds, context=context)
# Scheduler
##########################################################################
@ -246,7 +240,12 @@ class Collection:
log_path = self.path.replace(".anki2", "2.log")
# connect
self.backend.open_collection(self.path, media_dir, media_db, log_path)
self.backend.open_collection(
collection_path=self.path,
media_folder_path=media_dir,
media_db_path=media_db,
log_path=log_path,
)
self.db = DBProxy(weakref.proxy(self.backend))
self.db.begin()
@ -317,7 +316,7 @@ class Collection:
return Note(self, self.models.current(forDeck))
def add_note(self, note: Note, deck_id: int) -> None:
note.id = self.backend.add_note(note.to_backend_note(), deck_id)
note.id = self.backend.add_note(note=note.to_backend_note(), deck_id=deck_id)
def addNote(self, note: Note) -> int:
self.add_note(note, note.model()["did"])
@ -423,7 +422,7 @@ select id from notes where id in %s and id not in (select nid from cards)"""
mode = pb.SortOrder(
builtin=pb.BuiltinSearchOrder(kind=kind, reverse=reverse)
)
return self.backend.search_cards(query, mode)
return self.backend.search_cards(search=query, order=mode)
def find_notes(self, query: str) -> Sequence[int]:
return self.backend.search_notes(query)

View file

@ -37,7 +37,7 @@ class ConfigManager:
raise KeyError
def set(self, key: str, val: Any) -> None:
self.col.backend.set_config_json(key, to_json_bytes(val))
self.col.backend.set_config_json(key=key, value_json=to_json_bytes(val))
def remove(self, key: str) -> None:
self.col.backend.remove_config(key)

View file

@ -205,7 +205,7 @@ class DeckManager:
"Add or update an existing deck. Used for syncing and merging."
try:
g["id"] = self.col.backend.add_or_update_deck_legacy(
to_json_bytes(g), preserve_usn
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
)
except anki.rsbackend.DeckIsFilteredError:
raise DeckRenameError("deck was filtered")
@ -284,7 +284,7 @@ class DeckManager:
def update_config(self, conf: Dict[str, Any], preserve_usn=False) -> None:
conf["id"] = self.col.backend.add_or_update_deck_config_legacy(
to_json_bytes(conf), preserve_usn
config=to_json_bytes(conf), preserve_usn_and_mtime=preserve_usn
)
def add_config(

View file

@ -38,7 +38,14 @@ def findReplace(
fold: bool = True,
) -> int:
"Find and replace fields in a note. Returns changed note count."
return col.backend.find_and_replace(nids, src, dst, regex, not fold, field)
return col.backend.find_and_replace(
nids=nids,
search=src,
replacement=dst,
regex=regex,
match_case=not fold,
field_name=field,
)
def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]:

View file

@ -86,7 +86,7 @@ def render_latex_returning_errors(
header = model["latexPre"]
footer = model["latexPost"]
proto = col.backend.extract_latex(html, svg, expand_clozes)
proto = col.backend.extract_latex(text=html, svg=svg, expand_clozes=expand_clozes)
out = ExtractedLatexOutput.from_proto(proto)
errors = []
html = out.html

View file

@ -96,7 +96,7 @@ class MediaManager:
"""Write the file to the media folder, renaming if not unique.
Returns possibly-renamed filename."""
return self.col.backend.add_media_file(desired_fname, data)
return self.col.backend.add_media_file(desired_name=desired_fname, data=data)
def add_extension_based_on_mime(self, fname: str, content_type: str) -> str:
"If jpg or png mime, add .png/.jpg if missing extension."

View file

@ -223,7 +223,7 @@ class ModelManager:
self._remove_from_cache(m["id"])
self.ensureNameUnique(m)
m["id"] = self.col.backend.add_or_update_notetype(
to_json_bytes(m), preserve_usn_and_mtime=preserve_usn
json=to_json_bytes(m), preserve_usn_and_mtime=preserve_usn
)
self.setCurrent(m)
self._mutate_after_write(m)

View file

@ -15,19 +15,7 @@ import enum
import json
import os
from dataclasses import dataclass
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
NewType,
NoReturn,
Optional,
Sequence,
Tuple,
Union,
)
from typing import Any, Dict, List, Optional, Sequence, Union
import ankirspy # pytype: disable=import-error
@ -37,9 +25,7 @@ from anki import hooks
from anki.dbproxy import Row as DBRow
from anki.dbproxy import ValueForDB
from anki.fluent_pb2 import FluentString as TR
from anki.sound import AVTag, SoundOrVideoTag, TTSTag
from anki.types import assert_impossible_literal
from anki.utils import intTime
assert ankirspy.buildhash() == anki.buildinfo.buildhash
@ -54,19 +40,13 @@ StockNoteType = pb.StockNoteType
try:
import orjson
to_json_bytes = orjson.dumps
from_json_bytes = orjson.loads
except:
# add compat layer for 32 bit builds that can't use orjson
print("reverting to stock json")
class orjson: # type: ignore
def dumps(obj: Any) -> bytes:
return json.dumps(obj).encode("utf8")
loads = json.loads
to_json_bytes = orjson.dumps
from_json_bytes = orjson.loads
to_json_bytes = lambda obj: json.dumps(obj).encode("utf8") # type: ignore
from_json_bytes = json.loads
class Interrupted(Exception):
@ -223,7 +203,7 @@ class RustBackend:
return self._db_command(dict(kind="rollback"))
def _db_command(self, input: Dict[str, Any]) -> Any:
return orjson.loads(self._backend.db_command(orjson.dumps(input)))
return from_json_bytes(self._backend.db_command(to_json_bytes(input)))
def translate(self, key: TR, **kwargs: Union[str, int, float]) -> str:
return self.translate_string(translate_string_in(key, **kwargs))
@ -236,7 +216,7 @@ class RustBackend:
print(
"please use col.format_timespan() instead of col.backend.format_time_span()"
)
return self.format_timespan(seconds, context)
return self.format_timespan(seconds=seconds, context=context)
def _run_command(self, method: int, input: Any) -> bytes:
input_bytes = input.SerializeToString()
@ -253,14 +233,14 @@ class RustBackend:
# @@AUTOGEN@@
def extract_av_tags(self, text: str, question_side: bool) -> pb.ExtractAVTagsOut:
def extract_av_tags(self, *, text: str, question_side: bool) -> pb.ExtractAVTagsOut:
input = pb.ExtractAVTagsIn(text=text, question_side=question_side)
output = pb.ExtractAVTagsOut()
output.ParseFromString(self._run_command(1, input))
return output
def extract_latex(
self, text: str, svg: bool, expand_clozes: bool
self, *, text: str, svg: bool, expand_clozes: bool
) -> pb.ExtractLatexOut:
input = pb.ExtractLatexIn(text=text, svg=svg, expand_clozes=expand_clozes)
output = pb.ExtractLatexOut()
@ -273,14 +253,14 @@ class RustBackend:
output.ParseFromString(self._run_command(3, input))
return output
def render_existing_card(self, card_id: int, browser: bool) -> pb.RenderCardOut:
def render_existing_card(self, *, card_id: int, browser: bool) -> pb.RenderCardOut:
input = pb.RenderExistingCardIn(card_id=card_id, browser=browser)
output = pb.RenderCardOut()
output.ParseFromString(self._run_command(4, input))
return output
def render_uncommitted_card(
self, note: pb.Note, card_ord: int, template: bytes, fill_empty: bool
self, *, note: pb.Note, card_ord: int, template: bytes, fill_empty: bool
) -> pb.RenderCardOut:
input = pb.RenderUncommittedCardIn(
note=note, card_ord=card_ord, template=template, fill_empty=fill_empty
@ -295,7 +275,7 @@ class RustBackend:
output.ParseFromString(self._run_command(6, input))
return output.val
def search_cards(self, search: str, order: pb.SortOrder) -> Sequence[int]:
def search_cards(self, *, search: str, order: pb.SortOrder) -> Sequence[int]:
input = pb.SearchCardsIn(search=search, order=order)
output = pb.SearchCardsOut()
output.ParseFromString(self._run_command(7, input))
@ -309,6 +289,7 @@ class RustBackend:
def find_and_replace(
self,
*,
nids: Sequence[int],
search: str,
replacement: str,
@ -346,13 +327,13 @@ class RustBackend:
output.ParseFromString(self._run_command(12, input))
return output
def studied_today(self, cards: int, seconds: float) -> str:
def studied_today(self, *, cards: int, seconds: float) -> str:
input = pb.StudiedTodayIn(cards=cards, seconds=seconds)
output = pb.String()
output.ParseFromString(self._run_command(13, input))
return output.val
def congrats_learn_message(self, next_due: float, remaining: int) -> str:
def congrats_learn_message(self, *, next_due: float, remaining: int) -> str:
input = pb.CongratsLearnMessageIn(next_due=next_due, remaining=remaining)
output = pb.String()
output.ParseFromString(self._run_command(14, input))
@ -370,7 +351,7 @@ class RustBackend:
output.ParseFromString(self._run_command(16, input))
return output
def add_media_file(self, desired_name: str, data: bytes) -> str:
def add_media_file(self, *, desired_name: str, data: bytes) -> str:
input = pb.AddMediaFileIn(desired_name=desired_name, data=data)
output = pb.String()
output.ParseFromString(self._run_command(17, input))
@ -389,7 +370,7 @@ class RustBackend:
return output
def add_or_update_deck_legacy(
self, deck: bytes, preserve_usn_and_mtime: bool
self, *, deck: bytes, preserve_usn_and_mtime: bool
) -> int:
input = pb.AddOrUpdateDeckLegacyIn(
deck=deck, preserve_usn_and_mtime=preserve_usn_and_mtime
@ -398,7 +379,7 @@ class RustBackend:
output.ParseFromString(self._run_command(20, input))
return output.did
def deck_tree(self, include_counts: bool, top_deck_id: int) -> pb.DeckTreeNode:
def deck_tree(self, *, include_counts: bool, top_deck_id: int) -> pb.DeckTreeNode:
input = pb.DeckTreeIn(include_counts=include_counts, top_deck_id=top_deck_id)
output = pb.DeckTreeNode()
output.ParseFromString(self._run_command(21, input))
@ -429,7 +410,7 @@ class RustBackend:
return output.json
def get_deck_names(
self, skip_empty_default: bool, include_filtered: bool
self, *, skip_empty_default: bool, include_filtered: bool
) -> Sequence[pb.DeckNameID]:
input = pb.GetDeckNamesIn(
skip_empty_default=skip_empty_default, include_filtered=include_filtered
@ -451,7 +432,7 @@ class RustBackend:
return output
def add_or_update_deck_config_legacy(
self, config: bytes, preserve_usn_and_mtime: bool
self, *, config: bytes, preserve_usn_and_mtime: bool
) -> int:
input = pb.AddOrUpdateDeckConfigLegacyIn(
config=config, preserve_usn_and_mtime=preserve_usn_and_mtime
@ -506,7 +487,7 @@ class RustBackend:
output.ParseFromString(self._run_command(37, input))
return output
def add_note(self, note: pb.Note, deck_id: int) -> int:
def add_note(self, *, note: pb.Note, deck_id: int) -> int:
input = pb.AddNoteIn(note=note, deck_id=deck_id)
output = pb.NoteID()
output.ParseFromString(self._run_command(38, input))
@ -523,14 +504,14 @@ class RustBackend:
output.ParseFromString(self._run_command(40, input))
return output
def add_note_tags(self, nids: Sequence[int], tags: str) -> int:
def add_note_tags(self, *, nids: Sequence[int], tags: str) -> int:
input = pb.AddNoteTagsIn(nids=nids, tags=tags)
output = pb.UInt32()
output.ParseFromString(self._run_command(41, input))
return output.val
def update_note_tags(
self, nids: Sequence[int], tags: str, replacement: str, regex: bool
self, *, nids: Sequence[int], tags: str, replacement: str, regex: bool
) -> int:
input = pb.UpdateNoteTagsIn(
nids=nids, tags=tags, replacement=replacement, regex=regex
@ -545,7 +526,7 @@ class RustBackend:
return output.numbers
def after_note_updates(
self, nids: Sequence[int], mark_notes_modified: bool, generate_cards: bool
self, *, nids: Sequence[int], mark_notes_modified: bool, generate_cards: bool
) -> pb.Empty:
input = pb.AfterNoteUpdatesIn(
nids=nids,
@ -562,7 +543,9 @@ class RustBackend:
output.ParseFromString(self._run_command(45, input))
return output.fields
def add_or_update_notetype(self, json: bytes, preserve_usn_and_mtime: bool) -> int:
def add_or_update_notetype(
self, *, json: bytes, preserve_usn_and_mtime: bool
) -> int:
input = pb.AddOrUpdateNotetypeIn(
json=json, preserve_usn_and_mtime=preserve_usn_and_mtime
)
@ -608,6 +591,7 @@ class RustBackend:
def open_collection(
self,
*,
collection_path: str,
media_folder_path: str,
media_db_path: str,
@ -635,7 +619,7 @@ class RustBackend:
output.ParseFromString(self._run_command(55, input))
return output.problems
def sync_media(self, hkey: str, endpoint: str) -> pb.Empty:
def sync_media(self, *, hkey: str, endpoint: str) -> pb.Empty:
input = pb.SyncMediaIn(hkey=hkey, endpoint=endpoint)
output = pb.Empty()
output.ParseFromString(self._run_command(56, input))
@ -659,7 +643,7 @@ class RustBackend:
return output.val
def format_timespan(
self, seconds: float, context: pb.FormatTimespanIn.Context
self, *, seconds: float, context: pb.FormatTimespanIn.Context
) -> str:
input = pb.FormatTimespanIn(seconds=seconds, context=context)
output = pb.String()
@ -667,7 +651,7 @@ class RustBackend:
return output.val
def register_tags(
self, tags: str, preserve_usn: bool, usn: int, clear_first: bool
self, *, tags: str, preserve_usn: bool, usn: int, clear_first: bool
) -> bool:
input = pb.RegisterTagsIn(
tags=tags, preserve_usn=preserve_usn, usn=usn, clear_first=clear_first
@ -694,8 +678,8 @@ class RustBackend:
output.ParseFromString(self._run_command(64, input))
return output.json
def set_config_json(self, key: str, val: bytes) -> pb.Empty:
input = pb.SetConfigJsonIn(key=key, val=val)
def set_config_json(self, *, key: str, value_json: bytes) -> pb.Empty:
input = pb.SetConfigJsonIn(key=key, value_json=value_json)
output = pb.Empty()
output.ParseFromString(self._run_command(65, input))
return output

View file

@ -1270,7 +1270,9 @@ from cards where did in {dids} and queue = {QUEUE_TYPE_LRN}
remaining = remaining or 0
if next and next < self.dayCutoff:
next -= intTime() - self.col.conf["collapseTime"]
return self.col.backend.congrats_learn_message(abs(next), remaining)
return self.col.backend.congrats_learn_message(
next_due=abs(next), remaining=remaining
)
else:
return ""

View file

@ -177,7 +177,7 @@ from revlog where id > ? """
return "<b>" + str(s) + "</b>"
if cards:
b += self.col.backend.studied_today(cards, float(thetime))
b += self.col.backend.studied_today(cards=cards, seconds=float(thetime))
# again/pass count
b += "<br>" + _("Again count: %s") % bold(failed)
if cards:

View file

@ -83,14 +83,16 @@ class TagManager:
def bulk_add(self, nids: List[int], tags: str) -> int:
"""Add space-separate tags to provided notes, returning changed count."""
return self.col.backend.add_note_tags(nids, tags)
return self.col.backend.add_note_tags(nids=nids, tags=tags)
def bulk_update(
self, nids: List[int], tags: str, replacement: str, regex: bool
) -> int:
"""Replace space-separated tags, returning changed count.
Tags replaced with an empty string will be removed."""
return self.col.backend.update_note_tags(nids, tags, replacement, regex)
return self.col.backend.update_note_tags(
nids=nids, tags=tags, replacement=replacement, regex=regex
)
# legacy routines

View file

@ -215,10 +215,10 @@ class TemplateRenderContext:
)
qtext = apply_custom_filters(partial.qnodes, self, front_side=None)
qout = self.col().backend.extract_av_tags(qtext, True)
qout = self.col().backend.extract_av_tags(text=qtext, question_side=True)
atext = apply_custom_filters(partial.anodes, self, front_side=qtext)
aout = self.col().backend.extract_av_tags(atext, False)
aout = self.col().backend.extract_av_tags(text=atext, question_side=False)
output = TemplateRenderOutput(
question_text=qout.text,
@ -237,14 +237,16 @@ class TemplateRenderContext:
if self._template:
# card layout screen
out = self._col.backend.render_uncommitted_card(
self._note.to_backend_note(),
self._card.ord,
to_json_bytes(self._template),
self._fill_empty,
note=self._note.to_backend_note(),
card_ord=self._card.ord,
template=to_json_bytes(self._template),
fill_empty=self._fill_empty,
)
else:
# existing card (eg study mode)
out = self._col.backend.render_existing_card(self._card.id, self._browser)
out = self._col.backend.render_existing_card(
card_id=self._card.id, browser=self._browser
)
return PartiallyRenderedCard.from_proto(out)

View file

@ -80,7 +80,10 @@ def fix_snakecase(name):
def get_input_args(msg):
fields = sorted(msg.fields, key=lambda x: x.number)
return ", ".join(["self"] + [f"{f.name}: {python_type(f)}" for f in fields])
self_star = ["self"]
if len(fields) >= 2:
self_star.append("*")
return ", ".join(self_star + [f"{f.name}: {python_type(f)}" for f in fields])
def get_input_assign(msg):

View file

@ -304,7 +304,7 @@ class CardLayout(QDialog):
self.preview_web.set_bridge_command(self._on_bridge_cmd, self)
if self._isCloze():
nums = self.note.cloze_numbers_in_fields()
nums = list(self.note.cloze_numbers_in_fields())
if self.ord + 1 not in nums:
# current card is empty
nums.append(self.ord + 1)

View file

@ -145,7 +145,7 @@ where id > ?""",
)
cards = cards or 0
thetime = thetime or 0
buf = self.mw.col.backend.studied_today(cards, float(thetime))
buf = self.mw.col.backend.studied_today(cards=cards, seconds=float(thetime))
return buf
def _renderDeckTree(self, top: DeckTreeNode) -> str:

View file

@ -25,7 +25,7 @@ def bodyClass(col, card) -> str:
def allSounds(text) -> List:
print("allSounds() deprecated")
out = aqt.mw.col.backend.extract_av_tags(text, True)
out = aqt.mw.col.backend.extract_av_tags(text=text, question_side=True)
return [
x.filename
for x in av_tags_to_native(out.av_tags)

View file

@ -74,7 +74,7 @@ class MediaSyncer:
gui_hooks.media_sync_did_start_or_stop(True)
def run() -> None:
self.mw.col.backend.sync_media(hkey, self._endpoint())
self.mw.col.backend.sync_media(hkey=hkey, endpoint=self._endpoint())
self.mw.taskman.run_in_background(run, self._on_finished)

View file

@ -89,7 +89,7 @@ class Preferences(QDialog):
f.useCurrent.setCurrentIndex(int(not qc.get("addToCur", True)))
s = self.prefs.sched
s = self.prefs
f.lrnCutoff.setValue(s.learn_ahead_secs / 60.0)
f.timeLimit.setValue(s.time_limit_secs / 60.0)
f.showEstimates.setChecked(s.show_intervals_on_buttons)
@ -122,7 +122,7 @@ class Preferences(QDialog):
qc = d.conf
qc["addToCur"] = not f.useCurrent.currentIndex()
s = self.prefs.sched
s = self.prefs
s.show_remaining_due_counts = f.showProgress.isChecked()
s.show_intervals_on_buttons = f.showEstimates.isChecked()
s.new_review_mix = f.newSpread.currentIndex()

View file

@ -1028,7 +1028,7 @@ impl BackendService for Backend {
self.with_col(|col| {
col.transact(None, |col| {
// ensure it's a well-formed object
let val: JsonValue = serde_json::from_slice(&input.val)?;
let val: JsonValue = serde_json::from_slice(&input.value_json)?;
col.set_config(input.key.as_str(), &val)
})
})