Skip to content
Merged
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
4 changes: 0 additions & 4 deletions source/_addonStore/dataManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

from copy import deepcopy
import json
import os
Expand Down
4 changes: 0 additions & 4 deletions source/_addonStore/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

from os import (
PathLike,
)
Expand Down
4 changes: 0 additions & 4 deletions source/_addonStore/models/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

import dataclasses
import json
import os
Expand Down
4 changes: 0 additions & 4 deletions source/_addonStore/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting Future
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

from concurrent.futures import (
Future,
ThreadPoolExecutor,
Expand Down
22 changes: 10 additions & 12 deletions source/addonHandler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict, UserDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

from abc import abstractmethod, ABC
import sys
import os.path
Expand Down Expand Up @@ -79,24 +75,25 @@
isCLIParamKnown = extensionPoints.AccumulatingDecider(defaultDecision=False)


class AddonsState(collections.UserDict):
AddonStateDictT = Dict[AddonStateCategory, CaseInsensitiveSet[str]]


class AddonsState(collections.UserDict[AddonStateCategory, CaseInsensitiveSet[str]]):
"""
Subclasses `collections.UserDict` to preserve backwards compatibility.
In future versions of python (3.8+) UserDict[AddonStateCategory, CaseInsensitiveSet[str]]
can have type information added.
AddonStateCategory string enums mapped to a set of the add-on "name/id" currently in that state.
Add-ons that have the same ID except differ in casing cause a path collision,
as add-on IDs are installed to a case insensitive path.
Therefore add-on IDs should be treated as case insensitive.
"""

@staticmethod
def _generateDefaultStateContent() -> Dict[AddonStateCategory, CaseInsensitiveSet[str]]:
def _generateDefaultStateContent() -> AddonStateDictT:
return {
category: CaseInsensitiveSet() for category in AddonStateCategory
}

data: Dict[AddonStateCategory, CaseInsensitiveSet[str]]
data: AddonStateDictT
manualOverridesAPIVersion: MajorMinorPatch

@property
Expand Down Expand Up @@ -224,7 +221,7 @@ def _cleanupCompatibleAddonsFromDowngrade(self) -> None:
self[AddonStateCategory.OVERRIDE_COMPATIBILITY].discard(blockedAddon)


state: AddonsState[AddonStateCategory, CaseInsensitiveSet[str]] = AddonsState()
state = AddonsState()


def getRunningAddons() -> "AddonHandlerModelGeneratorT":
Expand Down Expand Up @@ -762,8 +759,9 @@ def initTranslation():
try:
callerFrame = inspect.currentframe().f_back
callerFrame.f_globals['_'] = translations.gettext
# Install our pgettext function.
callerFrame.f_globals['pgettext'] = languageHandler.makePgettext(translations)
# Install pgettext and npgettext function.
callerFrame.f_globals['pgettext'] = translations.pgettext
callerFrame.f_globals['npgettext'] = translations.npgettext
finally:
del callerFrame # Avoid reference problems with frames (per python docs)

Expand Down
3 changes: 0 additions & 3 deletions source/gui/_addonStoreGui/viewModels/addonList.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum

Expand Down
4 changes: 0 additions & 4 deletions source/gui/_addonStoreGui/viewModels/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

# Needed for type hinting CaseInsensitiveDict
# Can be removed in a future version of python (3.8+)
from __future__ import annotations

from os import (
PathLike,
startfile,
Expand Down
53 changes: 1 addition & 52 deletions source/languageHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
such as converting Windows locale ID's to friendly names and presenting available languages.
"""

import builtins
import os
import sys
import ctypes
Expand All @@ -27,7 +26,6 @@
Optional,
Tuple,
Union,
Callable,
)

#a few Windows locale constants
Expand Down Expand Up @@ -290,52 +288,6 @@ def getAvailableLanguages(presentational: bool = False) -> List[Tuple[str, str]]
return langs


def makePgettext(translations):
"""Obtain a pgettext function for use with a gettext translations instance.
pgettext is used to support message contexts,
but Python 3.7's gettext module doesn't support this,
so NVDA must provide its own implementation.
"""
if isinstance(translations, gettext.GNUTranslations):
def pgettext(context, message):
try:
# Look up the message with its context.
return translations._catalog[u"%s\x04%s" % (context, message)]
except KeyError:
return message
elif isinstance(translations, gettext.NullTranslations):
# A language without a translation catalog, such as English.
def pgettext(context, message):
return message
else:
raise ValueError("%s is Not a GNUTranslations or NullTranslations object" % translations)
return pgettext


def makeNpgettext(
translations: Union[None, gettext.GNUTranslations, gettext.NullTranslations],
) -> Callable[[str, str, str, Union[int, float]], str]:
"""Obtain a npgettext function for use with a gettext translations instance.
npgettext is used to support message contexts with respect to ngettext,
but Python 3.7's gettext module doesn't support this,
so NVDA must provide its own implementation.
"""
if isinstance(translations, gettext.GNUTranslations):
def npgettext(context: str, msgSingular: str, msgPlural: str, n: Union[int, float]) -> str:
try:
# Look up the message with its context.
return translations._catalog[(f"{context}\x04{msgSingular}", translations.plural(n))]
except KeyError:
return msgSingular if n == 1 else msgPlural
elif isinstance(translations, gettext.NullTranslations):
# A language without a translation catalog, such as English.
def npgettext(context: str, msgSingular: str, msgPlural: str, n: Union[int, float]) -> str:
return msgSingular if n == 1 else msgPlural
else:
raise ValueError("%s is Not a GNUTranslations or NullTranslations object" % translations)
return npgettext


def getLanguageCliArgs() -> Tuple[str, ...]:
"""Returns all command line arguments which were used to set current NVDA language
or an empty tuple if language has not been specified from the CLI."""
Expand Down Expand Up @@ -408,11 +360,8 @@ def setLanguage(lang: str) -> None:
if trans is None:
trans = _createGettextTranslation("en")

trans.install(names=['ngettext'])
trans.install(names=["pgettext", "npgettext", "ngettext"])
setLocale(getLanguage())
# Install our pgettext and npgettext functions.
builtins.pgettext = makePgettext(trans)
builtins.npgettext = makeNpgettext(trans)

global installedTranslation
installedTranslation = weakref.ref(trans)
Expand Down
4 changes: 0 additions & 4 deletions source/monkeyPatches/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,3 @@ def applyMonkeyPatches():
# Apply several monkey patches to comtypes
from . import comtypesMonkeyPatches
comtypesMonkeyPatches.applyMonkeyPatches()

# Apply patches to Enum, prevent cyclic references on ValueError during construction
from . import enumPatches
enumPatches.replace__new__()
60 changes: 0 additions & 60 deletions source/monkeyPatches/enumPatches.py

This file was deleted.

2 changes: 1 addition & 1 deletion source/utils/displayString.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class _DisplayStringEnumMixin(ABC):
This mixin can be used with a class which subclasses Enum to provided translated display strings for
members of the enum. The abstract properties must be overridden.
To be used with `_DisplayStringEnumMixinMeta`.
Usage for python 3.7 is as follows:
Usage:
```
class ExampleEnum(_DisplayStringEnumMixin, str, Enum, metaclass=_DisplayStringEnumMixinMeta):
pass
Expand Down
9 changes: 5 additions & 4 deletions source/visionEnhancementProviders/NVDAHighlighter.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,12 +449,13 @@ def _run(self):
timer = winUser.WinTimer(window.handle, 0, self._refreshInterval, None)
self._highlighterRunningEvent.set() # notify main thread that initialisation was successful
msg = MSG()
# Python 3.8 note, Change this to use an Assignment expression to catch a return value of -1.
# See the remarks section of
# https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
while winUser.getMessage(byref(msg), None, 0, 0) > 0:
while (res := winUser.getMessage(byref(msg), None, 0, 0)) > 0:
winUser.user32.TranslateMessage(byref(msg))
winUser.user32.DispatchMessageW(byref(msg))
if res == -1:
# See the return value section of
# https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
raise WinError()
if vision._isDebug():
log.debug("Quit message received on NVDAHighlighter thread")
timer.terminate()
Expand Down
13 changes: 0 additions & 13 deletions source/winAPI/dpiAwareness.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,6 @@ def setDPIAwareness() -> None:
# Windows 8 / Server 2012 - `shcore` library exists,
# but `SetProcessDpiAwareness` is not present yet.
log.debug("Cannot set PROCESS_PER_MONITOR_DPI_AWARE - SetProcessDpiAwareness missing")
except WindowsError as e:
# `ctypes` raises `WindowsError` for missing DLL's.
# On Windows 7 `shcore` library is not present.
# Inspect error code and either ignore the exception falling back to the legacy method
# if it is caused by missing dll, log an error otherwise.
# In Python 3.8 and later `ctypes` raises `FileNotFoundError`
# rather than `WindowsError` for missing libraries.
# When updating NVDA the exception has to be changed
# or, if support for Windows 7 is dropped, this section should be removed.
if e.winerror == SystemErrorCodes.MOD_NOT_FOUND:
log.debug("Cannot set PROCESS_PER_MONITOR_DPI_AWARE - shcore not found")
else:
log.error("Failed to set PROCESS_PER_MONITOR_DPI_AWARE", exc_info=True)
else:
if hResult == HResult.S_OK:
return
Expand Down
4 changes: 3 additions & 1 deletion source/winUser.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,11 @@ def MAKELONG(lo,hi):
def waitMessage():
return user32.WaitMessage()

def getMessage(*args):

def getMessage(*args) -> int:
return user32.GetMessageW(*args)


def translateMessage(*args):
return user32.TranslateMessage(*args)

Expand Down
12 changes: 1 addition & 11 deletions tests/unit/test_controlTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,23 +254,13 @@ def test_rolesValues(self):

class Test_FontSize(unittest.TestCase):
def test_translateFromAttribute(self):
with self.assertLogs(logHandler.log, level=logging.DEBUG) as logContext:
# We want to assert there are no logs, but the 'assertLogs' method does not support that.
# 'assertNoLogs' has been added in Python 3.10
# Therefore, we are adding a canary warning, and then we will assert it is the only warning.
logHandler.log.debug("Canary warning")
with self.assertNoLogs(logHandler.log, level=logging.DEBUG) as logContext:
# Ensure keyword sizes parse to a translatable version of themselves
self.assertEqual(FontSize.translateFromAttribute("smaller"), "smaller")
# Ensure measurement sizes parse to a translatable version of themselves
self.assertEqual(FontSize.translateFromAttribute("13.0pt"), "13.0 pt")
self.assertEqual(FontSize.translateFromAttribute("11px"), "11 px")
self.assertEqual(FontSize.translateFromAttribute("23.3%"), "23.3%")

self.assertEqual(
["DEBUG:nvda:Canary warning"],
logContext.output,
msg="Font size parsing failed, failure was logged"
)

with self.assertLogs(logHandler.log, level=logging.DEBUG) as logContext:
self.assertEqual(FontSize.translateFromAttribute("unsupported"), "unsupported")
Expand Down
2 changes: 2 additions & 0 deletions user_docs/en/changes.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ That method receives a ``DriverRegistrar`` object on which the ``addUsbDevices``
- ``IoThread.autoDeleteApcReference`` has been removed. (#14924, @LeonarddeR)
- To support capital pitch changes, synthesizers must now explicitly declare their support for the ``PitchCommand`` in the ``supportedCommands`` attribute on the driver. (#15433, @LeonarddeR)
- ``speechDictHandler.speechDictVars`` has been removed. Use ``NVDAState.WritePaths.speechDictsDir`` instead of ``speechDictHandler.speechDictVars.speechDictsPath``. (#15614, @lukaszgo1)
- ``languageHandler.makeNpgettext`` and ``languageHandler.makePgettext`` have been removed.
``npgettext`` and ``pgettext`` are supported natively now. (#15546)
% Insert new list items here as the alias appModule table should be kept at the bottom of this list
- The following app modules are removed.
Code which imports from one of them, should instead import from the replacement module. (#15618, @lukaszgo1)
Expand Down