diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 92ea82c..c707018 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -33,7 +33,11 @@ jobs: uv sync - name: Code checks - run: export SKIP=no-commit-to-branch; uv run pre-commit run --all-files + # Pyright is skipped here for the same reason .pre-commit-config.yaml skips it on + # pre-commit.ci: it needs the NVDA source tree at ../nvda/source (see the extraPaths + # setting in pyproject.toml), which is not available on the runner, so every NVDA + # import is unresolved and the hook can never pass. + run: export SKIP=no-commit-to-branch,pyright; uv run pre-commit run --all-files - name: building addon run: uv run scons && uv run scons pot diff --git a/addon/globalPlugins/columnsReview/__init__.py b/addon/globalPlugins/columnsReview/__init__.py index 1e69975..000fb90 100644 --- a/addon/globalPlugins/columnsReview/__init__.py +++ b/addon/globalPlugins/columnsReview/__init__.py @@ -20,12 +20,17 @@ from logHandler import log from NVDAObjects.IAccessible import getNVDAObjectFromEvent from NVDAObjects.IAccessible import sysListView32 -from NVDAObjects.UIA import UIA # For UIA implementations only, chiefly 64-bit. +from NVDAObjects.UIA import UIA # For UIA implementations only, chiefly 64-bit. import sys from comtypes.client import CreateObject from comtypes.gen.IAccessible2Lib import IAccessible2 from globalCommands import commands -from oleacc import STATE_SYSTEM_MULTISELECTABLE, SELFLAG_TAKEFOCUS, SELFLAG_TAKESELECTION, SELFLAG_ADDSELECTION +from oleacc import ( + STATE_SYSTEM_MULTISELECTABLE, + SELFLAG_TAKEFOCUS, + SELFLAG_TAKESELECTION, + SELFLAG_ADDSELECTION, +) from scriptHandler import getLastScriptRepeatCount import weakref from threading import Thread, Event @@ -77,12 +82,13 @@ # for debug logging DEBUG = False + def debugLog(message): if DEBUG: log.info(message) -class GlobalPlugin(globalPluginHandler.GlobalPlugin): +class GlobalPlugin(globalPluginHandler.GlobalPlugin): def __init__(self, *args, **kwargs): super(GlobalPlugin, self).__init__(*args, **kwargs) if globalVars.appArgs.secure: @@ -116,11 +122,7 @@ def chooseNVDAObjectOverlayClasses(self, obj, clsList): clsList.insert(0, CRList64) return # for Outlook - if ( - objRole == roles.TABLE - and UIA in clsList - and obj.UIAElement.cachedClassName == "SuperGrid" - ): + if objRole == roles.TABLE and UIA in clsList and obj.UIAElement.cachedClassName == "SuperGrid": clsList.insert(0, UIASuperGrid) return # for Thunderbird before 115 @@ -142,10 +144,7 @@ def chooseNVDAObjectOverlayClasses(self, obj, clsList): def event_focusEntered(self, obj, nextHandler): objRole = obj.role - if ( - objRole == roles.LIST - or (objRole == roles.TABLE and obj.windowClassName == "MozillaWindowClass") - ): + if objRole == roles.LIST or (objRole == roles.TABLE and obj.windowClassName == "MozillaWindowClass"): self.proceedWithBounds = True else: self.proceedWithBounds = False @@ -160,11 +159,9 @@ def event_gainFocus(self, obj, nextHandler): nextHandler() return objRole = obj.role - if ( - self.proceedWithBounds - and (objRole == roles.LISTITEM - or (objRole == roles.TABLEROW and obj.windowClassName == "MozillaWindowClass") - ) + if self.proceedWithBounds and ( + objRole == roles.LISTITEM + or (objRole == roles.TABLEROW and obj.windowClassName == "MozillaWindowClass") ): self.reportListBounds(obj) nextHandler() @@ -178,7 +175,7 @@ def reportListBounds(self, obj): similar = positionInfo.get("similarItemsInGroup") if index == similar == 1: pos = "mono" - elif index == similar != None: + elif index == similar is not None: pos = "bottom" elif index == 1: pos = "top" @@ -193,20 +190,39 @@ def reportListBounds(self, obj): bottomBeep = confFromObj.bottomBeep beepLen = confFromObj.beepLen if pos == "mono": - # Translators: message when list contains one item only - message = (_("Mono-item list: "),) if reportFunc != beep else (abs(topBeep-bottomBeep), beepLen*2,) + message = ( + # Translators: message when list contains one item only + (_("Mono-item list: "),) + if reportFunc != beep + else ( + abs(topBeep - bottomBeep), + beepLen * 2, + ) + ) elif pos == "bottom": - # Translators: message when user lands on the last list item - message = (_("List bottom: "),) if reportFunc != beep else (topBeep, beepLen,) + message = ( + # Translators: message when user lands on the last list item + (_("List bottom: "),) + if reportFunc != beep + else ( + topBeep, + beepLen, + ) + ) elif pos == "top": - # Translators: message when user lands on the first list item - message = (_("List top: "),) if reportFunc != beep else (bottomBeep, beepLen,) + message = ( + # Translators: message when user lands on the first list item + (_("List top: "),) + if reportFunc != beep + else ( + bottomBeep, + beepLen, + ) + ) reportFunc(*message) def createMenu(self): - gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append( - dialogs.ColumnsReviewSettingsDialog - ) + gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append(dialogs.ColumnsReviewSettingsDialog) def terminate(self): for extPointName in PROFILE_SWITCHED_NOTIFIERS: @@ -214,9 +230,7 @@ def terminate(self): getattr(config, extPointName).unregister(self.handleConfigProfileSwitch) except AttributeError: continue - gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove( - dialogs.ColumnsReviewSettingsDialog - ) + gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove(dialogs.ColumnsReviewSettingsDialog) # release COM object if CRList64.shell: try: @@ -238,7 +252,7 @@ class CRList(object): # Translators: Name of the default category # in the Input Gestures dialog where scripts of this add-on are placed. - scriptCategory = _('{name} (DO NOT EDIT!)').format(name=addonHandler.getCodeAddon().manifest['summary']) + scriptCategory = _("{name} (DO NOT EDIT!)").format(name=addonHandler.getCodeAddon().manifest["summary"]) _instances = weakref.WeakSet() # the variable representing tens @@ -270,7 +284,7 @@ def initOverlayClass(self): def event_focusEntered(self): # apparently, this event is fired only by pre-populated lists -# ui.message("focusEntered raised!") + # ui.message("focusEntered raised!") super(CRList, self).event_focusEntered() self.bindCRGestures() @@ -284,7 +298,11 @@ def bindCRGestures(self, reinitializeObj=False): # other useful gesture to remap scriptMap = { # for color reporting - getattr(commands, "script_reportOrShowFormattingAtCaret", commands.script_reportFormatting): "reportOrShowFormattingAtCaret", + getattr( + commands, + "script_reportOrShowFormattingAtCaret", + commands.script_reportFormatting, + ): "reportOrShowFormattingAtCaret", # for current selection commands.script_reportCurrentSelection: "reportCurrentSelection", } @@ -316,7 +334,10 @@ def bindCRGestures(self, reinitializeObj=False): else: # do same things for no numpad case self.bindGesture("kb:{0}+0".format(enabledModifiers), "readColumn") - self.bindGesture("kb:{0}+{1}".format(enabledModifiers, confFromObj.nextColumnsGroupKey), "changeInterval") + self.bindGesture( + "kb:{0}+{1}".format(enabledModifiers, confFromObj.nextColumnsGroupKey), + "changeInterval", + ) self.bindGesture("kb:{0}+delete".format(enabledModifiers), "itemInfo") self.bindGesture("kb:{0}+enter".format(enabledModifiers), "manageHeaders") @@ -330,7 +351,7 @@ def getColumnData(self, colNumber): def script_readColumn(self, gesture): # ask for index - num = self.getIndex(gesture.mainKeyName.rsplit('+', 1)[-1]) + num = self.getIndex(gesture.mainKeyName.rsplit("+", 1)[-1]) repeatCount = getLastScriptRepeatCount() if not repeatCount: self.repeatCount = 0 @@ -345,7 +366,7 @@ def script_readColumn(self, gesture): self.repeatCount += 1 actionToExecute = configuredActions().get( self.repeatCount, - ACTIONS[0].name # Default dummy action + ACTIONS[0].name, # Default dummy action ) actionToExecute = actionFromName(actionToExecute) if not actionToExecute.performsAction: @@ -371,7 +392,7 @@ def script_readColumn(self, gesture): script_readColumn.canPropagate = True script_readColumn.__doc__ = _( # Translators: documentation of script to read columns - "Returns the header and the content of the list column at the index corresponding to the number pressed" + "Returns the header and the content of the list column at the index corresponding to the number pressed", ) script_readColumn.speakOnDemand = True @@ -385,10 +406,10 @@ def getIndex(self, key): # if num == 0, from numpad or keyboard if not num: # set it to 10, 20, etc - num = (self.tens+1)*10 + num = (self.tens + 1) * 10 else: # set it to 9, 13, 22, etc - num = self.tens*10+num + num = self.tens * 10 + num return num def script_changeInterval(self, gesture): @@ -396,7 +417,7 @@ def script_changeInterval(self, gesture): it's built so to have always all gestures from 1 to 0""" curItem = api.getFocusObject() # no further interval - if curItem.childCount<10: + if curItem.childCount < 10: # Translators: message when digit pressed exceed the columns number ui.message(_("No more columns available")) return @@ -405,23 +426,23 @@ def script_changeInterval(self, gesture): # intervals (2) of needed 10 columns; # if childCount is a multiple of 10 (es. 30), # we have exactly childCount/10=3 intervals. - mod = curItem.childCount//10+(1 if curItem.childCount%10 else 0) + mod = curItem.childCount // 10 + (1 if curItem.childCount % 10 else 0) # now, we can scroll ten by ten among intervals, using modulus - self.tens = (self.tens+1)%mod + self.tens = (self.tens + 1) % mod # interval bounds to announce - start = self.tens*10+1 + start = self.tens * 10 + 1 # nice: announce what is the absolutely last column available - if self.tens == mod-1: + if self.tens == mod - 1: end = curItem.childCount else: - end = (self.tens+1)*10 + end = (self.tens + 1) * 10 # Translators: message when you change interval in a list with more ten columns ui.message(_("From {start} to {end}").format(start=start, end=end)) script_changeInterval.canPropagate = True script_changeInterval.__doc__ = _( # Translators: documentation for script to change interval - "Cycles between a variable number of intervals of ten columns" + "Cycles between a variable number of intervals of ten columns", ) def script_itemInfo(self, gesture): @@ -439,28 +460,26 @@ def script_itemInfo(self, gesture): # Translators: Reported when information about position on a list cannot be retrieved. ui.message(_("No information available")) else: - info = ' '.join([NVDALocale("item"), NVDALocale("{number} of {total}").format(number=number, total=total)]) + info = " ".join( + [NVDALocale("item"), NVDALocale("{number} of {total}").format(number=number, total=total)], + ) ui.message(info) script_itemInfo.canPropagate = True script_itemInfo.__doc__ = _( # Translators: documentation for script to announce list item info - "Announces list item position information" + "Announces list item position information", ) script_itemInfo.speakOnDemand = True def script_manageHeaders(self, gesture): headers = [h for h in self.getHeaderParent().children if states.INVISIBLE not in h.states] - wx.CallAfter( - dialogs.HeaderDialog.Run, - title=self.appModule.appName, - headerList=headers - ) + wx.CallAfter(dialogs.HeaderDialog.Run, title=self.appModule.appName, headerList=headers) script_manageHeaders.canPropagate = True script_manageHeaders.__doc__ = _( # Translators: documentation for script to manage headers - "Provides a dialog for interactions with list column headers" + "Provides a dialog for interactions with list column headers", ) def getHeaderParent(self): @@ -476,7 +495,7 @@ def getSelectedItems(self): curItem = api.getFocusObject() items = [] item = self.firstChild - while (item and item.role == curItem.role): + while item and item.role == curItem.role: if states.SELECTED in item.states: itemChild = item.getChild(0) itemName = itemChild.name if itemChild else item.name @@ -488,15 +507,17 @@ def getSelectedItems(self): def script_reportCurrentSelection(self, gesture): items = self.getSelectedItems() if items is not None: - ui.message(_( - # Translators: message presented when get selected item count and names - "{selCount} selected items: {selNames}").format(selCount=len(items), selNames=', '.join(items) - )) + ui.message( + _( + # Translators: message presented when get selected item count and names + "{selCount} selected items: {selNames}", + ).format(selCount=len(items), selNames=", ".join(items)), + ) script_reportCurrentSelection.canPropagate = True script_reportCurrentSelection.__doc__ = _( # Translators: documentation for script to know current selected items - "Reports current selected list items" + "Reports current selected list items", ) script_reportCurrentSelection.speakOnDemand = True @@ -507,7 +528,7 @@ def script_find(self, gesture, reverse=False): else: try: d = FindDialog(gui.mainFrame, self, self._lastFindText, self._lastCaseSensitivity, reverse) - except: + except Exception: # until NVDA 2020.3 d = FindDialog(gui.mainFrame, self, self._lastFindText, self._lastCaseSensitivity) gui.mainFrame.prePopup() @@ -517,7 +538,7 @@ def script_find(self, gesture, reverse=False): script_find.canPropagate = True script_find.__doc__ = _( # Translators: documentation for script to find in list - "Provides a dialog for searching in item list" + "Provides a dialog for searching in item list", ) def doFindText(self, text, reverse=False, caseSensitive=False): @@ -529,6 +550,7 @@ def doFindText(self, text, reverse=False, caseSensitive=False): msgArgs = [_("Searching...")] try: from speech.priorities import SpeechPriority + msgArgs.append(SpeechPriority.NOW) except ImportError: # NVDA 2019.2.1 or earlier - no priorities in speech. pass @@ -542,7 +564,12 @@ def doFindText(self, text, reverse=False, caseSensitive=False): if res: self.successSearchAction(res) else: - wx.CallAfter(gui.messageBox, NVDALocale('text "%s" not found')%text, NVDALocale("Find Error"), wx.OK|wx.ICON_ERROR) + wx.CallAfter( + gui.messageBox, + NVDALocale('text "%s" not found') % text, + NVDALocale("Find Error"), + wx.OK | wx.ICON_ERROR, + ) CRList._lastFindText = text CRList._lastCaseSensitivity = caseSensitive @@ -566,21 +593,24 @@ def launchFinder(self, text, reverse, caseSensitive): if finder.res: core.callLater(0, self.successSearchAction, finder.res) else: - wx.CallAfter(gui.messageBox, NVDALocale('text "%s" not found')%text, NVDALocale("Find Error"), wx.OK|wx.ICON_ERROR) + wx.CallAfter( + gui.messageBox, + NVDALocale('text "%s" not found') % text, + NVDALocale("Find Error"), + wx.OK | wx.ICON_ERROR, + ) else: core.callLater(0, beep, 220, 150) finder = None - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs the search in item list, via NVDA object navigation.""" # generic implementation curItem = self.searchFromItem item = curItem.previous if reverse else curItem.next - while (item and item.role == curItem.role): - if ( - (not caseSensitive and item.name and text.lower() in item.name.lower()) - or - (caseSensitive and text in item.name) + while item and item.role == curItem.role: + if (not caseSensitive and item.name and text.lower() in item.name.lower()) or ( + caseSensitive and text in item.name ): return item item = item.previous if reverse else item.next @@ -598,12 +628,12 @@ def script_findNext(self, gesture): self.script_find(gesture) return self.searchFromItem = api.getFocusObject() - self.doFindText(self._lastFindText, caseSensitive = self._lastCaseSensitivity) + self.doFindText(self._lastFindText, caseSensitive=self._lastCaseSensitivity) script_findNext.canPropagate = True script_findNext.__doc__ = _( # Translators: documentation for script to manage headers - "Goes to next result of current search" + "Goes to next result of current search", ) def script_findPrevious(self, gesture): @@ -611,12 +641,12 @@ def script_findPrevious(self, gesture): self.script_find(gesture, reverse=True) return self.searchFromItem = api.getFocusObject() - self.doFindText(self._lastFindText, reverse=True, caseSensitive = self._lastCaseSensitivity) + self.doFindText(self._lastFindText, reverse=True, caseSensitive=self._lastCaseSensitivity) script_findPrevious.canPropagate = True script_findPrevious.__doc__ = _( # Translators: documentation for script to manage headers - "Goes to previous result of current search" + "Goes to previous result of current search", ) def script_readListItems(self, gesture): @@ -626,7 +656,7 @@ def script_readListItems(self, gesture): script_readListItems.canPropagate = True script_readListItems.__doc__ = _( # Translators: documentation for script to read all list items starting from the focused one. - "Starts reading all list items beginning at the item with focus" + "Starts reading all list items beginning at the item with focus", ) script_readListItems.speakOnDemand = True @@ -673,7 +703,7 @@ def reportEmpty(self): def event_gainFocus(self): # apparently, this event is fired only when focusing an empty list # call super to get list type/name reporting -# ui.message("gainFocus raised!") + # ui.message("gainFocus raised!") super(CRList, self).event_gainFocus() # ignore desktop, usually not empty if self.supportsEmptyListAnnouncements and self.name != "Desktop" and self.isEmptyList(): @@ -687,7 +717,7 @@ def event_gainFocus(self): self.bindCRGestures() def waitForItems(self): - # for 10 seconds, check every 100 milliseconds + # for 10 seconds, check every 100 milliseconds # if list remains empty res, value = blockUntilConditionMet(self.isEmptyList, 10.0, lambda empty: not empty, 0.1) # now, if list has items and focus @@ -712,7 +742,7 @@ def bindGesturesForEmpty(self): scriptFuncs = ( commands.script_reportCurrentFocus, commands.script_reportCurrentLine, - commands.script_reportCurrentSelection + commands.script_reportCurrentSelection, ) scriptDict = getScriptGestures(*scriptFuncs) for script, gestures in scriptDict.items(): @@ -731,28 +761,34 @@ def script_reportOrShowFormattingAtCaret(self, gesture): for field in fields: if isinstance(field, textInfos.FieldCommand) and isinstance(field.field, textInfos.FormatField): fgColor = field.field.get("color") - if fgColor: fgColors.add(fgColor.name) + if fgColor: + fgColors.add(fgColor.name) bgColor = field.field.get("background-color") - if bgColor: bgColors.add(bgColor.name) + if bgColor: + bgColors.add(bgColor.name) if fgColors and bgColors: - foregroundColors = ', '.join(fgColors) - backgroundColors = ', '.join(bgColors) + foregroundColors = ", ".join(fgColors) + backgroundColors = ", ".join(bgColors) # Translators: message listing foreground over background colors - message = _("{foregroundColors} over {backgroundColors}").format(foregroundColors=foregroundColors, backgroundColors=backgroundColors) + message = _("{foregroundColors} over {backgroundColors}").format( + foregroundColors=foregroundColors, + backgroundColors=backgroundColors, + ) else: message = NVDALocale("No formatting information") ui.message(message) + script_reportOrShowFormattingAtCaret.canPropagate = True script_reportOrShowFormattingAtCaret.__doc__ = _( # Translators: Description of the keyboard command, # which reports foreground and background color of the current list item. - "reports foreground and background colors of the current list item." + "reports foreground and background colors of the current list item.", ) script_reportOrShowFormattingAtCaret.speakOnDemand = True class CRList32(CRList): -# for SysListView32 or WindowsForms10.SysListView32.app.0.* + # for SysListView32 or WindowsForms10.SysListView32.app.0.* # flag to guarantee thread support THREAD_SUPPORTED = True @@ -768,7 +804,7 @@ def getColumnData(self, colNumber): # for invisible column case num = self.getFixedNum(colNumber) # getChild is zero-based - obj = curItem.getChild(num-1) + obj = curItem.getChild(num - 1) else: obj = curItem # None obj should be generated @@ -790,9 +826,9 @@ def getColumnData(self, colNumber): def getFixedNum(self, num): curItem = api.getFocusObject() child = curItem.simpleFirstChild - startNum = child.columnNumber-1 + startNum = child.columnNumber - 1 if num == 1: - return startNum+1 + return startNum + 1 counter = 1 stop = False while not stop: @@ -803,7 +839,7 @@ def getFixedNum(self, num): counter += 1 if counter == num: stop = True - return child.columnNumber if child else curItem.childCount+1 + return child.columnNumber if child else curItem.childCount + 1 def getHeaderParent(self): # faster than previous self.simpleParent.children[-1] @@ -811,7 +847,7 @@ def getHeaderParent(self): headerParent = getNVDAObjectFromEvent(headerHandle, winUser.OBJID_CLIENT, 0) return headerParent - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs search in item list, via object handles.""" # specific implementation fg = api.getForegroundObject() @@ -825,17 +861,15 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): # 1-based index curIndex = curItem.positionInfo["indexInGroup"] if reverse: - indexes = rangeFunc(curIndex-1,0,-1) + indexes = rangeFunc(curIndex - 1, 0, -1) else: - indexes = rangeFunc(curIndex+1,listLen+1) + indexes = rangeFunc(curIndex + 1, listLen + 1) for index in indexes: item = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, index) if not item or not item.name: continue - if ( - (not caseSensitive and text.lower() in item.name.lower()) - or - (caseSensitive and text in item.name) + if (not caseSensitive and text.lower() in item.name.lower()) or ( + caseSensitive and text in item.name ): return item if stopCheck(): @@ -847,7 +881,7 @@ def isMultipleSelectionSupported(self): states = curItem.IAccessibleObject.accState(curItem.IAccessibleChildID) if states & STATE_SYSTEM_MULTISELECTABLE: return True - except: + except Exception: pass def successSearchAction(self, res): @@ -859,7 +893,7 @@ def successSearchAction(self, res): if useMultipleSelection: res.IAccessibleObject.accSelect(SELFLAG_ADDSELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) else: - res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) + res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) def getSelectedItems(self): parentHandle = self.windowHandle @@ -870,12 +904,12 @@ def getSelectedItems(self): parentHandle, sysListView32.LVM_GETNEXTITEM, -1, - ctypes.wintypes.LPARAM(sysListView32.LVNI_SELECTED) + ctypes.wintypes.LPARAM(sysListView32.LVNI_SELECTED), ) listLen = watchdog.cancellableSendMessage(parentHandle, sysListView32.LVM_GETITEMCOUNT, 0, 0) items = [] - while (0 <= selItemIndex < listLen): - item = getNVDAObjectFromEvent(parentHandle, winUser.OBJID_CLIENT, selItemIndex+1) + while 0 <= selItemIndex < listLen: + item = getNVDAObjectFromEvent(parentHandle, winUser.OBJID_CLIENT, selItemIndex + 1) itemChild = item.getChild(0) itemName = itemChild.name if itemChild else item.name if itemName: @@ -885,7 +919,7 @@ def getSelectedItems(self): parentHandle, sysListView32.LVM_GETNEXTITEM, selItemIndex, - ctypes.wintypes.LPARAM(sysListView32.LVNI_SELECTED) + ctypes.wintypes.LPARAM(sysListView32.LVNI_SELECTED), ) return items @@ -929,7 +963,7 @@ def getColumnData(self, colNumber): # colNumber is passed as is, excluding the first position (0) of the children list # containing an icon, so this check in this way curItem = api.getFocusObject() - if colNumber > curItem.childCount-1: + if colNumber > curItem.childCount - 1: raise noColumnAtIndex obj = curItem.getChild(colNumber) # obj.value is the column content @@ -968,7 +1002,7 @@ def preCheck(self, onFailureMsg=None): if window.hwnd and window.hwnd == fg.windowHandle: self.curWindow = window break - except: + except Exception: pass if not self.curWindow: if onFailureMsg: @@ -999,6 +1033,7 @@ def script_findNext(self, gesture): # Translators: Reported when current list does not support searching. if self.preCheck(_("Cannot search here.")): super(CRList64, self).script_findNext(gesture) + script_findNext.canPropagate = True script_findNext.__doc__ = CRList.script_findNext.__doc__ @@ -1010,7 +1045,7 @@ def script_findPrevious(self, gesture): script_findPrevious.canPropagate = True script_findPrevious.__doc__ = CRList.script_findPrevious.__doc__ - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs search in item list, via shell32 object.""" # reacquire curWindow for current thread self.preCheck() # No message on failure here as we cannot hit this code path if shell is not supported. @@ -1023,7 +1058,7 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): # corresponding indexes to query info for each file detailIndexes = [] # 500 limit seems reasonable (they are 300+ on my system!) - for index in rangeFunc(0,500): + for index in rangeFunc(0, 500): # localized detail name, as "size" detailName = curFolder.GetDetailsOf("", index) # we get index corresponding to name, so update lists @@ -1039,7 +1074,13 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): curPath = self.curWindow.LocationURL.rsplit("/", 1)[0][8:] # we get from current path, to ensure precision # also on external drives or different partitions (not verified) - getBytePerSector(ctypes.c_wchar_p(curPath), None, ctypes.pointer(bytePerSector), None, None,) + getBytePerSector( + ctypes.c_wchar_p(curPath), + None, + ctypes.pointer(bytePerSector), + None, + None, + ) listLen = curItem.positionInfo["similarItemsInGroup"] # 1-based index curIndex = curItem.positionInfo["indexInGroup"] @@ -1047,13 +1088,13 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): items = curFolder.Items() resIndex = None if reverse: -# indexes = rangeFunc(curIndex-2,-1,-1) + # indexes = rangeFunc(curIndex-2,-1,-1) # unfortunately, list pointer seems to change # for each query in reverse order # so, this range - indexes = rangeFunc(0,curIndex-1) + indexes = rangeFunc(0, curIndex - 1) else: - indexes = rangeFunc(curIndex,listLen) + indexes = rangeFunc(curIndex, listLen) for index in indexes: # pointer to item item = items.Item(index) @@ -1064,23 +1105,25 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): # item.size returns as file size in bytes # but explorer shows file size on disk, in kilobytes... if (detailIndex == 1) and not item.IsFolder: - # formula below is an optimization of ((item.size-1)/bytePerSector.value+1)*bytePerSector.value - diskSizeB = ((item.size-1)&~(bytePerSector.value-1))+bytePerSector.value if item.size>512 else 1024 - diskSizeKB = int(round(diskSizeB/1024.0)) + # formula below is an optimization of ((item.size-1)/bytePerSector.value+1)*bytePerSector.value + diskSizeB = ( + ((item.size - 1) & ~(bytePerSector.value - 1)) + bytePerSector.value + if item.size > 512 + else 1024 + ) + diskSizeKB = int(round(diskSizeB / 1024.0)) # to insert thousands separator - formattedSize = locale.format_string('%d', diskSizeKB, True) - formattedSize = formattedSize if py3 else formattedSize.decode('mbcs') - explorerSize = ' '.join([formattedSize, "KB"]) + formattedSize = locale.format_string("%d", diskSizeKB, True) + formattedSize = formattedSize if py3 else formattedSize.decode("mbcs") + explorerSize = " ".join([formattedSize, "KB"]) tempItemInfo.append(explorerSize) else: tempItemInfo.append(curFolder.GetDetailsOf(item, detailIndex)) # our reconstruction of item as shown in explorer - itemInfo = '; '.join(tempItemInfo) + itemInfo = "; ".join(tempItemInfo) # finally, the search if - if ( - (not caseSensitive and text.lower() in itemInfo.lower()) - or - (caseSensitive and text in itemInfo) + if (not caseSensitive and text.lower() in itemInfo.lower()) or ( + caseSensitive and text in itemInfo ): resIndex = index if not reverse: @@ -1121,7 +1164,7 @@ def isEmptyList(self): try: watchdog.alive() childCount = self._get_UIAGridPattern().CurrentRowCount - except: + except Exception: # assume not empty childCount = 1 return not bool(childCount) @@ -1144,7 +1187,6 @@ def event_gainFocus(self): class UIASuperGrid(CRList): - # flag to guarantee thread support, # apparently, self-managed by UIAHandler.handler.MTAThreadFunc THREAD_SUPPORTED = True @@ -1155,17 +1197,21 @@ class UIASuperGrid(CRList): def preCheck(self, featureKeys, onFailureMsg=None): if self.UIAFeatures is None: # check and cache results - self.UIAFeatures = {}.fromkeys(("selection","scroll","selectionItem", "grid"), False) - if hasattr(self, 'UIASelectionPattern') and self.UIASelectionPattern is not None: + self.UIAFeatures = {}.fromkeys(("selection", "scroll", "selectionItem", "grid"), False) + if hasattr(self, "UIASelectionPattern") and self.UIASelectionPattern is not None: self.UIAFeatures["selection"] = True # for some reason, NVDA does not expose UIAScrollPattern, so... - if hasattr(self, '_getUIAPattern') and self._getUIAPattern(UIAHandler.UIA_ScrollPatternId, UIAHandler.IUIAutomationScrollPattern) is not None: + if ( + hasattr(self, "_getUIAPattern") + and self._getUIAPattern(UIAHandler.UIA_ScrollPatternId, UIAHandler.IUIAutomationScrollPattern) + is not None + ): self.UIAFeatures["scroll"] = True - if hasattr(self, 'UIAGridPattern') and self.UIAGridPattern is not None: + if hasattr(self, "UIAGridPattern") and self.UIAGridPattern is not None: self.UIAFeatures["grid"] = True # check everytime focus = api.getFocusObject() - if hasattr(focus, 'UIASelectionItemPattern') and focus.UIASelectionItemPattern is not None: + if hasattr(focus, "UIASelectionItemPattern") and focus.UIASelectionItemPattern is not None: self.UIAFeatures["selectionItem"] = True res = all((self.UIAFeatures[x] for x in featureKeys)) if not res and onFailureMsg: @@ -1176,7 +1222,7 @@ def getColumnData(self, colNumber): curItem = api.getFocusObject() if colNumber > curItem.childCount: raise noColumnAtIndex - obj = curItem.getChild(colNumber-1) + obj = curItem.getChild(colNumber - 1) # obj.name is the column content if obj and obj.name and len(obj.name): content = obj.name @@ -1203,19 +1249,19 @@ def getSelectedItems(self): items = [] try: selArray = self.UIASelectionPattern.GetCurrentSelection() - for index in rangeFunc(0,selArray.Length): + for index in rangeFunc(0, selArray.Length): item = selArray.GetElement(index).CurrentName items.append(item) - except AttributeError: # UIASelectionPattern absent or None + except AttributeError: # UIASelectionPattern absent or None pass return items def isMultipleSelectionSupported(self): # currently, scrolling the list brings to previous selection lost, # making this feature quite useless, so no support for now - #try: - # return bool(self.UIASelectionPattern.CurrentCanSelectMultiple) - #except AttributeError: # UIASelectionPattern absent or None + # try: + # return bool(self.UIASelectionPattern.CurrentCanSelectMultiple) + # except AttributeError: # UIASelectionPattern absent or None return False def script_find(self, gesture, reverse=False): @@ -1242,19 +1288,24 @@ def script_findPrevious(self, gesture): script_findPrevious.canPropagate = True script_findPrevious.__doc__ = CRList.script_findPrevious.__doc__ - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): # specific implementation curItem = self.searchFromItem curPos = curItem.positionInfo["indexInGroup"] listLen = curItem.positionInfo["similarItemsInGroup"] cl = UIAHandler.handler.clientObject classCond = cl.CreatePropertyCondition(UIAHandler.UIA_ClassNamePropertyId, "LeafRow") - scrollManager = self._getUIAPattern(UIAHandler.UIA_ScrollPatternId, UIAHandler.IUIAutomationScrollPattern) - verticalAmount = UIAHandler.ScrollAmount_LargeDecrement if reverse else UIAHandler.ScrollAmount_LargeIncrement + scrollManager = self._getUIAPattern( + UIAHandler.UIA_ScrollPatternId, + UIAHandler.IUIAutomationScrollPattern, + ) + verticalAmount = ( + UIAHandler.ScrollAmount_LargeDecrement if reverse else UIAHandler.ScrollAmount_LargeIncrement + ) while True: msgArr = self.UIAElement.FindAll(UIAHandler.TreeScope_Subtree, classCond) if reverse: - indexes = rangeFunc(msgArr.Length-1, -1, -1) + indexes = rangeFunc(msgArr.Length - 1, -1, -1) else: indexes = rangeFunc(0, msgArr.Length) for index in indexes: @@ -1262,10 +1313,8 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): itemPos = item.GetCurrentPropertyValue(UIAHandler.UIA_PositionInSetPropertyId) if (reverse and itemPos >= curPos) or (not reverse and itemPos <= curPos): continue - if ( - (not caseSensitive and text.lower() in item.CurrentName.lower()) - or - (caseSensitive and text in item.CurrentName) + if (not caseSensitive and text.lower() in item.CurrentName.lower()) or ( + caseSensitive and text in item.CurrentName ): return item if stopCheck(): @@ -1290,7 +1339,7 @@ def isEmptyList(self): try: childCount = self.UIAGridPattern.CurrentRowCount return not bool(childCount) - except: + except Exception: pass if self.childCount == 1 and self.firstChild.role == roles.PANE: # it's an empty list with header objs, so... @@ -1316,7 +1365,7 @@ def _getColumnHeader(self, index): # now, headers are not ordered as on screen, # but we deduce the order thanks to top location of each header headers.sort(key=lambda i: i.location) - return headers[index-1].name + return headers[index - 1].name def getFixedNum(self, num): return num @@ -1336,21 +1385,21 @@ def getSelectedItems(self): selCellArray, selCellNum = table.selectedCells for row in rangeFunc(0, selRowNum): # to scan cells of the row - rowRange = row*colNum + rowRange = row * colNum itemCells = [] for col in rangeFunc(0, colNum): - if rowRange+col >= selCellNum: + if rowRange + col >= selCellNum: # it should not happen, but if it is, # subscripting cells crashes NVDA, so... continue try: - cellText = selCellArray[rowRange+col].QueryInterface(IAccessible2).accName[0] + cellText = selCellArray[rowRange + col].QueryInterface(IAccessible2).accName[0] if cellText: itemCells.append(cellText) - except COMError: # unexplicable, but happens + except COMError: # unexplicable, but happens pass if itemCells: - item = ' '.join(itemCells)+";" + item = " ".join(itemCells) + ";" items.append(item) return items @@ -1385,16 +1434,14 @@ def script_findPrevious(self, gesture): script_findPrevious.canPropagate = True script_findPrevious.__doc__ = CRList.script_findPrevious.__doc__ - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs the search in item list, via NVDA object navigation (MozillaTable specific).""" index = self.curPos curItem = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, index) item = curItem.previous if reverse else curItem.next - while (item and item.role == curItem.role): - if ( - (not caseSensitive and item.name and text.lower() in item.name.lower()) - or - (caseSensitive and text in item.name) + while item and item.role == curItem.role: + if (not caseSensitive and item.name and text.lower() in item.name.lower()) or ( + caseSensitive and text in item.name ): resIndex = item.IAccessibleObject.uniqueID return resIndex @@ -1413,14 +1460,14 @@ def successSearchAction(self, resIndex): res.IAccessibleObject.accSelect(SELFLAG_ADDSELECTION, res.IAccessibleChildID) res.IAccessibleObject.accSelect(SELFLAG_TAKEFOCUS, res.IAccessibleChildID) else: - res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION, res.IAccessibleChildID) - res.IAccessibleObject.accSelect(SELFLAG_TAKEFOCUS, res.IAccessibleChildID) + res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION, res.IAccessibleChildID) + res.IAccessibleObject.accSelect(SELFLAG_TAKEFOCUS, res.IAccessibleChildID) def isEmptyList(self): try: if self.IAccessibleTable2Object.nRows == 0: return True - except: + except Exception: pass return False @@ -1444,7 +1491,7 @@ def _getColumnHeader(self, index): headerParent = self.getHeaderParent() if not headerParent: return None - headerObj = headerParent.getChild(index-1).firstChild + headerObj = headerParent.getChild(index - 1).firstChild return headerObj.name def getColumnData(self, colNumber): @@ -1453,7 +1500,7 @@ def getColumnData(self, colNumber): # list item as placed in first column if (1 != colNumber > curItem.childCount) or (curItem.role == self.role): raise noColumnAtIndex - cell = curItem.getChild(colNumber-1) + cell = curItem.getChild(colNumber - 1) # None obj should be generated # only in invisible column case if not cell: @@ -1492,52 +1539,53 @@ def script_reportCurrentSelection(self, gesture): def script_find(self, gesture, reverse=False): # not fully working for now ui.message(_("Cannot search here.")) -# self.curPos = api.getFocusObject().IAccessibleObject.uniqueID -# super(ThunderbirdSupernova, self).script_find(gesture, reverse) + + # self.curPos = api.getFocusObject().IAccessibleObject.uniqueID + # super(ThunderbirdSupernova, self).script_find(gesture, reverse) script_find.canPropagate = True script_find.__doc__ = CRList.script_find.__doc__ def script_findNext(self, gesture): ui.message(_("Cannot search here.")) -# self.curPos = api.getFocusObject().IAccessibleObject.uniqueID -# super(ThunderbirdSupernova, self).script_findNext(gesture) + + # self.curPos = api.getFocusObject().IAccessibleObject.uniqueID + # super(ThunderbirdSupernova, self).script_findNext(gesture) script_findNext.canPropagate = True script_findNext.__doc__ = CRList.script_findNext.__doc__ def script_findPrevious(self, gesture): ui.message(_("Cannot search here.")) -# self.curPos = api.getFocusObject().IAccessibleObject.uniqueID -# super(ThunderbirdSupernova, self).script_findPrevious(gesture) + + # self.curPos = api.getFocusObject().IAccessibleObject.uniqueID + # super(ThunderbirdSupernova, self).script_findPrevious(gesture) script_findPrevious.canPropagate = True script_findPrevious.__doc__ = CRList.script_findPrevious.__doc__ - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs the search in item list, via NVDA object navigation (ThunderbirdSupernova specific).""" index = self.curPos curItem = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, index) item = curItem.previous if reverse else curItem.next counter = -1 - while (item and item.role == curItem.role): + while item and item.role == curItem.role: counter += 1 - debugLog("Search on item %d"%counter) - if ( - (not caseSensitive and item.name and text.lower() in item.name.lower()) - or - (caseSensitive and text in item.name) + debugLog("Search on item %d" % counter) + if (not caseSensitive and item.name and text.lower() in item.name.lower()) or ( + caseSensitive and text in item.name ): resIndex = item.IAccessibleObject.uniqueID return resIndex newItem = item.previous if reverse else item.next if not newItem: - debugLog("Scrolled at %s"%item.name) -# from comInterfaces.IAccessible2Lib import IA2_SCROLL_TYPE_TOP_LEFT, IA2_SCROLL_TYPE_BOTTOM_RIGHT -# item.IAccessibleObject.scrollTo(IA2_SCROLL_TYPE_BOTTOM_RIGHT if reverse else IA2_SCROLL_TYPE_TOP_LEFT) + debugLog("Scrolled at %s" % item.name) + # from comInterfaces.IAccessible2Lib import IA2_SCROLL_TYPE_TOP_LEFT, IA2_SCROLL_TYPE_BOTTOM_RIGHT + # item.IAccessibleObject.scrollTo(IA2_SCROLL_TYPE_BOTTOM_RIGHT if reverse else IA2_SCROLL_TYPE_TOP_LEFT) self.getFocusMovingMouse(item) newItem = item.previous if reverse else item.next - debugLog("newItem: %s"%(newItem.name if newItem else None)) + debugLog("newItem: %s" % (newItem.name if newItem else None)) item = newItem if stopCheck(): break @@ -1567,6 +1615,7 @@ def getFocusMovingMouse(self, obj): if subjectChild: api.moveMouseToNVDAObject(subjectChild) import mouseHandler + mouseHandler.doPrimaryClick() def script_itemInfo(self, gesture): @@ -1582,7 +1631,9 @@ def script_itemInfo(self, gesture): # Translators: Reported when information about position on a list cannot be retrieved. ui.message(_("No information available")) else: - info = ' '.join([NVDALocale("item"), NVDALocale("{number} of {total}").format(number=number, total=total)]) + info = " ".join( + [NVDALocale("item"), NVDALocale("{number} of {total}").format(number=number, total=total)], + ) ui.message(info) script_itemInfo.canPropagate = True @@ -1597,7 +1648,6 @@ def script_itemInfo(self, gesture): class CRTreeview(CRList32): - # flag to guarantee thread support THREAD_SUPPORTED = False supportsEmptyListAnnouncements = True @@ -1611,8 +1661,8 @@ def getColumnData(self, colNumber): if (1 != colNumber > len(headers)) or (curItem.role == self.role): raise noColumnAtIndex try: - header = headers[colNumber-1].name - except: + header = headers[colNumber - 1].name + except Exception: header = None # too few cases, it's all a big try... try: @@ -1623,15 +1673,15 @@ def getColumnData(self, colNumber): nextHeader = "" else: nextHeader = headers[colNumber].name - content = curItem.description.split("%s: "%header, 1)[1].split(", %s: "%nextHeader, 1)[0] - except: + content = curItem.description.split("%s: " % header, 1)[1].split(", %s: " % nextHeader, 1)[0] + except Exception: content = None return {"columnContent": content, "columnHeader": header} def getHeaderParent(self): return self.simplePrevious - def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def findInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs search in item list, via object handles.""" # specific implementation fg = api.getForegroundObject() @@ -1646,40 +1696,34 @@ def findInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): # 1-based index curIndex = curItem.positionInfo["indexInGroup"] if reverse: - indexes = rangeFunc(curIndex-1,0,-1) + indexes = rangeFunc(curIndex - 1, 0, -1) else: - indexes = rangeFunc(curIndex+1,listLen+1) + indexes = rangeFunc(curIndex + 1, listLen + 1) for index in indexes: item = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, index) if not item or not item.name: continue if ( (not caseSensitive and text.lower() in item.name.lower()) - or - (not caseSensitive and text.lower() in item.description.lower()) - or - (caseSensitive and text in item.name) - or - (caseSensitive and text in item.description) + or (not caseSensitive and text.lower() in item.description.lower()) + or (caseSensitive and text in item.name) + or (caseSensitive and text in item.description) ): return item if stopCheck(): break - def genericFindInList(self, text, reverse, caseSensitive, stopCheck=lambda:False): + def genericFindInList(self, text, reverse, caseSensitive, stopCheck=lambda: False): """performs the search in treeview, via NVDA object navigation.""" # generic implementation curItem = self.searchFromItem item = curItem.previous if reverse else curItem.next - while (item and item.role == curItem.role): + while item and item.role == curItem.role: if ( (not caseSensitive and item.name and text.lower() in item.name.lower()) - or - (not caseSensitive and item.description and text.lower() in item.description.lower()) - or - (caseSensitive and text in item.name) - or - (caseSensitive and text in item.description) + or (not caseSensitive and item.description and text.lower() in item.description.lower()) + or (caseSensitive and text in item.name) + or (caseSensitive and text in item.description) ): return item item = item.previous if reverse else item.next @@ -1695,20 +1739,24 @@ def successSearchAction(self, res): resIndex = res.positionInfo["indexInGroup"] # sometime, due to list updates, items/indexes may differ if foundIndex != resIndex: - res = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, foundIndex+(foundIndex-resIndex)) + res = getNVDAObjectFromEvent( + self.windowHandle, + winUser.OBJID_CLIENT, + foundIndex + (foundIndex - resIndex), + ) if useMultipleSelection: res.IAccessibleObject.accSelect(SELFLAG_ADDSELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) else: - res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) + res.IAccessibleObject.accSelect(SELFLAG_TAKESELECTION | SELFLAG_TAKEFOCUS, res.IAccessibleChildID) def getSelectedItems(self): # generic (slow) implementation curItem = api.getFocusObject() items = [] item = self.firstChild - while (item and item.role == curItem.role): + while item and item.role == curItem.role: if states.SELECTED in item.states: - itemName = ' '.join([item.name, item.description]) + itemName = " ".join([item.name, item.description]) if itemName: items.append(itemName) item = item.next @@ -1717,14 +1765,13 @@ def getSelectedItems(self): def isEmptyList(self): try: childCount = self.childCount - except: + except Exception: # assume not empty childCount = 1 return not bool(childCount) class Finder(Thread): - STATUS_NOT_STARTED = 1 STATUS_RUNNING = 2 STATUS_COMPLETE = 3 diff --git a/addon/globalPlugins/columnsReview/actions.py b/addon/globalPlugins/columnsReview/actions.py index e26178c..da9f57c 100644 --- a/addon/globalPlugins/columnsReview/actions.py +++ b/addon/globalPlugins/columnsReview/actions.py @@ -53,8 +53,8 @@ def __call__(self, columnContent, columnHeader): if not columnHeader or config.conf["columnsReview"]["general"]["readHeader"] is False: columnHeader = "" else: - columnHeader = u"{}: ".format(columnHeader) - ui.message(u"{0}{1}".format(columnHeader, columnContent)) + columnHeader = "{}: ".format(columnHeader) + ui.message("{0}{1}".format(columnHeader, columnContent)) class CopyAction(Action): @@ -72,8 +72,8 @@ def __call__(self, columnContent, columnHeader): if not columnHeader or config.conf["columnsReview"]["general"]["copyHeader"] is False: columnHeader = "" else: - columnHeader = u"{}: ".format(columnHeader) - res = u"{0}{1}".format(columnHeader, columnContent) + columnHeader = "{}: ".format(columnHeader) + res = "{0}{1}".format(columnHeader, columnContent) if api.copyToClip(res): # Translators: message announcing what was copied ui.message(NVDALocale("Copied to clipboard: {text}").format(text=res)) @@ -110,7 +110,7 @@ def __call__(self, columnContent, columnHeader): ui.message(_("Empty column")) return if not columnHeader: - columnHeader = u"" + columnHeader = "" elif currentVersion < (2023, 3, 3): # code partially from Character Information add-on # for security advisory GHSA-xg6w-23rw-39r8. @@ -127,13 +127,7 @@ def __call__(self, columnContent, columnHeader): # List of actions in order in which they appear in the GUI # when implementing a new one please add it at the end. -ACTIONS = ( - NoAction(), - ReadAction(), - CopyAction(), - SpellAction(), - DisplayAction() -) +ACTIONS = (NoAction(), ReadAction(), CopyAction(), SpellAction(), DisplayAction()) def actionFromName(name): @@ -141,10 +135,7 @@ def actionFromName(name): if not matchingActions: raise RuntimeError("Action named %s does not exist" % (name)) if len(matchingActions) > 1: - raise RuntimeError( - "More than one action with such name exist." - "This is unexpected." - ) + raise RuntimeError("More than one action with such name exist.This is unexpected.") return matchingActions[0] diff --git a/addon/globalPlugins/columnsReview/blockUntilConditionMet.py b/addon/globalPlugins/columnsReview/blockUntilConditionMet.py index 37a5207..18a3c6b 100644 --- a/addon/globalPlugins/columnsReview/blockUntilConditionMet.py +++ b/addon/globalPlugins/columnsReview/blockUntilConditionMet.py @@ -30,13 +30,13 @@ def blockUntilConditionMet( - getValue: Callable[[], GetValueResultT], - giveUpAfterSeconds: float, - shouldStopEvaluator: Callable[[GetValueResultT], bool] = lambda value: bool(value), - intervalBetweenSeconds: float = DEFAULT_INTERVAL_BETWEEN_EVAL_SECONDS, - ) -> Tuple[ -EvaluatorWasMetT, # Was evaluator met? -Optional[GetValueResultT] # None or the value when the evaluator was met + getValue: Callable[[], GetValueResultT], + giveUpAfterSeconds: float, + shouldStopEvaluator: Callable[[GetValueResultT], bool] = lambda value: bool(value), + intervalBetweenSeconds: float = DEFAULT_INTERVAL_BETWEEN_EVAL_SECONDS, +) -> Tuple[ + EvaluatorWasMetT, # Was evaluator met? + Optional[GetValueResultT], # None or the value when the evaluator was met ]: """Repeatedly tries to get a value up until a time limit expires. Tries are separated by a time interval. diff --git a/addon/globalPlugins/columnsReview/commonFunc.py b/addon/globalPlugins/columnsReview/commonFunc.py index 2ca8a2d..deed833 100644 --- a/addon/globalPlugins/columnsReview/commonFunc.py +++ b/addon/globalPlugins/columnsReview/commonFunc.py @@ -1,7 +1,6 @@ # -*- coding: UTF-8 -*- # Utility functions for the Columns Review add-on -from .compat import CTWRAPPER import ctypes import winUser @@ -11,9 +10,12 @@ WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.wintypes.BOOL, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM) + + def findAllDescendantWindows(parent, visible=None, controlID=None, className=None): """See windowUtils.findDescendantWindow for parameters documentation.""" results = [] + @WNDENUMPROC def callback(window, data): if ( @@ -23,25 +25,31 @@ def callback(window, data): ): results.append(window) return True + # call previous func until it returns True, # thus always, getting all windows ctypes.windll.user32.EnumChildWindows(parent, callback, 0) # return all results return results + # to get NVDA script gestures, regardless its user remap def getScriptGestures(*args): from inputCore import manager + allGestures = manager.getAllGestureMappings() scriptDict = {} for scriptFunc in args: - scriptGestures = [] try: - scriptCategory = scriptFunc.category if hasattr(scriptFunc, "category") else scriptFunc.__self__.__class__.scriptCategory + scriptCategory = ( + scriptFunc.category + if hasattr(scriptFunc, "category") + else scriptFunc.__self__.__class__.scriptCategory + ) scriptDoc = scriptFunc.__doc__ script = allGestures[scriptCategory][scriptDoc] scriptDict[scriptFunc] = script.gestures - except: + except Exception: pass # try to avoid garbageHandler warnings del allGestures diff --git a/addon/globalPlugins/columnsReview/compat.py b/addon/globalPlugins/columnsReview/compat.py index ce4a86d..bcfd11e 100644 --- a/addon/globalPlugins/columnsReview/compat.py +++ b/addon/globalPlugins/columnsReview/compat.py @@ -2,6 +2,7 @@ # Provides various stuff used to preserve compatibility with older releases of NVDA. import controlTypes + try: from buildVersion import version_year, version_major, version_minor except ImportError: @@ -16,7 +17,6 @@ class EnhancedGetter(object): - def __init__(self, modWithAttrs, baseAttrName, gettersToTry): super(EnhancedGetter, self).__init__() self.mod = modWithAttrs @@ -33,7 +33,6 @@ def __getattr__(self, attrName): class ControlTypesCompatWrapper(object): - def __init__(self): super(ControlTypesCompatWrapper, self).__init__() self.Role = EnhancedGetter( @@ -42,7 +41,7 @@ def __init__(self): [ lambda mod, bName, name: getattr(mod, "{0}_{1}".format(bName.upper(), name)), lambda mod, bName, name: getattr(getattr(mod, bName), name), - ] + ], ) self.State = EnhancedGetter( controlTypes, @@ -50,7 +49,7 @@ def __init__(self): [ lambda mod, bName, name: getattr(mod, "{0}_{1}".format(bName.upper(), name)), lambda mod, bName, name: getattr(getattr(mod, bName), name), - ] + ], ) @@ -60,11 +59,12 @@ def __init__(self): def rangeFunc(*args, **kwargs): try: import six + return six.moves.range(*args, **kwargs) except ImportError: try: import __builtin__ + return __builtin__.xrange(*args, **kwargs) except ImportError: return range(*args, **kwargs) - diff --git a/addon/globalPlugins/columnsReview/configManager.py b/addon/globalPlugins/columnsReview/configManager.py index e3bc5b0..737e693 100644 --- a/addon/globalPlugins/columnsReview/configManager.py +++ b/addon/globalPlugins/columnsReview/configManager.py @@ -1,5 +1,6 @@ # -*- coding: UTF-8 -*- import config + try: from configobj.validate import is_boolean except ImportError: @@ -7,7 +8,6 @@ class ConfigFromObject(object): - def __init__(self, obj): self.obj = obj try: @@ -35,11 +35,15 @@ def getApplicableProfiles(self): if getattr(config.conf._profileCache[profileName], "manual", False): res.append(config.conf._profileCache[config.conf.profiles[-1].name]) try: - res.append(config.conf._profileCache[config.conf.triggersToProfiles[self.possibleTriggerName]]) + res.append( + config.conf._profileCache[config.conf.triggersToProfiles[self.possibleTriggerName]], + ) except KeyError: try: config.conf._getProfile(config.conf.triggersToProfiles[self.possibleTriggerName]) - res.append(config.conf._profileCache[config.conf.triggersToProfiles[self.possibleTriggerName]]) + res.append( + config.conf._profileCache[config.conf.triggersToProfiles[self.possibleTriggerName]], + ) except KeyError: pass res.append(config.conf._profileCache[None]) # Default config diff --git a/addon/globalPlugins/columnsReview/configSpec.py b/addon/globalPlugins/columnsReview/configSpec.py index d191d5e..4d897ca 100644 --- a/addon/globalPlugins/columnsReview/configSpec.py +++ b/addon/globalPlugins/columnsReview/configSpec.py @@ -6,9 +6,9 @@ except ModuleNotFoundError: # Python 3 from io import StringIO from configobj import ConfigObj -from . actions import ACTIONS +from .actions import ACTIONS -configSpecString = (""" +configSpecString = """ [general] readHeader = boolean(default=True) copyHeader = boolean(default=True) @@ -33,6 +33,6 @@ press2 = option({actionNames} default="copy") press3 = option({actionNames} default="noAction") press4 = option({actionNames} default="noAction") -""".format(actionNames=''.join('"{}", '.format(action.name) for action in ACTIONS)[:-1])) +""".format(actionNames="".join('"{}", '.format(action.name) for action in ACTIONS)[:-1]) confspec = ConfigObj(StringIO(configSpecString), list_values=False, encoding="UTF-8") confspec.newlines = "\r\n" diff --git a/addon/globalPlugins/columnsReview/dialogs.py b/addon/globalPlugins/columnsReview/dialogs.py index f3df135..7f2a3b2 100644 --- a/addon/globalPlugins/columnsReview/dialogs.py +++ b/addon/globalPlugins/columnsReview/dialogs.py @@ -18,14 +18,13 @@ class configureActionPanel(wx.Panel): - COPY_ACTION_INDEX = getActionIndexFromName("copy") READ_ACTION_INDEX = getActionIndexFromName("read") try: HIDE_NEXT_PANELS_AFTER = ACTIONS.index( - [action for action in ACTIONS if action.showLaterActions is False][0] + [action for action in ACTIONS if action.showLaterActions is False][0], ) - except(IndexError, ValueError): + except (IndexError, ValueError): HIDE_NEXT_PANELS_AFTER = None ON_PRESS_LABELS = { @@ -36,7 +35,7 @@ class configureActionPanel(wx.Panel): # Translators: Label of a combobox in which action can be assigned to a third press of the shortcut. 3: _("On third press:"), # Translators: Label of a combobox in which action can be assigned to a fourth press of the shortcut. - 4: _("On fourth press:") + 4: _("On fourth press:"), } TRANSLATED_ACTION_NAMES = tuple(action.translatedName for action in ACTIONS) @@ -48,7 +47,7 @@ def __init__(self, parent, panelNumber, initialSelection): self.chooseActionCombo = sizer.addLabeledControl( self.ON_PRESS_LABELS[self.panelNumber], wx.Choice, - choices=self.TRANSLATED_ACTION_NAMES + choices=self.TRANSLATED_ACTION_NAMES, ) self.chooseActionCombo.SetSelection(initialSelection) self.chooseActionCombo.Bind(wx.EVT_CHOICE, self.onSelectedActionChange) @@ -77,10 +76,10 @@ def onSelectedActionChange(self, evt): for panel in self.Parent.panels: panel.setControlsVisibility() if evt.GetSelection() == self.HIDE_NEXT_PANELS_AFTER: - for panel in self.Parent.panels[self.panelNumber:]: + for panel in self.Parent.panels[self.panelNumber :]: panel.Disable() else: - for panel in self.Parent.panels[self.panelNumber:]: + for panel in self.Parent.panels[self.panelNumber :]: panel.Enable() if panel.chooseActionCombo.GetSelection() == self.HIDE_NEXT_PANELS_AFTER: break @@ -96,8 +95,7 @@ def setControlsVisibility(self): self.Parent.readCheckboxEnabled = True self.readHeader.Enable() shouldDisableReadHeaderChk = ( - self.chooseActionCombo.GetSelection() != self.READ_ACTION_INDEX - and self.readHeader.IsEnabled() + self.chooseActionCombo.GetSelection() != self.READ_ACTION_INDEX and self.readHeader.IsEnabled() ) if shouldDisableReadHeaderChk: self.readHeader.Disable() @@ -110,8 +108,7 @@ def setControlsVisibility(self): self.Parent.copyCheckboxEnabled = True self.copyHeader.Enable() shouldDisableCopyHeaderChk = ( - self.chooseActionCombo.GetSelection() != self.COPY_ACTION_INDEX - and self.copyHeader.IsEnabled() + self.chooseActionCombo.GetSelection() != self.COPY_ACTION_INDEX and self.copyHeader.IsEnabled() ) if shouldDisableCopyHeaderChk: self.copyHeader.Disable() @@ -130,9 +127,9 @@ def makeSettings(self, settingsSizer): wx.StaticBox( self, # Translators: Help message for group of comboboxes allowing to assign action to a keypress. - label=_("When pressing combination to read column:") + label=_("When pressing combination to read column:"), ), - wx.VERTICAL + wx.VERTICAL, ) for pressNumber, actionName in configuredActions().items(): actionIndex = getActionIndexFromName(actionName) @@ -148,9 +145,9 @@ def makeSettings(self, settingsSizer): wx.StaticBox( self, # Translators: Help message for sub-sizer of keys choices - label=_("Choose the keys you want to use with numbers:") + label=_("Choose the keys you want to use with numbers:"), ), - wx.VERTICAL + wx.VERTICAL, ) self.keysChks = [] gesturesSect = config.conf["columnsReview"]["gestures"] @@ -169,7 +166,7 @@ def makeSettings(self, settingsSizer): self._switchCharLabel = wx.StaticText( self, # Translators: label for edit field in settings, visible if previous checkbox is disabled - label=_("Insert the char after \"0\" in your keyboard layout, or another char as you like:") + label=_('Insert the char after "0" in your keyboard layout, or another char as you like:'), ) settingsSizer.Add(self._switchCharLabel) self._switchChar = wx.TextCtrl(self, name="switchCharTextCtrl") @@ -180,14 +177,16 @@ def makeSettings(self, settingsSizer): settingsSizer.Hide(self._switchCharLabel) settingsSizer.Hide(self._switchChar) self._announceEmptyList = wx.CheckBox( + self, # Translators: label for announce-empty-list checkbox in settings - self, label=_("Announce empty list") + label=_("Announce empty list"), ) self._announceEmptyList.SetValue(config.conf["columnsReview"]["general"]["announceEmptyList"]) settingsSizer.Add(self._announceEmptyList) self._announceListBounds = wx.CheckBox( + self, # Translators: label for announce-list-bounds checkbox in settings - self, label=_("Announce list bounds (top, mono-item, bottom)") + label=_("Announce list bounds (top, mono-item, bottom)"), ) self._announceListBounds.SetValue(config.conf["columnsReview"]["general"]["announceListBounds"]) self._announceListBounds.Bind(wx.EVT_CHECKBOX, self.onCheck) @@ -199,30 +198,31 @@ def makeSettings(self, settingsSizer): _("beep"), ] self._announceListBoundsWith = wx.RadioBox( + self, # Translators: label for announce-list-bounds-with radio box in settings - self, label=_("Announce with:"), choices=voiceOrBeep + label=_("Announce with:"), + choices=voiceOrBeep, + ) + self._announceListBoundsWith.SetSelection( + 0 if config.conf["columnsReview"]["general"]["announceListBoundsWith"] == "voice" else 1, ) - self._announceListBoundsWith.SetSelection(0 if config.conf["columnsReview"]["general"]["announceListBoundsWith"] == "voice" else 1) self._announceListBoundsWith.Bind(wx.EVT_RADIOBOX, self.onRadioCheck) settingsSizer.Add(self._announceListBoundsWith) - # Translators: a tooltip on beep values input box - self._beepInstructions=_("Please input a frequency for top beep, a frequency for bottom beep, and their duration in milliseconds (each of three values must be a positive number, separated by comma):") - self._beepSizer = wx.StaticBoxSizer( - wx.StaticBox(self, label=self._beepInstructions), - wx.HORIZONTAL - ) - beepValues = ', '.join([str(x) for x in config.conf["columnsReview"]["beep"].dict().values()]) - self._beepValues = wx.TextCtrl( - self, value=beepValues, name=_("Beep values") + self._beepInstructions = _( + # Translators: a tooltip on beep values input box + "Please input a frequency for top beep, a frequency for bottom beep, and their duration in milliseconds (each of three values must be a positive number, separated by comma):", ) + self._beepSizer = wx.StaticBoxSizer(wx.StaticBox(self, label=self._beepInstructions), wx.HORIZONTAL) + beepValues = ", ".join([str(x) for x in config.conf["columnsReview"]["beep"].dict().values()]) + self._beepValues = wx.TextCtrl(self, value=beepValues, name=_("Beep values")) self._beepValues.Bind(wx.EVT_KILL_FOCUS, self.evaluateBeepValues) self._beepSizer.Add(self._beepValues) settingsSizer.Add(self._beepSizer) if not self._announceListBounds.IsChecked(): settingsSizer.Hide(self._announceListBoundsWith) - settingsSizer.Hide(self._beepSizer) #self._beepValues) + settingsSizer.Hide(self._beepSizer) # self._beepValues) if self._announceListBoundsWith.GetSelection() != 1: - settingsSizer.Hide(self._beepSizer) #self._beepValues) + settingsSizer.Hide(self._beepSizer) # self._beepValues) def saveConfig(self): # Update Configuration @@ -269,20 +269,20 @@ def onCheck(self, evt): self.settingsSizer.Show(self._switchChar) if not self._announceListBounds.IsChecked(): self.settingsSizer.Hide(self._announceListBoundsWith) - self.settingsSizer.Hide(self._beepSizer) #self._beepValues) + self.settingsSizer.Hide(self._beepSizer) # self._beepValues) else: self.settingsSizer.Show(self._announceListBoundsWith) if self._announceListBoundsWith.GetSelection() != 1: - self.settingsSizer.Hide(self._beepSizer) #self._beepValues) + self.settingsSizer.Hide(self._beepSizer) # self._beepValues) else: - self.settingsSizer.Show(self._beepSizer) #self._beepValues) + self.settingsSizer.Show(self._beepSizer) # self._beepValues) self.Fit() def onRadioCheck(self, evt): if self._announceListBoundsWith.GetSelection() == 1: - self.settingsSizer.Show(self._beepSizer) #self._beepValues) + self.settingsSizer.Show(self._beepSizer) # self._beepValues) else: - self.settingsSizer.Hide(self._beepSizer) #self._beepValues) + self.settingsSizer.Hide(self._beepSizer) # self._beepValues) def evaluateBeepValues(self, evt): try: @@ -290,9 +290,10 @@ def evaluateBeepValues(self, evt): topBeep, bottomBeep, beepLen = self.getBeepValues(text) from tones import beep from time import sleep + beep(topBeep, beepLen) sleep(0.3) - beep(abs(topBeep-bottomBeep), beepLen*2) + beep(abs(topBeep - bottomBeep), beepLen * 2) sleep(0.3) beep(bottomBeep, beepLen) except (ValueError, IndexError): @@ -301,7 +302,7 @@ def evaluateBeepValues(self, evt): _("Please input valid values for beep."), # Translators: Title of the dialog when user inputs wrong values for beep _("Error!"), - wx.OK | wx.ICON_ERROR + wx.OK | wx.ICON_ERROR, ) self._beepValues.SetFocus() @@ -314,12 +315,13 @@ def getBeepValues(self, text): raise ValueError return values + class HeaderDialog(wx.Dialog): """define dialog for column headers management.""" def __init__(self, title, headerList): # Translators: Title of the dialog which allows to perform actions on headers of the current list. - super(HeaderDialog, self).__init__(None, title=' - '.join([_("Headers manager"), title])) + super(HeaderDialog, self).__init__(None, title=" - ".join([_("Headers manager"), title])) helperSizer = BoxSizerHelper(self, wx.HORIZONTAL) # Translators: Shown for a header which has no name. choices = [x.name if x.name else _("Unnamed header") for x in headerList] diff --git a/addon/globalPlugins/columnsReview/exceptions.py b/addon/globalPlugins/columnsReview/exceptions.py index 5c59810..04def4a 100644 --- a/addon/globalPlugins/columnsReview/exceptions.py +++ b/addon/globalPlugins/columnsReview/exceptions.py @@ -4,9 +4,11 @@ class noColumnAtIndex(Exception): """Raised when column at the specified index does not exist.""" + pass class columnAtIndexNotVisible(Exception): """Raised when column at the requested index exists, but is not visible.""" + pass diff --git a/addon/globalPlugins/columnsReview/utils.py b/addon/globalPlugins/columnsReview/utils.py index 0f5bef7..7b24c9e 100644 --- a/addon/globalPlugins/columnsReview/utils.py +++ b/addon/globalPlugins/columnsReview/utils.py @@ -14,7 +14,6 @@ def getRowsReaderSuperClass(): class _RowsReader(getRowsReaderSuperClass()): - def walk(self, obj): yield obj nextObj = obj.next @@ -25,12 +24,15 @@ def walk(self, obj): @classmethod def readRows(cls, obj): import weakref + try: import sayAllHandler + reader = cls(obj) sayAllHandler._activeSayAll = weakref.ref(reader) except ImportError: import speech.sayAll + reader = cls(speech.sayAll.SayAllHandler, obj) speech.sayAll.SayAllHandler._getActiveSayAll = weakref.ref(reader) reader.next() diff --git a/addon/installTasks.py b/addon/installTasks.py index babedd7..b5b5abc 100644 --- a/addon/installTasks.py +++ b/addon/installTasks.py @@ -1,33 +1,48 @@ import addonHandler import os import sys + py3 = sys.version.startswith("3") addonHandler.initTranslation() + def onInstall(): import gui import wx + for addon in addonHandler.getAvailableAddons(): if addon.name == "columnsReview": addonPath = addon.path if py3 else addon.path.encode("mbcs") iniFile = os.path.join(addonPath, "globalPlugins", "settings.ini") if os.path.isfile(iniFile): gui.messageBox( - # Translators: the label of a message box dialog. - _("Previous add-on settings will be lost. Please configure it again, from NVDA preferences."), + _( + # Translators: the label of a message box dialog. + "Previous add-on settings will be lost. Please configure it again, from NVDA preferences.", + ), # Translators: the title of a message box dialog. _("Add-on settings reset"), - wx.OK|wx.ICON_WARNING) + wx.OK | wx.ICON_WARNING, + ) try: os.remove(iniFile) - except: + except Exception: pass elif addon.name == "ExplorerEnhancements": - if gui.messageBox( - # Translators: the label of a message box dialog to uninstall another add-on - _("You have installed {another_addon} by {another_author}, that causes problems with empty folder feature of ColumnsReview (if enabled); do you want to remove it now?").format(another_addon=addon.manifest["summary"], another_author=addon.manifest["author"]), - # Translators: the title of a message box dialog. - _("Warning!"), - wx.YES|wx.NO|wx.ICON_WARNING) == wx.YES: + if ( + gui.messageBox( + _( + # Translators: the label of a message box dialog to uninstall another add-on + "You have installed {another_addon} by {another_author}, that causes problems with empty folder feature of ColumnsReview (if enabled); do you want to remove it now?", + ).format( + another_addon=addon.manifest["summary"], + another_author=addon.manifest["author"], + ), + # Translators: the title of a message box dialog. + _("Warning!"), + wx.YES | wx.NO | wx.ICON_WARNING, + ) + == wx.YES + ): addon.requestRemove() diff --git a/readme.md b/readme.md index d866d7c..2540159 100644 --- a/readme.md +++ b/readme.md @@ -53,4 +53,3 @@ Following list types are supported: * Outlook messages table (but list search is not recommended in thread view). [rss]: https://github.com/ABuffEr/rssowlnixSupport - diff --git a/sconstruct b/sconstruct index cdbad3f..e62cbea 100644 --- a/sconstruct +++ b/sconstruct @@ -42,7 +42,7 @@ def validateVersionNumber(key: str, val: str, _): def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: - return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip('/'))] + return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip("/"))] addonDir: Final = Path("addon/") @@ -67,7 +67,7 @@ env.Append( if env["dev"]: from datetime import date - versionTimestamp = date.today().strftime('%Y%m%d') + versionTimestamp = date.today().strftime("%Y%m%d") version = f"{versionTimestamp}.0.0" env["addon_info"]["addon_version"] = version env["versionNumber"] = version @@ -84,7 +84,7 @@ env.Append(**env["addon_info"]) addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) -langDirs: list[FS.Dir] = [env.Dir(d) for d in env.Glob(localeDir/"*/") if d.isdir()] +langDirs: list[FS.Dir] = [env.Dir(d) for d in env.Glob(localeDir / "*/") if d.isdir()] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated moByLang: dict[str, FS.File] = {} @@ -116,7 +116,7 @@ if (readmeFile := Path("readme.md")).is_file(): readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) -for mdFile in env.Glob(docsDir/"*/*.md"): +for mdFile in env.Glob(docsDir / "*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. lang = mdFile.dir.name @@ -143,7 +143,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl") +manifest = env.NVDAManifest(env.File(addonDir / "manifest.ini"), "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index a71857d..7de9357 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -34,12 +34,14 @@ def generate(env: Environment): env.SetDefault(excludePatterns=tuple()) addonAction = env.Action( - lambda target, source, env: createAddonBundleFromPath( - source[0].abspath, - target[0].abspath, - env["excludePatterns"], - ) - and None, + lambda target, source, env: ( + createAddonBundleFromPath( + source[0].abspath, + target[0].abspath, + env["excludePatterns"], + ) + and None + ), lambda target, source, env: f"Generating Addon {target[0]}", ) env["BUILDERS"]["NVDAAddon"] = Builder( @@ -53,15 +55,17 @@ def generate(env: Environment): env.SetDefault(speechDictionaries={}) manifestAction = env.Action( - lambda target, source, env: generateManifest( - source[0].abspath, - target[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - speechDictionaries=env["speechDictionaries"], - ) - and None, + lambda target, source, env: ( + generateManifest( + source[0].abspath, + target[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], + ) + and None + ), lambda target, source, env: f"Generating manifest {target[0]}", ) env["BUILDERS"]["NVDAManifest"] = Builder( @@ -71,16 +75,18 @@ def generate(env: Environment): ) translatedManifestAction = env.Action( - lambda target, source, env: generateTranslatedManifest( - source[1].abspath, - target[0].abspath, - mo=source[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - speechDictionaries=env["speechDictionaries"], - ) - and None, + lambda target, source, env: ( + generateTranslatedManifest( + source[1].abspath, + target[0].abspath, + mo=source[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], + ) + and None + ), lambda target, source, env: f"Generating translated manifest {target[0]}", ) @@ -93,14 +99,16 @@ def generate(env: Environment): env.SetDefault(mdExtensions={}) mdAction = env.Action( - lambda target, source, env: md2html( - source[0].path, - target[0].path, - moFile=env["moFile"].path if env["moFile"] else None, - mdExtensions=env["mdExtensions"], - addon_info=env["addon_info"], - ) - and None, + lambda target, source, env: ( + md2html( + source[0].path, + target[0].path, + moFile=env["moFile"].path if env["moFile"] else None, + mdExtensions=env["mdExtensions"], + addon_info=env["addon_info"], + ) + and None + ), lambda target, source, env: f"Generating {target[0]}", ) env["BUILDERS"]["md2html"] = env.Builder(