From 8a46d2852b9112bdefe13f8e76f873a5699c55ce Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Tue, 26 Sep 2023 15:38:07 +1000 Subject: [PATCH 1/3] Minor fixes in preparation for python 3.11 --- source/NVDAHelper.py | 1 - source/_addonStore/dataManager.py | 4 ++-- source/_addonStore/models/addon.py | 4 ++-- source/garbageHandler.py | 4 ++-- source/globalVars.py | 5 +++++ .../_addonStoreGui/viewModels/addonList.py | 2 +- source/monkeyPatches/enumPatches.py | 20 +++++++++---------- source/watchdog.py | 6 +++++- 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/source/NVDAHelper.py b/source/NVDAHelper.py index 544f2989a61..fcb05b92491 100755 --- a/source/NVDAHelper.py +++ b/source/NVDAHelper.py @@ -599,7 +599,6 @@ def initialize() -> None: raise RuntimeError("Error initializing NVDAHelperRemote") #Manually start the in-process manager thread for this NVDA main thread now, as a slow system can cause this action to confuse WX _remoteLib.initInprocManagerThreadIfNeeded() - versionedLibARM64Path arch = winVersion.getWinVer().processorArchitecture if arch == 'AMD64': _remoteLoaderAMD64 = _RemoteLoader(versionedLibAMD64Path) diff --git a/source/_addonStore/dataManager.py b/source/_addonStore/dataManager.py index ece757ab903..67870f83eef 100644 --- a/source/_addonStore/dataManager.py +++ b/source/_addonStore/dataManager.py @@ -186,7 +186,7 @@ def _getCachedAddonData(self, cacheFilePath: str) -> Optional[CachedAddonsModel] def getLatestCompatibleAddons( self, - onDisplayableError: Optional[DisplayableError.OnDisplayableErrorT] = None, + onDisplayableError: Optional["DisplayableError.OnDisplayableErrorT"] = None, ) -> "AddonGUICollectionT": cacheHash = self._getCacheHash() shouldRefreshData = ( @@ -225,7 +225,7 @@ def getLatestCompatibleAddons( def getLatestAddons( self, - onDisplayableError: Optional[DisplayableError.OnDisplayableErrorT] = None, + onDisplayableError: Optional["DisplayableError.OnDisplayableErrorT"] = None, ) -> "AddonGUICollectionT": cacheHash = self._getCacheHash() shouldRefreshData = ( diff --git a/source/_addonStore/models/addon.py b/source/_addonStore/models/addon.py index 2a00d374e7d..187e24115c5 100644 --- a/source/_addonStore/models/addon.py +++ b/source/_addonStore/models/addon.py @@ -182,7 +182,7 @@ class _AddonManifestModel(_AddonGUIModel): homepage: Optional[str] minNVDAVersion: MajorMinorPatch lastTestedVersion: MajorMinorPatch - manifest: AddonManifest + manifest: "AddonManifest" legacy: bool = False """ Legacy add-ons contain invalid metadata @@ -216,7 +216,7 @@ class AddonManifestModel(_AddonManifestModel): homepage: Optional[str] minNVDAVersion: MajorMinorPatch lastTestedVersion: MajorMinorPatch - manifest: AddonManifest + manifest: "AddonManifest" legacy: bool = False """ Legacy add-ons contain invalid metadata diff --git a/source/garbageHandler.py b/source/garbageHandler.py index aa90fab0f0a..7593d075f66 100644 --- a/source/garbageHandler.py +++ b/source/garbageHandler.py @@ -44,7 +44,7 @@ def initialize(): def _collectionCallback(action, info): global _collectionThreadID, _reportCountDuringCollection if action == "start": - _collectionThreadID = threading.currentThread().ident + _collectionThreadID = threading.current_thread().ident _reportCountDuringCollection = 0 elif action == "stop": _collectionThreadID = 0 @@ -60,7 +60,7 @@ def notifyObjectDeletion(obj): if it is due to Python's cyclic garbage collector. """ global _reportCountDuringCollection - if _collectionThreadID != threading.currentThread().ident: + if _collectionThreadID != threading.current_thread().ident: return _reportCountDuringCollection += 1 if _reportCountDuringCollection == 1: diff --git a/source/globalVars.py b/source/globalVars.py index 1e0f5644465..432e04db678 100644 --- a/source/globalVars.py +++ b/source/globalVars.py @@ -131,6 +131,11 @@ class DefaultAppArgs(argparse.Namespace): """The process ID of NVDA itself. """ +appDir: str +""" +The directory where NVDA is installed or running from. +Set by nvda_slave.pyw and nvda.pyw. +""" # TODO: encapsulate in synthDriverHandler settingsRing = None diff --git a/source/gui/_addonStoreGui/viewModels/addonList.py b/source/gui/_addonStoreGui/viewModels/addonList.py index be03ae1d27b..6aa25a6c237 100644 --- a/source/gui/_addonStoreGui/viewModels/addonList.py +++ b/source/gui/_addonStoreGui/viewModels/addonList.py @@ -132,7 +132,7 @@ def __repr__(self) -> str: class AddonDetailsVM: - def __init__(self, listVM: AddonListVM): + def __init__(self, listVM: "AddonListVM"): self._listVM = listVM self._listItem: Optional[AddonListItemVM] = listVM.getSelection() self.updated = extensionPoints.Action() # triggered by setting L{self._listItem} diff --git a/source/monkeyPatches/enumPatches.py b/source/monkeyPatches/enumPatches.py index 6abee38b6c7..1f6b1d9dc29 100644 --- a/source/monkeyPatches/enumPatches.py +++ b/source/monkeyPatches/enumPatches.py @@ -46,15 +46,15 @@ def _replacement__new__(cls, value): if isinstance(result, cls): return result - with ValueError( + ve_exc = ValueError( "%r is not a valid %s" % (value, cls.__name__) - ) as ve_exc: - if result is None: - raise ve_exc + ) + if result is None: + raise ve_exc - te_exc = TypeError( - 'error in %s._missing_: returned %r instead of None or a valid member' - % (cls.__name__, result) - ) - te_exc.__context__ = ve_exc - raise te_exc + te_exc = TypeError( + 'error in %s._missing_: returned %r instead of None or a valid member' + % (cls.__name__, result) + ) + te_exc.__context__ = ve_exc + raise te_exc diff --git a/source/watchdog.py b/source/watchdog.py index d220bc3f0c4..7790ac681be 100644 --- a/source/watchdog.py +++ b/source/watchdog.py @@ -396,7 +396,11 @@ def cancellableExecute(func, *args, ccPumpMessages=True, **kwargs): @raise CallCancelled: If the call was cancelled. """ global cancellableCallThread - if not isRunning or _suspended or not isinstance(threading.currentThread(), threading._MainThread): + if ( + not isRunning + or _suspended + or threading.current_thread() is not threading.main_thread() + ): # Watchdog is not running or this is a background thread, # so just execute the call. return func(*args, **kwargs) From d47a2dd7c808c512fa8bc1cbad3c23551c31bf87 Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Tue, 26 Sep 2023 15:46:26 +1000 Subject: [PATCH 2/3] fix scaling size --- source/gui/dpiScalingHelper.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/gui/dpiScalingHelper.py b/source/gui/dpiScalingHelper.py index 6ba3714234f..12f8065a9b5 100644 --- a/source/gui/dpiScalingHelper.py +++ b/source/gui/dpiScalingHelper.py @@ -1,6 +1,6 @@ # -*- coding: UTF-8 -*- # A part of NonVisual Desktop Access (NVDA) -# Copyright (C) 2018-2022 NV Access Limited +# Copyright (C) 2018-2023 NV Access Limited # This file is covered by the GNU General Public License. # See the file COPYING for more details. from typing import Optional, Any, Callable, Tuple, Union @@ -8,17 +8,17 @@ _FloatInt = Union[int, float] _Size = Union[Tuple[_FloatInt, _FloatInt], _FloatInt] -_ScaledSize = Union[Tuple[float, float], float] +_ScaledSize = Union[Tuple[int, int], int] def scaleSize(scaleFactor: float, size: _Size) -> _ScaledSize: """Helper method to scale a size using the logical DPI @param size: The size (x, y) as a tuple or a single numerical type to scale - @returns: The scaled size, as a float or tuple of floats. + @returns: The scaled size, as a tuple or a single numerical type. """ if isinstance(size, tuple): - return (scaleFactor * size[0], scaleFactor * size[1]) - return scaleFactor * size + return (int(scaleFactor * size[0]), int(scaleFactor * size[1])) + return int(scaleFactor * size) def getScaleFactor(windowHandle: int) -> float: From 3d9a46486dcd5620d65a82aeb9fd934a454e40bf Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Tue, 26 Sep 2023 16:22:37 +1000 Subject: [PATCH 3/3] Use AppendColumn --- source/gui/_addonStoreGui/controls/addonList.py | 4 ++-- source/gui/addonGui.py | 14 +++++++------- source/gui/settingsDialogs.py | 8 ++++---- source/gui/speechDict.py | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/source/gui/_addonStoreGui/controls/addonList.py b/source/gui/_addonStoreGui/controls/addonList.py index 09375d5e357..259dd3c14c6 100644 --- a/source/gui/_addonStoreGui/controls/addonList.py +++ b/source/gui/_addonStoreGui/controls/addonList.py @@ -64,8 +64,8 @@ def __init__( def _refreshColumns(self): self.ClearAll() - for colIndex, col in enumerate(self._addonsListVM.presentedFields): - self.InsertColumn(colIndex, col.displayString, width=self.scaleSize(col.width)) + for col in self._addonsListVM.presentedFields: + self.AppendColumn(col.displayString, width=self.scaleSize(col.width)) self.Layout() def _getListSelectionPosition(self) -> Optional[wx.Position]: diff --git a/source/gui/addonGui.py b/source/gui/addonGui.py index e21636e95df..d9cf53a4625 100644 --- a/source/gui/addonGui.py +++ b/source/gui/addonGui.py @@ -185,13 +185,13 @@ def __init__(self, parent): proportion=1, ) # Translators: The label for a column in add-ons list used to identify add-on package name (example: package is OCR). - self.addonsList.InsertColumn(0, _("Package"), width=self.scaleSize(150)) + self.addonsList.AppendColumn(_("Package"), width=self.scaleSize(150)) # Translators: The label for a column in add-ons list used to identify add-on's running status (example: status is running). - self.addonsList.InsertColumn(1, _("Status"), width=self.scaleSize(50)) + self.addonsList.AppendColumn(_("Status"), width=self.scaleSize(50)) # Translators: The label for a column in add-ons list used to identify add-on's version (example: version is 0.3). - self.addonsList.InsertColumn(2, _("Version"), width=self.scaleSize(50)) + self.addonsList.AppendColumn(_("Version"), width=self.scaleSize(50)) # Translators: The label for a column in add-ons list used to identify add-on's author (example: author is NV Access). - self.addonsList.InsertColumn(3, _("Author"), width=self.scaleSize(300)) + self.addonsList.AppendColumn(_("Author"), width=self.scaleSize(300)) self.addonsList.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onListItemSelected) # this is the group of buttons that affects the currently selected addon @@ -710,11 +710,11 @@ def __init__( ) # Translators: The label for a column in add-ons list used to identify add-on package name (example: package is OCR). - self.addonsList.InsertColumn(1, _("Package"), width=self.scaleSize(150)) + self.addonsList.AppendColumn(_("Package"), width=self.scaleSize(150)) # Translators: The label for a column in add-ons list used to identify add-on's running status (example: status is running). - self.addonsList.InsertColumn(2, _("Version"), width=self.scaleSize(150)) + self.addonsList.AppendColumn(_("Version"), width=self.scaleSize(150)) # Translators: The label for a column in add-ons list used to provide some explanation about incompatibility - self.addonsList.InsertColumn(3, _("Incompatible reason"), width=self.scaleSize(180)) + self.addonsList.AppendColumn(_("Incompatible reason"), width=self.scaleSize(180)) buttonSizer = guiHelper.ButtonHelper(wx.HORIZONTAL) # Translators: The label for a button in Add-ons Manager dialog to show information about the selected add-on. diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 8a5757837d7..a9190f49658 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -4453,14 +4453,14 @@ def makeSettings(self, settingsSizer): ) # Translators: The label for a column in symbols list used to identify a symbol. - self.symbolsList.InsertColumn(0, _("Symbol"), width=self.scaleSize(150)) + self.symbolsList.AppendColumn(_("Symbol"), width=self.scaleSize(150)) # Translators: The label for a column in symbols list used to identify a replacement. - self.symbolsList.InsertColumn(1, _("Replacement")) + self.symbolsList.AppendColumn(_("Replacement")) # Translators: The label for a column in symbols list used to identify a symbol's speech level (either none, some, most, all or character). - self.symbolsList.InsertColumn(2, _("Level")) + self.symbolsList.AppendColumn(_("Level")) # Translators: The label for a column in symbols list which specifies when the actual symbol will be sent to the synthesizer (preserved). # See the "Punctuation/Symbol Pronunciation" section of the User Guide for details. - self.symbolsList.InsertColumn(3, _("Preserve")) + self.symbolsList.AppendColumn(_("Preserve")) self.symbolsList.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onListItemFocused) # Translators: The label for the group of controls in symbol pronunciation dialog to change the pronunciation of a symbol. diff --git a/source/gui/speechDict.py b/source/gui/speechDict.py index ef7f45b714e..e564bb0de34 100644 --- a/source/gui/speechDict.py +++ b/source/gui/speechDict.py @@ -177,19 +177,19 @@ def makeSettings(self, settingsSizer): wx.ListCtrl, style=wx.LC_REPORT | wx.LC_SINGLE_SEL ) # Translators: The label for a column in dictionary entries list used to identify comments for the entry. - self.dictList.InsertColumn(0, _("Comment"), width=150) + self.dictList.AppendColumn(_("Comment"), width=150) # Translators: The label for a column in dictionary entries list used to identify pattern # (original word or a pattern). - self.dictList.InsertColumn(1, _("Pattern"), width=150) + self.dictList.AppendColumn(_("Pattern"), width=150) # Translators: The label for a column in dictionary entries list and in a list of symbols # from symbol pronunciation dialog used to identify replacement for a pattern or a symbol - self.dictList.InsertColumn(2, _("Replacement"), width=150) + self.dictList.AppendColumn(_("Replacement"), width=150) # Translators: The label for a column in dictionary entries list used to identify # whether the entry is case sensitive or not. - self.dictList.InsertColumn(3, _("case"), width=50) + self.dictList.AppendColumn(_("case"), width=50) # Translators: The label for a column in dictionary entries list used to identify # whether the entry is a regular expression, matches whole words, or matches anywhere. - self.dictList.InsertColumn(4, _("Type"), width=50) + self.dictList.AppendColumn(_("Type"), width=50) self.offOn = (_("off"), _("on")) for entry in self.tempSpeechDict: self.dictList.Append((