anki/pylib/tests/test_collection.py

175 lines
4.6 KiB
Python
Raw Normal View History

2021-04-13 10:45:05 +02:00
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
# coding: utf-8
import os
import tempfile
2019-12-24 10:14:48 +01:00
from anki.collection import Collection as aopen
2020-04-06 12:09:44 +02:00
from anki.dbproxy import emulate_named_args
from anki.lang import TR, without_unicode_isolation
PEP8 for rest of pylib (#1451) * PEP8 dbproxy.py * PEP8 errors.py * PEP8 httpclient.py * PEP8 lang.py * PEP8 latex.py * Add decorator to deprectate key words * Make replacement for deprecated attribute optional * Use new helper `_print_replacement_warning()` * PEP8 media.py * PEP8 rsbackend.py * PEP8 sound.py * PEP8 stdmodels.py * PEP8 storage.py * PEP8 sync.py * PEP8 tags.py * PEP8 template.py * PEP8 types.py * Fix DeprecatedNamesMixinForModule The class methods need to be overridden with instance methods, so every module has its own dicts. * Use `# pylint: disable=invalid-name` instead of id * PEP8 utils.py * Only decorate `__getattr__` with `@no_type_check` * Fix mypy issue with snakecase Importing it from `anki._vendor` raises attribute errors. * Format * Remove inheritance of DeprecatedNamesMixin There's almost no shared code now and overriding classmethods with instance methods raises mypy issues. * Fix traceback frames of deprecation warnings * remove fn/TimedLog (dae) Neither Anki nor add-ons appear to have been using it * fix some issues with stringcase use (dae) - the wheel was depending on the PyPI version instead of our vendored version - _vendor:stringcase should not have been listed in the anki py_library. We already include the sources in py_srcs, and need to refer to them directly. By listing _vendor:stringcase as well, we were making a top-level stringcase library available, which would have only worked for distributing because the wheel definition was also incorrect. - mypy errors are what caused me to mistakenly add the above - they were because the type: ignore at the top of stringcase.py was causing mypy to completely ignore the file, so it was not aware of any attributes it contained.
2021-10-25 06:50:13 +02:00
from anki.stdmodels import _legacy_add_basic_model, get_stock_notetypes
from anki.utils import is_win
2014-06-03 10:38:47 +02:00
from tests.shared import assertException, getEmptyCol
2019-12-25 05:18:34 +01:00
2017-10-05 06:14:56 +02:00
def test_create_open():
(fd, path) = tempfile.mkstemp(suffix=".anki2", prefix="test_attachNew")
try:
os.close(fd)
os.unlink(path)
except OSError:
pass
col = aopen(path)
# for open()
newPath = col.path
newMod = col.mod
col.close()
del col
2017-10-05 06:14:56 +02:00
# reopen
col = aopen(newPath)
assert col.mod == newMod
col.close()
# non-writeable dir
if is_win:
2019-12-24 10:14:48 +01:00
dir = "c:\root.anki2"
else:
dir = "/attachroot.anki2"
2019-12-25 05:18:34 +01:00
assertException(Exception, lambda: aopen(dir))
# reuse tmp file from before, test non-writeable file
os.chmod(newPath, 0)
2019-12-25 05:18:34 +01:00
assertException(Exception, lambda: aopen(newPath))
os.chmod(newPath, 0o666)
os.unlink(newPath)
2019-12-25 05:18:34 +01:00
def test_noteAddDelete():
col = getEmptyCol()
# add a note
note = col.newNote()
note["Front"] = "one"
note["Back"] = "two"
n = col.addNote(note)
assert n == 1
# test multiple cards - add another template
m = col.models.current()
mm = col.models
2021-06-27 05:49:58 +02:00
t = mm.new_template("Reverse")
2019-12-25 05:18:34 +01:00
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
2021-06-27 05:49:58 +02:00
mm.add_template(m, t)
mm.save(m)
2021-06-27 07:12:22 +02:00
assert col.card_count() == 2
# creating new notes should use both cards
note = col.newNote()
note["Front"] = "three"
note["Back"] = "four"
n = col.addNote(note)
assert n == 2
2021-06-27 07:12:22 +02:00
assert col.card_count() == 4
# check q/a generation
c0 = note.cards()[0]
2021-06-27 04:12:23 +02:00
assert "three" in c0.question()
# it should not be a duplicate
assert not note.fields_check()
# now let's make a duplicate
note2 = col.newNote()
note2["Front"] = "one"
note2["Back"] = ""
assert note2.fields_check()
# empty first field should not be permitted either
note2["Front"] = " "
assert note2.fields_check()
2019-12-25 05:18:34 +01:00
def test_fieldChecksum():
col = getEmptyCol()
note = col.newNote()
note["Front"] = "new"
note["Back"] = "new2"
col.addNote(note)
assert col.db.scalar("select csum from notes") == int("c2a6b03f", 16)
# changing the val should change the checksum
note["Front"] = "newx"
note.flush()
assert col.db.scalar("select csum from notes") == int("302811ae", 16)
2019-12-25 05:18:34 +01:00
def test_addDelTags():
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
col.addNote(note)
note2 = col.newNote()
note2["Front"] = "2"
col.addNote(note2)
# adding for a given id
2021-03-05 11:47:51 +01:00
col.tags.bulk_add([note.id], "foo")
note.load()
note2.load()
assert "foo" in note.tags
assert "foo" not in note2.tags
# should be canonified
2021-03-05 11:47:51 +01:00
col.tags.bulk_add([note.id], "foo aaa")
note.load()
assert note.tags[0] == "aaa"
assert len(note.tags) == 2
2019-12-25 05:18:34 +01:00
def test_timestamps():
col = getEmptyCol()
assert len(col.models.all_names_and_ids()) == len(get_stock_notetypes(col))
for i in range(100):
PEP8 for rest of pylib (#1451) * PEP8 dbproxy.py * PEP8 errors.py * PEP8 httpclient.py * PEP8 lang.py * PEP8 latex.py * Add decorator to deprectate key words * Make replacement for deprecated attribute optional * Use new helper `_print_replacement_warning()` * PEP8 media.py * PEP8 rsbackend.py * PEP8 sound.py * PEP8 stdmodels.py * PEP8 storage.py * PEP8 sync.py * PEP8 tags.py * PEP8 template.py * PEP8 types.py * Fix DeprecatedNamesMixinForModule The class methods need to be overridden with instance methods, so every module has its own dicts. * Use `# pylint: disable=invalid-name` instead of id * PEP8 utils.py * Only decorate `__getattr__` with `@no_type_check` * Fix mypy issue with snakecase Importing it from `anki._vendor` raises attribute errors. * Format * Remove inheritance of DeprecatedNamesMixin There's almost no shared code now and overriding classmethods with instance methods raises mypy issues. * Fix traceback frames of deprecation warnings * remove fn/TimedLog (dae) Neither Anki nor add-ons appear to have been using it * fix some issues with stringcase use (dae) - the wheel was depending on the PyPI version instead of our vendored version - _vendor:stringcase should not have been listed in the anki py_library. We already include the sources in py_srcs, and need to refer to them directly. By listing _vendor:stringcase as well, we were making a top-level stringcase library available, which would have only worked for distributing because the wheel definition was also incorrect. - mypy errors are what caused me to mistakenly add the above - they were because the type: ignore at the top of stringcase.py was causing mypy to completely ignore the file, so it was not aware of any attributes it contained.
2021-10-25 06:50:13 +02:00
_legacy_add_basic_model(col)
assert len(col.models.all_names_and_ids()) == 100 + len(get_stock_notetypes(col))
2019-12-25 05:18:34 +01:00
def test_furigana():
col = getEmptyCol()
mm = col.models
m = mm.current()
# filter should work
2019-12-25 05:18:34 +01:00
m["tmpls"][0]["qfmt"] = "{{kana:Front}}"
mm.save(m)
n = col.newNote()
2019-12-25 05:18:34 +01:00
n["Front"] = "foo[abc]"
col.addNote(n)
c = n.cards()[0]
2021-06-27 04:12:23 +02:00
assert c.question().endswith("abc")
# and should avoid sound
2019-12-25 05:18:34 +01:00
n["Front"] = "foo[sound:abc.mp3]"
n.flush()
2021-06-27 04:12:23 +02:00
assert "anki:play" in c.question(reload=True)
# it shouldn't throw an error while people are editing
2019-12-25 05:18:34 +01:00
m["tmpls"][0]["qfmt"] = "{{kana:}}"
mm.save(m)
2021-06-27 04:12:23 +02:00
c.question(reload=True)
2020-02-16 12:07:40 +01:00
def test_translate():
col = getEmptyCol()
2020-02-20 03:48:46 +01:00
no_uni = without_unicode_isolation
2020-02-16 12:07:40 +01:00
assert (
2021-03-26 03:37:18 +01:00
col.tr.card_template_rendering_front_side_problem()
== "Front template has a problem:"
)
assert no_uni(col.tr.statistics_reviews(reviews=1)) == "1 review"
assert no_uni(col.tr.statistics_reviews(reviews=2)) == "2 reviews"
2020-04-06 12:09:44 +02:00
2020-04-06 12:24:05 +02:00
def test_db_named_args(capsys):
2020-04-06 12:09:44 +02:00
sql = "select a, 2+:test5 from b where arg =:foo and x = :test5"
args = []
kwargs = dict(test5=5, foo="blah")
s, a = emulate_named_args(sql, args, kwargs)
assert s == "select a, 2+?1 from b where arg =?2 and x = ?1"
assert a == [5, "blah"]
2020-04-06 12:24:05 +02:00
# swallow the warning
_ = capsys.readouterr()