Strange scheduling+import since upp'ing to 2.1.30

Four days ago I upgraded from 2.1.21 to 2.1.30 and since then I’ve been having strange scheduling issues on one of my main decks that I’ve been using for over two years.

First off, when I re-import (which is every day, as I work on the notes in a text file) several times Anki said it has found a lot of changes (e.g., 42 cards) even though I’ve only edited a few.

What is that, is Anki maybe converting some html tags now?

Then there is the scheduling issue.

The screenshot says it all: Hard is at 10 (which is normal for this card) but Good is at 1, so when I swipe right without thinking I end up pushing lots of familiar cards back to the top of the stack… Not fun the next day.

Even though the screenshot is from Ankidroid I do all my importing and a bit of editing on Desktop so the two are always in sync.

Thought a negative step might have come in by mistake, but that’s not the case, my steps are the same as always:
2 15 1440 5760 14400

I’ve been on v2 scheduler for six months and happy with it.

Would greatly appreciate any troubleshooting hints!
Thanks in advance.

If you restore from a backup in a separate profile, you can locate the notes that were updated and compare them - perhaps their HTML code is slightly different.

As for the scheduling issue, I suspect this is your settings rather than any change in Anki - you likely have increased the learning steps without changing the graduating interval and easy interval.

Hi Damian,

Thank you for your reply!

Your hunch that the graduating interval had changed was absolutely correct!

However, this is something that Anki did, not me. How do I know, apart from the fact that I hadn’t opened Options recently? I reviewed the options for four of my decks that live in different option groups, and lo-and-behold, the graduating interval was now 1 instead of 30 — in all groups!

Very glad to have that solved… But it suggests a problem in software. Not saying it’s Anki, who knows, maybe Ankidroid is the one that’s resetting the Graduating Intervals (a bug in some weird alpha?)

EDIT: I confirm that ALL the Graduating Intervals in the profile have been reset to 1 (across maybe 20 option groups).

Regarding the sync-ing, it blows my mind how today again I edited two cards in the text file, re-imported the file, and Anki says that 46 cards have changed. This never used to happen.

Is Anki now tweaking the html when importing text files? This particular file only uses two tags (just grepped them): <i> and <br>

Wishing you a beautiful weekend.

I can’t think of a reason why only your graduating interval would change. If you figure out a set of steps that reproduces the problem, please let me know.

If you compare the text you’re importing to the text in your fields, how does it differ? HTML gets run through a parser when you edit a note or display it in the browse screen, so perhaps there’s something about your source text that is being changed.

Without doing a full analysis, one difference I’m seeing which would account for the systematic ‘updates’ to existing cards is that Anki is now replacing all double quotes with single quotes. Since there are quotes in all html, e.g. class='something_nice', that accounts for the changes.

This did not happen in previous versions of Anki. Would it be possible to respecfully request that Anki revert to the previous behavior of respecting embedded quotes? For those who edit cards by hand like I do, when we re-import, it’s important to see that the number of new cards and updates correspond to what we expect.

Apart from my main handcrafted deck, I have 3000+ lines of Python generating an incredible deck I’m about to release (still need to write the manual and have a few people look at the beta), and the idea of having to look for all the places where to switch out quotes — and to escape them in the context of embedded quotes as in
line = f"the {snake} is <span='carpet_snake'>…"
makes my heart sink…

Thank you for your kind ear, Damian.

IIRC the normalizing of HTML only happens when using the HTML editor on a note, and it has been this way for quite a long time. Presumably that’s what you’re doing? If not, perhaps an add-on is doing it for you?

Hi Damian,

Okay, I tried your assumption.

  • disabled all add-ons
  • restarted Anki
  • import deck #1 over and over without making any changes. Each time, 40 notes updated
  • import deck #1 over and over without making any changes. Each time, 4229 notes updated

Steps to reproduce:

  • create empty deck
  • create test file with a single line:
    he said 'hello' <span class='color'>brightly</span>;the 'other' side <span class='test'>test</span>;some_tag
  • import: 1 note added
  • import again: 1 note added! (duplicate!)
  • inspect the fields:

Front → he said ‘hello’ <span class="color">brightly
Back → the ‘other’ side <span class="test">test

The single quotes inside html get converted, others not.

import deck #1 over and over without making any changes. Each time, 40 notes updated

This is really strange, but can’t reproduce it.

Actually, if just open the current card in the Editor, do nothing and just close it, the first field will lose its focus, Anki will save it and single quotes in HTML attributes in the Front field will be converted to double quotes.

Front: "he said 'hello' <span class=""color"">brightly</span>"
Back:  the 'other' side <span class='test'>test</span>

As far I can see, it’s the same behaviour for Anki 2.1.15 and Anki 2.1.30.

I’m afraid I don’t see any easy way of working around this on Anki’s end - the normalization appears to be happening in the web toolkit’s WYSIWYG editor.

1 Like

Ouch.
Okay, thank you!

In the program that generates the deck I’ll switch to
f"""triple quoted <span class="pop">{strings}</span>"""

The challenge will be the manual file, identifying what exactly webtoolkit id soing there as the only html is <br> and <i>

@dae Damian,
Now that I’ve put double quotes everywhere in the code, I see there are still import differences: in the Anki card, tags are sorted.

Is that also webtoolkit, or could that be a recent Anki feature that is throwing off the update comparison?

In which case before comparing the two fields it would be friendly to do something like a
sorted(tags.split())
on the tags being imported before comparing the two fields, rather than requiring that those who produce the cards always sort their tags.

Thanks in advance for your thoughts.

I’ll be returning to the importing code in the following months, so this may be possible then. In the mean time, perhaps you can sort the tags in your script?

I’ll do that.
I have something like 50 lines where the tags are assembled from various types, but I’ll get over it.
In the case of the file I edit by hand, it’ll be more annoying, will probably just write a script to sort the last field.

Great that you’ll be looking at it in the future: if not, it maybe should be mentioned in the manual that tags need to be sorted, as the discrepancies will surprise people a at the time of updating their decks.

Wishing you a great end of the week!

In case a non-programmer runs into the same problem for a file they edit by hand, here’s a short Python script to sort the tags.

  • replace your file.txt with your file’s name
  • if you have more than two fields (without counting the tags), replace {2} with the number of fields, e.g. {3}
  • if your file’s encoding is neither ASCII nor utf8, don’t proceed
  • the script doesn’t modify your file: the results are in the file prefixed with [sorted]
import re

anki_file = "your file.txt"  # if in the same folder as the script
sorted_tags_file = f"[sorted] {anki_file}"

ANKI_LINE = re.compile(r"""(?m)^(?!#)((?:[^;\r\n]*;){2})([^;\r\n]*)([\r\n]+)""")

with open(anki_file, "r", encoding="utf8") as fin:
    fout = open(sorted_tags_file, "w", encoding="utf8")
    for line in fin:
        match = ANKI_LINE.search(line)
        if match:
            sorted_tags =' '.join(sorted([tag.strip() for tag in match.group(2).split()]))
            fout.write(f"{match.group(1)}{sorted_tags}{match.group(3)}")
        else:
            fout.write(line)
    fout.close()
1 Like