Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate config to standard anki scheme (fixing 91 and 73) #96

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

BorisNA
Copy link

@BorisNA BorisNA commented Dec 19, 2024

Hopefully fix #91 and fix #73

Migrate config to the standard anki scheme

  • load with the anki function (support config-meta scheme)
  • monitor changes from inside the anki and update internal data (do not overwrite these changes with defaults)

Migrate config to the standard anki scheme
- load with the anki function (support config-meta scheme)
- monitor changes from inside the anki and update internal data (do not overwrite these changes with defaults)
Copy link
Contributor

@kieranlblack kieranlblack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! A few comments from me:

  1. This changes the semantics of self.config. Previously it was a defaultdict in which a KeyError would not be thrown on an attempt to access a key which did not exist but now it is only a dict. Is this intentional and have you confirmed this change is safe?

  2. The proposed solution here will mean that any existing config_saved.json will be totally discarded. In order to try and be backwards compatible, we should first check for the existence of this file and if it exists then addonManager.writeConfig it, at least for the next few releases then the check can be ripped out.

  3. This introduces a race condition where if config is updated from within the addon and then config is updated from within the Anki UI, the config from within the addon will be wiped out. Additionally, any config changes made from within the addon will not be visible in the Anki UI until save is called.

  4. It looks like the config updated callback passes the new config as an arg, we can use this for some cleaner code to avoid having intercept things with a lambda to ignore the args then calling getConfig again. Just using self.update as the callback could take care of this and also my point above about the race condition but not the point about changes not appearing in the UI. To fix everything and keep old behaviour would get kind of complicated but IMO we should go for the simplest thing here and rip out all the caching and that save method and fully rely on Anki for the config, no maintaining of a self.config copy.

  5. Now that we have stopped using them, could you remove the extra imports, namely:

from collections import defaultdict
from json import dump, load
from os.path import dirname, exists, join, realpath

Solution for installing in separate plugin directory
Adding loading of the old config  causes all tests to fail. Fix it by checking 'mocked' path in the ConfigManager code.
Copy link
Contributor

@kieranlblack kieranlblack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I appreciate the effort here. I'm thinking this is not the right way forwards.

I think almost all the pitfalls we are looking at can be avoided by removing the self.config variable and instead going through this procedure:

  1. On init, check if old config_saved.json exists, if it doesn't then we are done (firstRun doesn't matter here).
  2. If it does exist then load it, .update the mw.addonManager.getConfig(__name__) config with it then immediately mw.addonManager.writeConfig(__name__, updated_config) it.
  3. If all this worked then move config_saved.json to config_saved.json.bak.

Comment on lines +30 to +39
def _get_old_addon_config_file() -> Path:
apath = Path(mw.pm.addonFolder())
# This is mainly for tests, since 'current-module-dir is mocked, but we cannot mock/patch this function,
# it is called at the import time, by main.py, ugh
if exists(apath):
ret = apath.resolve(strict=True) / '1752008591/config_saved.json'
else:
ret = None

return ret
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • it looks like mw.addonManager.addonsFolder(__name__) does what you want here?
  • if this can return None then the type hint should indicate that
  • we shouldn't be mixing old os.path stuff with the new pathlib stuff
  • it feels wrong that this could return None if the path doesn't exist in one case but return a path that doesn't exist in another case, why do both? I think you can get rid of this function entirely.

self._load_config()
mw.addonManager.setConfigUpdatedAction(__name__, lambda *_: self._config_updated_handler())

if self.config['firstRun']:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now this forces everyone who updates to have firstRun trigger to true, but it isn't necessarily their first runs.

spath = _get_old_addon_config_file()

if spath and spath.is_file():
# Old MacDonald had a farm. E-I-E-I-O.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what?

Comment on lines +57 to +60
showInfo( 'Configuration from the old "Chinese Support 3" was imported.\n\n'
'This is a one-time post install action, if you update the configuration in the original addon, '
'it will not be synchronized.\n\n'
'It is recommended to disable the old addon.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this, since there is an update there is no addon which needs to be disabled. I think this message should be removed entirely. We can perform this completely unbeknownst to the user.

Comment on lines +55 to +56
for k in ['enabledModels', 'speech', 'target', 'max_examples', 'fields']:
self.config[k] = config_saved[k]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to manually copy select fields, just copy all of it.

@@ -36,6 +36,7 @@
if config['firstRun']:
dictionary.create_indices()
config['firstRun'] = False
config.save() # need for correct meta.json handling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need this. Our view of the config shouldn't get out of sync with the Anki view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Addon json config changes are not honored Configuring the maximum amount of examples does not work
2 participants