Skip to content

fix: stop reading deprecated braille module aliases - #9

Closed
serrebidev wants to merge 1 commit into
josephsl:mainfrom
serrebidev:fix/braille-module-deprecations
Closed

fix: stop reading deprecated braille module aliases#9
serrebidev wants to merge 1 commit into
josephsl:mainfrom
serrebidev:fix/braille-module-deprecations

Conversation

@serrebidev

Copy link
Copy Markdown

Problem

NVDA split the flat braille and brailleInput namespaces into sub-modules and left deprecated aliases behind. Every read of an alias goes through the utils._deprecate module __getattr__, which logs a WARNING and a full stack trace.

Braille Essentials reads those names 167 times across 12 modules, so start-up alone produces around 50 of these, and more arrive on braille updates:

WARNING - utils._deprecate.module_getattr:
braille.TextInfoRegion is deprecated. Use braille.regions.textInfo.TextInfoRegion instead.
Stack trace:
  ...
  File "...\addons\brailleEssentials\globalPlugins\brailleEssentials\patches.py", line 117, in _saveOriginals
    o["TextInfoRegion._addTextWithFields"] = braille.TextInfoRegion._addTextWithFields

Observed on NVDA alpha-57522 (Python 3.13) with add-on 26.08.

The names involved: Region, TextRegion, TextInfoRegion, NVDAObjectRegion, NVDAObjectHasUsefulText, BrailleBuffer, BrailleHandler, getControlFieldBraille, getFormatFieldBraille, getPropertiesBraille, getFocusRegions, getFocusContextRegions, getDisplayList, roleLabels, positiveStateLabels, negativeStateLabels, landmarkLabels, TEXT_SEPARATOR, INPUT_START_IND, INPUT_END_IND, SELECTION_SHAPE, brailleInput.handler, brailleInput.BrailleInputHandler.

Fix

Add globalPlugins/brailleEssentials/brailleCompat.py, which imports each symbol from its real home and falls back to the flat modules when the sub-modules are absent — so the add-on still runs on the manifest minimum of 2025.3.3, where these names are neither moved nor deprecated.

Call sites become bc.TextInfoRegion instead of braille.TextInfoRegion, which is marginally shorter than what it replaces; no line goes over the configured 110-column limit.

Stable objects are re-exported directly. Two module aliases are kept, because they can't be captured at import time:

  • bc.brailleInputhandler is rebound by braille initialise/terminate, so it must be read through the module.
  • bc.regionsPropertiespatches.py assigns the field-formatting functions back, so it needs the module object.

Second bug: LOUIS_DOTS_IO_START raises AttributeError

patches.py reads brailleInput.LOUIS_DOTS_IO_START in its BrailleInputHandler._translate replacement, which runs on every braille keyboard translation:

data = "".join([chr(cell | brailleInput.LOUIS_DOTS_IO_START) for cell in self.bufferBraille[:pos]])

NVDA's deprecation table declares that name moved to braille.input.constants, but that module never defines it — I checked every module in library.zip, and the value now lives only in louisHelper._DOTS_IO_START. So the documented alias resolves to nothing and raises AttributeError on current builds.

brailleCompat resolves it from louisHelper._DOTS_IO_START, then the pre-split public name, then the liblouis literal 0x8000.

Verification

  • Every one of the 166 bc.* accesses was resolved against the actual symbol tables in NVDA's library.zip — 0 unresolved.
  • All modules byte-compile.
  • No braille.* / brailleInput.* deprecated reads remain; braille.handler is untouched, since it is not deprecated.
  • Diff is content-only: 176 insertions, 164 deletions, no reformatting.

Not addressed here

patches.py replaces the field-formatting functions by assigning to the braille module:

braille.getControlFieldBraille = getControlFieldBraille

On current NVDA braille/regions/textInfo.py binds getControlFieldBraille into its own module globals at import, so writing the name onto the braille package no longer reaches the code that calls it — these three patches appear to be inert on recent builds, independently of this PR. This change retargets the assignment to regionsProperties so save and restore stay symmetric and the deprecated alias reflects the patch, but making the patch effective again would mean assigning into the consumer modules, which is a behaviour change I did not want to make blind. Flagging it for you rather than guessing.

NVDA moved the regions, buffers, handler, labels, constants, display helpers
and the braille input handler out of the flat `braille` / `brailleInput`
namespaces into sub-modules, leaving deprecated aliases behind. Every read of
an alias goes through the `utils._deprecate` module `__getattr__`, which logs a
WARNING plus a full stack trace.

The add-on reads those names 167 times across 12 modules, so start-up alone
emits about 50 such warnings and more follow on braille updates.

Add `brailleCompat`, which imports each symbol from its real home and falls
back to the flat modules on builds that predate the split, so the add-on keeps
working down to the manifest minimum of 2025.3.3. Stable objects (classes,
functions, constants, label mappings) are re-exported directly; two module
aliases are kept because they cannot be captured at import time:

* `brailleInput`, since `handler` is rebound by braille initialise/terminate;
* `regionsProperties`, since patches.py assigns the field-formatting
  functions back.

Also fixes `LOUIS_DOTS_IO_START`, which patches.py reads on every braille
keyboard translation. NVDA's deprecation table says it moved to
`braille.input.constants`, but that module never defines it -- the value now
lives in `louisHelper._DOTS_IO_START`. Reading the documented alias raises
AttributeError on current builds, so `brailleCompat` resolves it from
louisHelper, then the pre-split public name, then the liblouis literal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUFZd6deUGuMmJYnLAvXxL
@serrebidev

Copy link
Copy Markdown
Author

Closing as a duplicate — I missed that #8 already covers this, and covers it better.

#8 resolves the same symbols through a brailleCompat module with the same pre-2026.1 fallback, and additionally fixes something I explicitly left alone here: it patches the field-formatting functions through patchBrailleFunction/_holderModules, writing to every namespace that actually holds a binding. That handles the import-time from .properties import ... bindings in braille/regions/NVDAObject.py and braille/regions/textInfo.py, which my branch did not. It also covers LOUIS_DOTS_IO_START.

Please review #8 instead. Sorry for the noise.

@serrebidev serrebidev closed this Aug 24, 2026
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.

1 participant