Skip to content

Python to 3.13.14 - #20476

Closed
dpy013 wants to merge 4 commits into
nvaccess:masterfrom
dpy013:py3.13.14
Closed

Python to 3.13.14#20476
dpy013 wants to merge 4 commits into
nvaccess:masterfrom
dpy013:py3.13.14

Conversation

@dpy013

@dpy013 dpy013 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
  ### Link to issue number:
  None
  ### Summary of the issue:
  Python 3.13.14 completely rewrote the `windows_locale` mapping table in `Lib/locale.py` to align with the [MS-LCID specification (revision 16.0)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f). This introduced new LCID entries for Central Kurdish (`0x0092: "ku"`, `0x7c92: "ku"`, `0x0492: "ku_IQ"`).

In Python 3.13.13, these entries did not exist, so ckb was classified as an unsupported Windows language and the locale assertion in test_NVDASupportedLanguages_LanguageIsSetCorrectly was skipped. In Python 3.13.14, ckb is now recognized by Windows (LCID 0x0492), but Windows maps it to ku_IQ (language code ku) rather than ckb, causing the test assertion 'ckb' != 'ku' to fail.
### Description of user facing changes:
None. This is an internal Python version bump and test fix with no user-facing behavior changes.
### Description of developer facing changes:
- The pinned CPython version is now 3.13.14 across all build configurations, CI workflows, and developer documentation.

  • A new WINDOWS_LOCALE_ALIASES mapping is introduced in tests/unit/test_languageHandler.py to handle cases where Windows returns a different but related language code than the one NVDA uses. Future locale mismatches can be resolved by adding entries to this dictionary.
    ### Description of development approach:
    1. Updated Python version from 3.13.13 to 3.13.14 in:
  • .python-versions (root, x86_64)
  • runtime-builders/synthDriverHost32/.python-version (x86)
  • .github/workflows/autofix.yml
  • .github/workflows/fetch-crowdin-translations.yml
  • .github/workflows/testAndPublish.yml (defaultPythonVersion and supportedPythonVersions)
  • projectDocs/dev/createDevEnvironment.md
  1. Fixed the ckb locale test failure by adding a WINDOWS_LOCALE_ALIASES dictionary in tests/unit/test_languageHandler.py that maps ckbku, and updated the thread locale assertion to use WINDOWS_LOCALE_ALIASES.get(langOnly, langOnly) instead of langOnly.
    References:
  • Python 3.13.14 Lib/locale.py

  • Python 3.13.13 Lib/locale.py

  • MS-LCID specification

  • Python 3.13.14 release notes
    ### Testing strategy:
    - CI run on dpy013/nvda branch py3.13.14: all jobs pass after the fix (Build, unit tests, Pyright type check, license check, translator comments, symbols).

  • The WINDOWS_LOCALE_ALIASES mapping is designed to be extensible — if similar locale mismatches surface on different Windows versions, new entries can be added without modifying test logic.
    ### Known issues with pull request:
    None.
    ### 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.
    

action run:
https://github.com/dpy013/nvda/actions/runs/29052432147

Bump the pinned CPython version used across the project from 3.13.13 to 3.13.14.

Changes:
- .python-versions: update cpython-3.13.13-windows-x86_64-none to cpython-3.13.14-windows-x86_64-none
- runtime-builders/synthDriverHost32/.python-version: update cpython-3.13.13-windows-x86-none to cpython-3.13.14-windows-x86-none
- .github/workflows/autofix.yml: update python-version from 3.13.13 to 3.13.14
- .github/workflows/fetch-crowdin-translations.yml: update python-version from 3.13.13 to 3.13.14
- .github/workflows/testAndPublish.yml: update defaultPythonVersion and supportedPythonVersions from 3.13.13 to 3.13.14
- projectDocs/dev/createDevEnvironment.md: update documented Python version requirement from 3.13.13 to 3.13.14

Signed-off-by: dpy013 <26911141+dpy013@users.noreply.github.com>
@dpy013
dpy013 requested a review from a team as a code owner July 9, 2026 22:22
@dpy013
dpy013 requested a review from seanbudd July 9, 2026 22:22
@dpy013 dpy013 changed the title python: 3.13.13 to 3.13.14 Python to 3.13.14 Jul 9, 2026
Comment thread runtime-builders/synthDriverHost32/.python-version Outdated
Comment thread tests/unit/test_languageHandler.py Outdated
# check that the language codes are correctly set for the thread
self.assertEqual(
langOnly,
WINDOWS_LOCALE_ALIASES.get(langOnly, langOnly),

@seanbudd seanbudd Jul 10, 2026

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.

I don't think this is the correct fix.
windows_locale is being removed in Python 3.14 as per python/cpython#144738

Instead we need to remove using windows_locale and use winKernel.LCIDToLocaleName instead. This involves changing languageHandler.windowsLCIDToLocaleName, removing _LCIDS_TO_TRANSLATED_LOCALES_OVERRIDES

def windowsLCIDToLocaleName(lcid: int) -> str | None:
	"""
	Gets a normalized locale from a Windows LCID.

	NVDA should avoid relying on LCIDs in future, as they have been deprecated by MS:
	https://docs.microsoft.com/en-us/globalization/locale/locale-names
	"""

	localeName = LCIDS_TO_TRANSLATED_LOCALES.get(lcid)
	if not localeName:
		localeName = winKernel.LCIDToLocaleName(lcid)
	if localeName:
		return normalizeLanguage(localeName)

Comment thread .python-versions Outdated
@seanbudd
seanbudd marked this pull request as draft July 10, 2026 04:09
dpy013 added a commit to dpy013/nvda that referenced this pull request Jul 10, 2026
As per reviewer feedback on PR nvaccess#20476, locale.windows_locale is being
deprecated and removed in Python 3.13 (see cpython#144738). This commit
removes NVDA's dependency on it in languageHandler.windowsLCIDToLocaleName.

Changes:
- Remove _LCIDS_TO_TRANSLATED_LOCALES_OVERRIDES (no longer needed since
  we're not using locale.windows_locale)
- Simplify windowsLCIDToLocaleName to check LCIDS_TO_TRANSLATED_LOCALES
  first, then use winKernel.LCIDToLocaleName (Windows API)
- Update LCIDS_TO_TRANSLATED_LOCALES docstring to reflect its new purpose
- Revert WINDOWS_LOCALE_ALIASES workaround in test_languageHandler.py
  (no longer needed since LCIDS_TO_TRANSLATED_LOCALES already has
  1170: "ckb", which correctly maps LCID 0x0492 to "ckb")

This fixes the ckb locale test failure because when Windows returns
LCID 0x0492 for Central Kurdish, windowsLCIDToLocaleName now checks
LCIDS_TO_TRANSLATED_LOCALES first and returns "ckb" directly, matching
what the test expects.

References:
- Python cpython#144738: python/cpython#144738
- PR nvaccess#20476 discussion: nvaccess#20476 (comment)
dpy013 and others added 3 commits July 10, 2026 16:39
fix

Co-authored-by: Sean Budd <seanbudd123@gmail.com>
fix

Co-authored-by: Sean Budd <seanbudd123@gmail.com>
dpy013 added a commit to dpy013/nvda that referenced this pull request Jul 10, 2026
As per reviewer feedback on PR nvaccess#20476, locale.windows_locale is being
deprecated and removed in Python 3.13 (see cpython#144738). This commit
removes NVDA's dependency on it in languageHandler.windowsLCIDToLocaleName.

Changes:
- Remove _LCIDS_TO_TRANSLATED_LOCALES_OVERRIDES (no longer needed since
  we're not using locale.windows_locale)
- Simplify windowsLCIDToLocaleName to check LCIDS_TO_TRANSLATED_LOCALES
  first, then use winKernel.LCIDToLocaleName (Windows API)
- Update LCIDS_TO_TRANSLATED_LOCALES docstring to reflect its new purpose
- Revert WINDOWS_LOCALE_ALIASES workaround in test_languageHandler.py
  (no longer needed since LCIDS_TO_TRANSLATED_LOCALES already has
  1170: "ckb", which correctly maps LCID 0x0492 to "ckb")

This fixes the ckb locale test failure because when Windows returns
LCID 0x0492 for Central Kurdish, windowsLCIDToLocaleName now checks
LCIDS_TO_TRANSLATED_LOCALES first and returns "ckb" directly, matching
what the test expects.

References:
- Python cpython#144738: python/cpython#144738
- PR nvaccess#20476 discussion: nvaccess#20476 (comment)
@dpy013
dpy013 marked this pull request as ready for review July 10, 2026 09:48
Comment thread source/languageHandler.py
# NOTE: this mapping is incomplete and out of date.
# We should stop relying on it and use Windows API calls instead.
# https://github.com/python/cpython/issues/123853
localeName = locale.windows_locale.get(lcid)

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.

make sure to remove all usages of windows_locale in NVDA currently

Copilot AI review requested due to automatic review settings July 14, 2026 01:11

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

This PR bumps NVDA’s pinned CPython version from 3.13.13 to 3.13.14 and updates Windows locale/LCID handling to account for CPython/Windows locale mapping changes (notably around Central Kurdish). It also updates SAPI voice language detection to use NVDA’s LCID-to-locale conversion instead of CPython’s locale.windows_locale.

Changes:

  • Updated Python version pins to 3.13.14 across CI/workflows, runtime builder config, developer docs, and changelog.
  • Updated windowsLCIDToLocaleName to prefer NVDA’s override mapping (LCIDS_TO_TRANSLATED_LOCALES) before calling the Windows API.
  • Added a Kernel32 binding for EnumSystemLocalesEx and updated unit tests to enumerate Windows locales using the Windows API; updated SAPI4/SAPI5 voice language locale mapping.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
user_docs/en/changes.md Documents Python bump to 3.13.14 in the changelog.
tests/unit/test_languageHandler.py Enumerates Windows locales via EnumSystemLocalesEx to drive locale-related tests.
source/winBindings/kernel32.py Adds ctypes bindings for LOCALE_ENUMPROCEX and EnumSystemLocalesEx.
source/synthDrivers/sapi5.py Uses languageHandler.windowsLCIDToLocaleName for SAPI5 voice language mapping.
source/languageHandler.py Changes LCID-to-locale resolution order to prefer NVDA overrides, then Windows API.
source/_synthDrivers32/sapi4.py Uses languageHandler.windowsLCIDToLocaleName for SAPI4 voice language mapping.
runtime-builders/synthDriverHost32/.python-version Updates 32-bit runtime builder Python pin to 3.13.14.
projectDocs/dev/createDevEnvironment.md Updates developer documentation to Python 3.13.14.
.python-versions Updates main pinned CPython build to 3.13.14.
.github/workflows/testAndPublish.yml Updates default/supported Python versions to 3.13.14.
.github/workflows/fetch-crowdin-translations.yml Updates setup-python version to 3.13.14.
.github/workflows/autofix.yml Updates setup-python version to 3.13.14.

Comment thread tests/unit/test_languageHandler.py Outdated
Comment on lines +38 to +43
if not localeName:
return True
normalizedLocale = languageHandler.normalizeLanguage(localeName)
if normalizedLocale:
windowsLangs.add(normalizedLocale)
return True
Comment thread source/_synthDrivers32/sapi4.py Outdated
language = locale.windows_locale[mode.language.LanguageID]
except KeyError:
language = None
language = languageHandler.windowsLCIDToLocaleName(mode.language.LanguageID)
Comment thread source/languageHandler.py Outdated
Comment on lines 129 to 132
localeName = LCIDS_TO_TRANSLATED_LOCALES.get(lcid)
if not localeName:
localeName = winKernel.LCIDToLocaleName(lcid)
if localeName:
Comment thread source/_synthDrivers32/sapi4.py Outdated
language = locale.windows_locale[mode.language.LanguageID]
except KeyError:
language = None
language = languageHandler.windowsLCIDToLocaleName(mode.language.LanguageID)

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.

are you sure we should be using languageHandler here and not winKernel.LCIDToLocaleName? Can you explain how you tested to ensure nothing broke here?

Comment thread source/synthDrivers/sapi5.py Outdated
language = locale.windows_locale[int(v[i].getattribute("language").split(";")[0], 16)]
except KeyError:
language = None
language = languageHandler.windowsLCIDToLocaleName(

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.

are you sure we should be using languageHandler here and not winKernel.LCIDToLocaleName? Can you explain how you tested to ensure nothing broke here?

@seanbudd

Copy link
Copy Markdown
Member

please fix up the formatting of the PR description

@seanbudd
seanbudd marked this pull request as draft July 14, 2026 03:16
@cary-rowen

Copy link
Copy Markdown
Contributor

@dpy013 I suspect you are using AI to assist with this PR (or perhaps relying on it entirely). Regardless, please ensure you thoroughly test your changes yourself first and address Sean's questions. Thank you.

@dpy013

dpy013 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

"Closing this PR for now as it needs further investigation."

@dpy013 dpy013 closed this Jul 15, 2026
@dpy013
dpy013 deleted the py3.13.14 branch July 15, 2026 21:26
@dpy013 dpy013 mentioned this pull request Jul 31, 2026
5 tasks
@dpy013 dpy013 mentioned this pull request Aug 9, 2026
5 tasks
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.

4 participants