Store addons state as JSON (#19564)
Closes #19559
### Summary of the issue:
Addons state is saved in a pickle file.
### Description of user facing changes:
None
### Description of developer facing changes:
The add-ons state file is now in JSON.
The `fromPickledDict` method on `AddonsState` has been renamed to
`fromDict`, but a shim has been introduced.
### Description of development approach:
Switch to using lists instead of sets when populating AddonsState from
dict and serializing to dict, as json.dump doesn't support serializing
sets.
Added methods to read in a pickled add-ons state file and emit a good
JSON representation of that add-ons state. My approach here was to
discard invalid values rather than raising an error, so we have the
greatest chance of success. This does mean that the conversion may be
lossy.
When updating NVDA, convert from pickle to JSON for the system config's
add-ons state file. This is done because this is essentially the only
context in which we should write to the system config directory and
which we know will be executed. User copies perform the migration on
first run by migrating if and only if no addonsState.json exists, but
addonsState.pickle does. User config migration is done by the installed
copy as (a) this is the only time we can guarantee that the user's NVDA
config wil be present; and (b) to minimise the amount of pickles we load
while elevated. In both cases, a backup of the old state file is kept
(as `addonsState.pickle.bak`).
When running on secure desktops, the pickled state will not be read,
even if it is the only addonsState file in the system config. This
should never happen, as the installer is responsible for migrating the
system config's add-ons state file. In other cases, the fallback of
reading the pickled state will attempt to save the JSON state and back
up the pickled state, but this is not required in order for the load to
succede. This is so when running in secure mode or with access to the
user config restricted, add-ons continue to function properly. This does
remove the security benefit of migrating away from pickle, but there's
no other option other than ripping pickle support out entirely and
breaking everyone's add-ons state entirely and having them manually
migrate.
### Testing strategy:
Unit and system tests.
Manual testing as follows:
1. Installed 2025.3.3
2. Installed add-ons (combination of 2026.1 compatible and incompatible,
enabled and disabled) and restarted NVDA
3. Copied user config to system config
4. Upgraded using self-signed launcher
5. Ensured that the installer migrated the system addons state, and the
installed copy migrated the user addons state on first run
Also "upgraded" my 2026.2 alpha copy with this launcher to ensure that
the migration works as expected if updating within the 2026.x series.
### Known issues with pull request:
None known (see notes above for some caviats about the approach though)