Skip to content

when upgrading config from schema 20 to 21, gracefully handle when a key or value does not exist E.g. for a config profile.#19519

Merged
SaschaCowley merged 2 commits into
betafrom
fixConfigProfileUpgrade
Jan 28, 2026
Merged

when upgrading config from schema 20 to 21, gracefully handle when a key or value does not exist E.g. for a config profile.#19519
SaschaCowley merged 2 commits into
betafrom
fixConfigProfileUpgrade

Conversation

@michaelDCurran

Copy link
Copy Markdown
Member

Link to issue number:

Addresses an issue introduced by pr #19432

Summary of the issue:

With the merging of pr #19432 which adds SAPI 32 bit support, An error is produced when switching to config profiles that do not have particular synth keys already set.

ERROR - config.ProfileTrigger.enter (16:08:50.860) - MainThread (12728):
Error entering trigger app:notepad, profile Text Editing
Traceback (most recent call last):
  File "config\__init__.pyc", line 1381, in enter
  File "config\__init__.pyc", line 865, in _triggerProfileEnter
  File "config\__init__.pyc", line 643, in _getProfile
  File "config\__init__.pyc", line 586, in _loadConfig
  File "config\__init__.pyc", line 582, in _loadConfig
  File "config\profileUpgrader.pyc", line 26, in upgrade
  File "config\profileUpgrader.pyc", line 42, in _doConfigUpgrade
  File "config\profileUpgradeSteps.pyc", line 642, in upgradeConfigFrom_20_to_21
  File "configobj\__init__.pyc", line 496, in __getitem__
KeyError: 'synth'

Description of user facing changes:

No error is produced and profiles load correctly.

Description of developer facing changes:

Description of development approach:

  • config.profileUpgradeSteps.upgradeConfigFrom_20_to_21: Fetch existing keys with get rather than key lookup.

Testing strategy:

  • Starting with a main config schema of 20 that contained synth = sapi4, and both sapi4 and sapi5 sections in speech, ensured that the synth value was changed to sapi4_32, and that the sapi4 section was renamed to sapi4_32, and that the sapi5 section was renamed to sapi5_32 when running NvDA, and that NVDA successfully used the sapi4_32 synth.
  • Started with a config profile for notepad at schema 20, which had no speech keys or values. Creted just with a change to braille config. Running NvDA, switching to notepad, ensured that the error reported above is gone, and that the profile loaded okay.

Known issues with pull request:

None known.

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

…key or value does not exist E.g. for a config profile.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes profile schema upgrade (20 → 21) to avoid exceptions when profiles don’t contain expected speech/synth keys, addressing a regression introduced by PR #19432.

Changes:

  • Update upgradeConfigFrom_20_to_21 to use .get() lookups instead of direct key access for [speech]/synth.
  • Add debug logging and early return when [speech] is absent.
  • Continue migrating legacy sapi4/sapi5 subsections to sapi4_32/sapi5_32.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"""Redirect old sapi4 and sapi5 config to 32 bit versions."""
synth = profile["speech"]["synth"]
speechConf = profile.get("speech")
if not speechConf:

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

speechConf = profile.get("speech") followed by if not speechConf: treats an existing but empty [speech] section the same as a missing section, and the log message becomes inaccurate (it may log “does not have a speech key” even when the key exists). Consider checking explicitly with if "speech" not in profile: (or if speechConf is None:) and adjust the message accordingly so it only fires when the section truly is absent.

Suggested change
if not speechConf:
if "speech" not in profile:

Copilot uses AI. Check for mistakes.
Comment thread source/config/profileUpgradeSteps.py
Comment on lines +655 to +663
sapi4Conf = speechConf.get("sapi4")
if sapi4Conf:
profile["speech"]["sapi4_32"] = sapi4Conf
del profile["speech"]["sapi4"]
sapi5Conf = profile["speech"].get("sapi5")
speechConf["sapi4_32"] = sapi4Conf
del speechConf["sapi4"]
log.debug("Moved old sapi4 configuration values to sapi4_32")
sapi5Conf = speechConf.get("sapi5")
if sapi5Conf:
profile["speech"]["sapi5_32"] = sapi5Conf
del profile["speech"]["sapi5"]
speechConf["sapi5_32"] = sapi5Conf
del speechConf["sapi5"]

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

if sapi4Conf: / if sapi5Conf: will skip migration when the [speech][sapi4] or [speech][sapi5] section exists but is empty (ConfigObj sections are dict-like and evaluate false when empty). If the goal is to remove legacy keys whenever they exist, consider checking for key presence (e.g. if "sapi4" in speechConf: / if sapi4Conf is not None:) so even empty sections get renamed/deleted.

Copilot uses AI. Check for mistakes.
@seanbudd seanbudd added this to the 2026.1 milestone Jan 27, 2026

@SaschaCowley SaschaCowley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good. Just a small clarification to the log message when there is no speech section in the config. Let me know if you think it's overkill and I'll approve without it though.

Comment thread source/config/profileUpgradeSteps.py Outdated
@SaschaCowley SaschaCowley added release/blocking this issue blocks the milestone release release/blocking-beta labels Jan 27, 2026
Co-authored-by: Sascha Cowley <16543535+SaschaCowley@users.noreply.github.com>
@SaschaCowley SaschaCowley merged commit b573741 into beta Jan 28, 2026
39 checks passed
@SaschaCowley SaschaCowley deleted the fixConfigProfileUpgrade branch January 28, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/blocking this issue blocks the milestone release release/blocking-beta

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants