Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions addon/globalPlugins/columnsReview/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

from .actions import ACTIONS, actionFromName, configuredActions
from .commonFunc import NVDALocale, findAllDescendantWindows, getScriptGestures
from .compat import CTWRAPPER, zeroItemsTemplate, rangeFunc
from .compat import CTWRAPPER, TextRegion, zeroItemsTemplate, rangeFunc
from . import configManager
from . import configSpec
from . import dialogs
Expand Down Expand Up @@ -690,7 +690,7 @@ def reportEmpty(self):
return
brlText = " {0}".format(text)
if regions[-1].rawText != brlText:
newRegion = braille.TextRegion(brlText)
newRegion = TextRegion(brlText)
newRegion.focusToHardLeft = True
newRegion.update()
regions.append(newRegion)
Expand Down Expand Up @@ -927,7 +927,7 @@ def getSelectedItems(self):
parentHandle,
sysListView32.LVM_GETNEXTITEM,
selItemIndex,
ctypes.c_void_p(sysListView32.LVNI_SELECTED)
ctypes.c_void_p(sysListView32.LVNI_SELECTED),
)
return items

Expand Down
6 changes: 6 additions & 0 deletions addon/globalPlugins/columnsReview/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

import controlTypes

try:
from braille.regions.base import TextRegion as TextRegion
except ImportError:
# NVDA before 2027.1 exposes TextRegion directly in braille.
from braille import TextRegion as TextRegion

try:
from buildVersion import version_year, version_major, version_minor
except ImportError:
Expand Down
67 changes: 67 additions & 0 deletions tests/unit/test_braille_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Exercise the compatibility module without requiring a running NVDA instance."""

from pathlib import Path
import runpy
import sys
from types import ModuleType
import unittest
from unittest.mock import patch


COMPAT_PATH = Path(__file__).resolve().parents[2] / "addon" / "globalPlugins" / "columnsReview" / "compat.py"


class TestTextRegionCompatibility(unittest.TestCase):
def loadCompat(self, brailleModules):
version = ModuleType("buildVersion")
version.version_year = 2027
version.version_major = 1
version.version_minor = 0
modules = {
"controlTypes": ModuleType("controlTypes"),
"buildVersion": version,
"braille.regions": None,
"braille.regions.base": None,
}
modules.update(brailleModules)
with patch.dict(sys.modules, modules):
return runpy.run_path(
str(COMPAT_PATH),
init_globals={"ngettext": lambda singular, plural, count: plural},
)

def test_current_api_does_not_access_deprecated_alias(self):
braille = ModuleType("braille")
braille.__path__ = []

def rejectLegacyAccess(name):
if name == "TextRegion":
raise AssertionError("The deprecated braille.TextRegion alias was accessed")
raise AttributeError(name)

braille.__getattr__ = rejectLegacyAccess
regions = ModuleType("braille.regions")
regions.__path__ = []
base = ModuleType("braille.regions.base")
base.TextRegion = type("CurrentTextRegion", (), {})
compat = self.loadCompat(
{
"braille": braille,
"braille.regions": regions,
"braille.regions.base": base,
},
)
self.assertIs(compat["TextRegion"], base.TextRegion)

def test_legacy_braille_module(self):
braille = ModuleType("braille")
braille.TextRegion = type("LegacyTextRegion", (), {})
compat = self.loadCompat({"braille": braille})
self.assertIs(compat["TextRegion"], braille.TextRegion)

def test_braille_package_without_regions(self):
braille = ModuleType("braille")
braille.__path__ = []
braille.TextRegion = type("LegacyTextRegion", (), {})
compat = self.loadCompat({"braille": braille})
self.assertIs(compat["TextRegion"], braille.TextRegion)
Loading