# FSRS4Anki Helper conflicts when other addon adjust settings

**URL:** <https://forums.ankiweb.net/t/fsrs4anki-helper-conflicts-when-other-addon-adjust-settings/39371>\
**Category:** Development\
**Created:** [January 8, 2024, 9:21am UTC](https://forums.ankiweb.net/t/fsrs4anki-helper-conflicts-when-other-addon-adjust-settings/39371 "2024-01-08T09:21:30Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![zZH2z](https://sea2.discourse-cdn.com/flex002/user_avatar/forums.ankiweb.net/zzh2z/32/23935_2.png) [@zZH2z](https://forums.ankiweb.net/u/zZH2z)\
**Post date:** [January 8, 2024, 9:21am UTC](https://forums.ankiweb.net/t/fsrs4anki-helper-conflicts-when-other-addon-adjust-settings/39371/1 "2024-01-08T09:21:30Z")

</div>

Hi,

I wrote addon (not published) but it goes in conflict with FSRS4Anki Helper. Can you advise how to improve my code?

Anki error:

```auto
Anki 23.12.1 (1a1d4d54) (ao)
Python 3.9.15 Qt 6.6.1 PyQt 6.6.1
Platform: Windows-10-10.0.22631

Traceback (most recent call last):
  File "aqt.taskman", line 142, in _on_closures_pending
  File "aqt.taskman", line 86, in <lambda>
  File "aqt.taskman", line 106, in wrapped_done
  File "aqt.operations", line 127, in wrapped_done
  File "aqt.reviewer", line 537, in after_answer
  File "aqt.reviewer", line 547, in _after_answering
  File "_aqt.hooks", line 4173, in __call__
  File "C:\Users\szare\AppData\Roaming\Anki2\addons21\759844606\schedule\disperse_siblings.py", line 229, in disperse_siblings_when_review
    mw.col.merge_undo_entries(undo_entry)
  File "anki.collection", line 1021, in merge_undo_entries
  File "anki._backend_generated", line 255, in merge_undo_entries
  File "anki._backend", line 166, in _run_command
anki.errors.InvalidInput: target undo op not found

===Add-ons (active)===
(add-on provided name [Add-on folder, installed at, version, is config changed])
Auto Adjuster ['!AutoAdjuster', 0, 'None', '']
FSRS4Anki Helper ['759844606', 2024-01-06T08:46, 'None', mod]

===IDs of active AnkiWeb add-ons===
759844606

===Add-ons (inactive)===
(add-on provided name [Add-on folder, installed at, version, is config changed])
'' ['edit', 0, 'None', '']
AwesomeTTS - Add speech to your flashcards ['1436550454', 2023-11-29T14:54, 'None', '']
Partial import from apkg file mizmu ['331704845', 2023-03-24T03:08, 'None', mod]

```

When problem appear: when my addon try to edit config of the deck (always when review/relearn goes to 0 but not only):

```auto
    def setNewCount(self, newCount: int):
        if self.rawData["new"]["perDay"] != newCount:
            self.rawData["new"]["perDay"] = newCount
            mw.col.decks.setConf(self.rawData, self.id)
            logger.info(f"[{self.name}] value {newCount} of new cards per day has been saved to the configuration.")
            self.update()
//[...]
def reviewer_did_answer_card(reviewer: Reviewer, card: Card, ease: Literal[1, 2, 3, 4]):
    manager: Manager = Manager()
    manager.update(onlyDeckID=[card.did])
    reviewer.refresh_if_needed()

```

What is the issue?

Full code:

```auto
from aqt import gui_hooks
import logging
from aqt import mw
from aqt.reviewer import Reviewer
import json
import os
from anki.cards import Card
from typing import Literal

logger = logging.getLogger( __name__ )
FORMAT = "%(asctime)s [%(filename)s][%(funcName)s:%(lineno)s][%(levelname)s]: %(message)s"
logFilePath = os.path.join(os.path.dirname(os.path.realpath( __file__ )), "auto_adjuster.log")
file_handler = logging.FileHandler(logFilePath, mode="a")
formatter = logging.Formatter(FORMAT)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.setLevel(logging.DEBUG)
logger.info("#")
logger.info("####################################################################################")
logger.info("#")

class Deck:
    def __init__ (self, rawData, newLimit) -> None:
        self.rawData = rawData
        self.newLimit = newLimit
        self.update()

    def update(self):
        self.id = self.rawData["id"]
        self.name = self.rawData["name"]
        self.configID = self.rawData["conf"]

    def getPrettyConfigData(self):
        return json.dumps(self.rawData, indent=4)

    def getCountCardsCountDoneToday(self):
        query = f"deck:{self.name} rated:1"
        cardsCount = len(mw.col.find_cards(query))
        return cardsCount

    def getCountStillInQueue(self):
        query = f"deck:{self.name} is:due"
        cardsCount = len(mw.col.find_cards(query))
        return cardsCount

class Config:
    def __init__ (self, rawData) -> None:
        self.rawData = rawData
        self.update()

    def update(self):
        self.id = self.rawData["id"]
        self.name = self.rawData["name"]

    def getPrettyConfigData(self):
        return json.dumps(self.rawData, indent=4)

    def setNewCount(self, newCount: int):
        if self.rawData["new"]["perDay"] != newCount:
            self.rawData["new"]["perDay"] = newCount
            mw.col.decks.setConf(self.rawData, self.id)
            logger.info(f"[{self.name}] value {newCount} of new cards per day has been saved to the configuration.")
            self.update()

class Manager:
    def __init__ (self) -> None:
        self.decks = []
        self.configs = []

    def update(self, onlyDeckID: list[int] = []):
        self.decks: list[Deck] = self.getDecks(onlyDeckID=onlyDeckID)
        self.configs = self.getConfigs()

        for deck in self.decks:
            deckConfig: Config = None
            for config in self.configs:
                if config.id == deck.configID:
                    deckConfig = config
                    break
            self.setNewCardsCount(deck=deck, deckConfig=deckConfig)

    def getDecks(self, onlyDeckID: list[int] = []):
        decksList = []
        rawDecks = mw.col.decks.get_all_legacy()
        allowedDecks = mw.addonManager.getConfig( __name__ )["includedDecks"]
        for rawDeck in rawDecks:
            if onlyDeckID == []:
                if rawDeck["name"] in allowedDecks:
                    deck = Deck(rawData=rawDeck, newLimit=allowedDecks[rawDeck["name"]])
                    decksList.append(deck)
            else:
                if rawDeck["id"] in onlyDeckID and rawDeck["name"] in allowedDecks:
                    deck = Deck(rawData=rawDeck, newLimit=allowedDecks[rawDeck["name"]])
                    decksList.append(deck)
        return decksList

    def getConfigs(self):
        configList = []
        rawConfigs = mw.col.decks.all_config()
        for rawConfig in rawConfigs:
            if rawConfig["id"] != 1:
                config = Config(rawData=rawConfig)
                configList.append(config)
        return configList

    def setNewCardsCount(self, deck: Deck, deckConfig: Config):
        countCardsCountDoneToday = deck.getCountCardsCountDoneToday()
        countStillInQueue = deck.getCountStillInQueue()
        logger.debug(f"[{deckConfig.name}][{deck.name}] countCardsCountDoneToday {countCardsCountDoneToday} countStillInQueue {countStillInQueue} newLimit {deck.newLimit}")
        if countStillInQueue != 0:
            deckConfig.setNewCount(newCount=0)
            return
        if countCardsCountDoneToday < deck.newLimit:
            deckConfig.setNewCount(newCount=100)
        else:
            deckConfig.setNewCount(newCount=1)

def profile_did_open():
    manager: Manager = Manager()
    manager.update()

def reviewer_did_answer_card(reviewer: Reviewer, card: Card, ease: Literal[1, 2, 3, 4]):
    manager: Manager = Manager()
    manager.update(onlyDeckID=[card.did])
    reviewer.refresh_if_needed()

gui_hooks.profile_did_open.append(profile_did_open)
gui_hooks.reviewer_did_answer_card.append(reviewer_did_answer_card)

```

---

<div class="post-metadata">

**Author:** ![L.M.Sherlock](https://sea2.discourse-cdn.com/flex002/user_avatar/forums.ankiweb.net/l.m.sherlock/32/16770_2.png) [@L.M.Sherlock](https://forums.ankiweb.net/u/L.M.Sherlock)\
**Post date:** [January 8, 2024, 10:27am UTC](https://forums.ankiweb.net/t/fsrs4anki-helper-conflicts-when-other-addon-adjust-settings/39371/2 "2024-01-08T10:27:52Z")

</div>

I guess your code breaks the undo steps of FSRS helper add-on. For details, please see:

> [@Add-on porting notes for Anki 2.1.45](https://forums.ankiweb.net/t/add-on-porting-notes-for-anki-2-1-45/11212#undoredo-4):
>
> Some porting notes for add-ons wanting to support Anki 2.1.45: (this has been made a wiki post - please add anything you feel would be useful here, and if you don’t have permission, please reply below) Type Hints A reminder that most of Anki’s codebase now has type hints, and you can easily install Anki packages (including betas) with ‘pip install’. Instead of just clicking around in your add-on to see what if anything has broken, investing some time getting mypy working is recommended, as it…

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex002/uploads/anki2/original/1X/8f1279ababc5879d54e4838989f606cfe55af8c7.jpeg) [@system](https://forums.ankiweb.net/u/system)\
**Post date:** [February 7, 2024, 10:28am UTC](https://forums.ankiweb.net/t/fsrs4anki-helper-conflicts-when-other-addon-adjust-settings/39371/3 "2024-02-07T10:28:36Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
