diff --git a/source/NVDAObjects/IAccessible/MSHTML.py b/source/NVDAObjects/IAccessible/MSHTML.py index dd71569cde3..b98c745fdfa 100644 --- a/source/NVDAObjects/IAccessible/MSHTML.py +++ b/source/NVDAObjects/IAccessible/MSHTML.py @@ -670,7 +670,7 @@ def _get_name(self): title=self.HTMLAttributes['title'] # #2121: MSHTML sometimes returns a node for the title attribute. # This doesn't make any sense, so ignore it. - if title and isinstance(title,basestring): + if title and isinstance(title,str): return title return "" return super(MSHTML,self).name diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index ef55eb865a8..d4b095921e9 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -326,7 +326,7 @@ def _iterTextWithEmbeddedObjects(self, withFields, formatConfig=None): items = [self.text] offset = self._startOffset for item in items: - if not isinstance(item, basestring): + if not isinstance(item, str): # This is a field. yield item continue @@ -741,14 +741,14 @@ def _get_name(self): res=self.IAccessibleObject.accName(self.IAccessibleChildID) except COMError: res=None - return res if isinstance(res,basestring) and not res.isspace() else None + return res if isinstance(res,str) and not res.isspace() else None def _get_value(self): try: res=self.IAccessibleObject.accValue(self.IAccessibleChildID) except COMError: res=None - return res if isinstance(res,basestring) and not res.isspace() else None + return res if isinstance(res,str) and not res.isspace() else None def _get_actionCount(self): if hasattr(self,'IAccessibleActionObject'): @@ -824,7 +824,7 @@ def _get_role(self): superRole=super(IAccessible,self).role if superRole!=controlTypes.ROLE_WINDOW: return superRole - if isinstance(IARole,basestring): + if isinstance(IARole,str): IARole=IARole.split(',')[0].lower() log.debug("IARole: %s"%IARole) return IAccessibleHandler.IAccessibleRolesToNVDARoles.get(IARole,controlTypes.ROLE_UNKNOWN) @@ -904,7 +904,7 @@ def _get_decodedAccDescription(self): def _get_description(self): if self.hasEncodedAccDescription: d=self.decodedAccDescription - if isinstance(d,basestring): + if isinstance(d,str): return d else: return "" @@ -912,14 +912,14 @@ def _get_description(self): res=self.IAccessibleObject.accDescription(self.IAccessibleChildID) except COMError: res=None - return res if isinstance(res,basestring) and not res.isspace() else None + return res if isinstance(res,str) and not res.isspace() else None def _get_keyboardShortcut(self): try: res=self.IAccessibleObject.accKeyboardShortcut(self.IAccessibleChildID) except COMError: res=None - return res if isinstance(res,basestring) and not res.isspace() else None + return res if isinstance(res,str) and not res.isspace() else None def _get_childCount(self): if self.IAccessibleChildID!=0: @@ -1379,7 +1379,7 @@ def _get_positionInfo(self): pass if self.hasEncodedAccDescription: d=self.decodedAccDescription - if d and not isinstance(d,basestring): + if d and not isinstance(d,str): groupdict=d.groupdict() return {x:int(y) for x,y in groupdict.items() if y is not None} if self.allowIAccessibleChildIDAndChildCountForPositionInfo and self.IAccessibleChildID>0: diff --git a/source/NVDAObjects/IAccessible/ia2TextMozilla.py b/source/NVDAObjects/IAccessible/ia2TextMozilla.py index 77ab540ae9c..015f31c229b 100644 --- a/source/NVDAObjects/IAccessible/ia2TextMozilla.py +++ b/source/NVDAObjects/IAccessible/ia2TextMozilla.py @@ -232,7 +232,7 @@ def _iterRecursiveText(self, ti, controlStack, formatConfig): for item in ti._iterTextWithEmbeddedObjects(controlStack is not None, formatConfig=formatConfig): if item is None: yield u"" - elif isinstance(item, basestring): + elif isinstance(item, str): yield item elif isinstance(item, int): # Embedded object. embedded = _getEmbedded(ti.obj, item) diff --git a/source/NVDAObjects/IAccessible/mozilla.py b/source/NVDAObjects/IAccessible/mozilla.py index 690a2c75cc9..55f899f75db 100755 --- a/source/NVDAObjects/IAccessible/mozilla.py +++ b/source/NVDAObjects/IAccessible/mozilla.py @@ -88,7 +88,7 @@ class Gecko1_9(Mozilla): def _get_description(self): rawDescription=super(Mozilla,self).description - if isinstance(rawDescription,basestring) and rawDescription.startswith('Description: '): + if isinstance(rawDescription,str) and rawDescription.startswith('Description: '): return rawDescription[13:] else: return "" diff --git a/source/NVDAObjects/IAccessible/winword.py b/source/NVDAObjects/IAccessible/winword.py index 02810f0876b..4c81ee81fe2 100644 --- a/source/NVDAObjects/IAccessible/winword.py +++ b/source/NVDAObjects/IAccessible/winword.py @@ -410,7 +410,7 @@ def _get_errorText(self): inBold=False textList=[] for field in fields: - if isinstance(field,basestring): + if isinstance(field,str): if inBold: textList.append(field) elif field.field: inBold=field.field.get('bold',False) diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py index 990eff87756..6df923c9536 100644 --- a/source/NVDAObjects/UIA/edge.py +++ b/source/NVDAObjects/UIA/edge.py @@ -202,7 +202,7 @@ def getTextWithFields(self,formatConfig=None): index=0 while index1 and isinstance(field,basestring) and field.isspace(): + if index>1 and isinstance(field,str) and field.isspace(): prevField=fields[index-2] if isinstance(prevField,textInfos.FieldCommand) and prevField.command=="controlEnd": del fields[index-1:index+1] @@ -214,7 +214,7 @@ def getTextWithFields(self,formatConfig=None): numFields=len(fields) for index in range(numFields-1,-1,-1): field=fields[index] - if isinstance(field,basestring): + if isinstance(field,str): break elif isinstance(field,textInfos.FieldCommand) and field.command=="controlStart" and not field.field.get('embedded'): startCount+=1 diff --git a/source/NVDAObjects/UIA/wordDocument.py b/source/NVDAObjects/UIA/wordDocument.py index ee2926b75f8..5bbddc6fb74 100644 --- a/source/NVDAObjects/UIA/wordDocument.py +++ b/source/NVDAObjects/UIA/wordDocument.py @@ -212,7 +212,7 @@ def getTextWithFields(self,formatConfig=None): elif isinstance(field,textInfos.FieldCommand) and field.command=="formatChange": # This is the most recent formatField we have seen. lastFormatField=field.field - elif listItemStarted and isinstance(field,basestring): + elif listItemStarted and isinstance(field,str): # This is the first text string within the list. # Remove the text up to the first space, and store it as line-prefix which NVDA will appropriately speak/braille as a bullet. try: diff --git a/source/NVDAObjects/__init__.py b/source/NVDAObjects/__init__.py index e2a454380c3..4518d60b30a 100644 --- a/source/NVDAObjects/__init__.py +++ b/source/NVDAObjects/__init__.py @@ -387,7 +387,7 @@ def _get_appModule(self): def _get_name(self): """The name or label of this object (example: the text of a button). - @rtype: basestring + @rtype: str """ return "" @@ -408,13 +408,13 @@ def _get_roleText(self): def _get_value(self): """The value of this object (example: the current percentage of a scrollbar, the selected option in a combo box). - @rtype: basestring + @rtype: str """ return "" def _get_description(self): """The description or help text of this object. - @rtype: basestring + @rtype: str """ return "" @@ -432,7 +432,7 @@ def getActionName(self,index=None): @param index: the optional 0-based index of the wanted action. @type index: int @return: the action's name - @rtype: basestring + @rtype: str """ raise NotImplementedError @@ -448,7 +448,7 @@ def _get_defaultActionIndex(self): def _get_keyboardShortcut(self): """The shortcut key that activates this object(example: alt+t). - @rtype: basestring + @rtype: str """ return "" @@ -1098,7 +1098,7 @@ def _get_basicText(self): newTime=time.time() oldTime=getattr(self,'_basicTextTime',0) if newTime-oldTime>0.5: - self._basicText=u" ".join(x for x in (self.name, self.value, self.description) if isinstance(x, basestring) and len(x) > 0 and not x.isspace()) + self._basicText=u" ".join(x for x in (self.name, self.value, self.description) if isinstance(x, str) and len(x) > 0 and not x.isspace()) if len(self._basicText)==0: self._basicText=u"" else: @@ -1120,13 +1120,13 @@ def _formatLongDevInfoString(string, truncateLen=250): If the string is too long to be useful, it will be truncated. This string should be included as returned. There is no need to call repr. @param string: The string to format. - @type string: nbasestring + @type string: str @param truncateLen: The length at which to truncate the string. @type truncateLen: int @return: The formatted string. - @rtype: basestring + @rtype: str """ - if isinstance(string, basestring) and len(string) > truncateLen: + if isinstance(string, str) and len(string) > truncateLen: return "%r (truncated)" % string[:truncateLen] return repr(string) @@ -1238,7 +1238,7 @@ def _get_mathMl(self): raise NotImplementedError #: The language/locale of this object. - #: @type: basestring + #: @type: str language = None def _get__hasNavigableText(self): diff --git a/source/NVDAObjects/window/edit.py b/source/NVDAObjects/window/edit.py index 17d98443d62..7de6a696d9a 100644 --- a/source/NVDAObjects/window/edit.py +++ b/source/NVDAObjects/window/edit.py @@ -372,7 +372,8 @@ def _getTextRange(self,start,end): if self.obj.isWindowUnicode or (res>1 and (buf[res]!=0 or buf[res+1]!=0)): text=ctypes.cast(buf,ctypes.c_wchar_p).value else: - text=unicode(ctypes.cast(buf,ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1]) + encoding=locale.getlocale()[1] + text=ctypes.cast(buf,ctypes.c_char_p).value.decode(encoding,errors="replace") # #4095: Some protected richEdit controls do not hide their password characters. # We do this specifically. # Note that protected standard edit controls get characters hidden in _getStoryText. diff --git a/source/NVDAObjects/window/excel.py b/source/NVDAObjects/window/excel.py index 8d6b317dd75..87ea5eadb5d 100755 --- a/source/NVDAObjects/window/excel.py +++ b/source/NVDAObjects/window/excel.py @@ -1538,7 +1538,7 @@ def _get_children(self): background=item.field.get('background-color',None) if (background,foreground)==self._highlightColors: states.add(controlTypes.STATE_SELECTED) - if isinstance(item,basestring): + if isinstance(item,str): obj=ExcelDropdownItem(parent=self,name=item,states=states,index=index) children.append(obj) index+=1 diff --git a/source/NVDAObjects/window/scintilla.py b/source/NVDAObjects/window/scintilla.py index 8527d03f1e0..fc6741f2ce2 100755 --- a/source/NVDAObjects/window/scintilla.py +++ b/source/NVDAObjects/window/scintilla.py @@ -176,9 +176,10 @@ def _getTextRange(self,start,end): winKernel.virtualFreeEx(processHandle,internalBuf,0,winKernel.MEM_RELEASE) cp=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_GETCODEPAGE,0,0) if cp==SC_CP_UTF8: - return unicode(buf.value, errors="replace", encoding="utf-8") + encoding="utf-8" else: - return unicode(buf.value, errors="replace", encoding=locale.getlocale()[1]) + encoding=locale.getlocale()[1] + return buf.value.decode(encoding,errors="replace") def _getWordOffsets(self,offset): start=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDSTARTPOSITION,offset,0) diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index dfbb07770b8..0b43944728e 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -721,7 +721,7 @@ def getTextWithFields(self,formatConfig=None): item.field=self._normalizeControlField(field) elif isinstance(field,textInfos.FormatField): item.field=self._normalizeFormatField(field,extraDetail=extraDetail) - elif index>0 and isinstance(item,basestring) and item.isspace(): + elif index>0 and isinstance(item,str) and item.isspace(): #2047: don't expose language for whitespace as its incorrect for east-asian languages lastItem=commandList[index-1] if isinstance(lastItem,textInfos.FieldCommand) and isinstance(lastItem.field,textInfos.FormatField): diff --git a/source/XMLFormatting.py b/source/XMLFormatting.py index af294b53170..a27a4c5a823 100755 --- a/source/XMLFormatting.py +++ b/source/XMLFormatting.py @@ -16,7 +16,7 @@ def _startElementHandler(self,tagName,attrs): data=attrs.get('value',None) if data is not None: try: - data=unichr(int(data)) + data=chr(int(data)) except ValueError: data=u'\ufffd' self._CharacterDataHandler(data) @@ -50,7 +50,7 @@ def _EndElementHandler(self,tagName): def _CharacterDataHandler(self,data): cmdList=self._commandList - if cmdList and isinstance(cmdList[-1],basestring): + if cmdList and isinstance(cmdList[-1],str): cmdList[-1]+=data else: cmdList.append(data) diff --git a/source/addonHandler/__init__.py b/source/addonHandler/__init__.py index f555ea28324..6158e6fbe5f 100644 --- a/source/addonHandler/__init__.py +++ b/source/addonHandler/__init__.py @@ -363,7 +363,6 @@ def addToPackagePath(self, package): if not os.path.isdir(extension_path): # This addon does not have extension points for this package return - # Python 2.x doesn't properly handle unicode import paths, so convert them before adding. converted_path = self._getPathForInclusionInPackage(package) package.__path__.insert(0, converted_path) self._extendedPackages.add(package) @@ -474,9 +473,9 @@ def getDocFilePath(self, fileName=None): An add-on can specify a default documentation file name via the docFileName parameter in its manifest. @param fileName: The requested file name or C{None} for the add-on's default. - @type fileName: basestring + @type fileName: str @return: The path to the requested file or C{None} if it wasn't found. - @rtype: basestring + @rtype: str """ if not fileName: fileName = self.manifest["docFileName"] @@ -507,7 +506,7 @@ def getCodeAddon(obj=None, frameDist=1): if obj is None: obj = sys._getframe(frameDist) fileName = inspect.getfile(obj) - dir= unicode(os.path.abspath(os.path.dirname(fileName)), "mbcs") + dir= os.path.abspath(os.path.dirname(fileName)) # if fileName is not a subdir of one of the addon paths # It does not belong to an addon. for p in _getDefaultAddonPaths(): @@ -558,7 +557,7 @@ def __init__(self, bundlePath): """ Constructs an L{AddonBundle} from a filename. @param bundlePath: The path for the bundle file. """ - self._path = bundlePath if isinstance(bundlePath, unicode) else unicode(bundlePath, "mbcs") + self._path = bundlePath # Read manifest: translatedInput=None with zipfile.ZipFile(self._path, 'r') as z: @@ -581,7 +580,7 @@ def extract(self, addonPath): """ with zipfile.ZipFile(self._path, 'r') as z: for info in z.infolist(): - if isinstance(info.filename, str): + if isinstance(info.filename, bytes): # #2505: Handle non-Unicode file names. # Most archivers seem to use the local OEM code page, even though the spec says only cp437. # HACK: Overriding info.filename is a bit ugly, but it avoids a lot of code duplication. diff --git a/source/api.py b/source/api.py index ec929bbac07..3c6a68f9581 100644 --- a/source/api.py +++ b/source/api.py @@ -285,7 +285,7 @@ def copyToClip(text): @param text: the text which will be copied to the clipboard @type text: string """ - if not isinstance(text,basestring) or len(text)==0: + if not isinstance(text,str) or len(text)==0: return False import gui with winUser.openClipboard(gui.mainFrame.Handle): @@ -335,7 +335,7 @@ def getStatusBarText(obj): text = obj.name or "" if text: text += " " - return text + " ".join(chunk for child in obj.children for chunk in (child.name, child.value) if chunk and isinstance(chunk, basestring) and not chunk.isspace()) + return text + " ".join(chunk for child in obj.children for chunk in (child.name, child.value) if chunk and isinstance(chunk, str) and not chunk.isspace()) def filterFileName(name): """Replaces invalid characters in a given string to make a windows compatible file name. diff --git a/source/appModuleHandler.py b/source/appModuleHandler.py index 759cbb84921..130caa90688 100644 --- a/source/appModuleHandler.py +++ b/source/appModuleHandler.py @@ -70,7 +70,7 @@ def getAppNameFromProcessID(processID,includeExt=False): @param includeExt: C{True} to include the extension of the application's executable filename, C{False} to exclude it. @type window: bool @returns: application name - @rtype: unicode or str + @rtype: str """ if processID==NVDAProcessID: return "nvda.exe" if includeExt else "nvda" @@ -78,7 +78,7 @@ def getAppNameFromProcessID(processID,includeExt=False): FProcessEntry32 = processEntry32W() FProcessEntry32.dwSize = ctypes.sizeof(processEntry32W) ContinueLoop = winKernel.kernel32.Process32FirstW(FSnapshotHandle, ctypes.byref(FProcessEntry32)) - appName = unicode() + appName = str() while ContinueLoop: if FProcessEntry32.th32ProcessID == processID: appName = FProcessEntry32.szExeFile @@ -93,8 +93,6 @@ def getAppNameFromProcessID(processID,includeExt=False): # This might be an executable which hosts multiple apps. # Try querying the app module for the name of the app being hosted. try: - # Python 2.x can't properly handle unicode module names, so convert them. - # #8768 (Py3 review required): no longer the case in Python 3. mod = importlib.import_module("appModules.%s" % appName, package="appModules") return mod.getAppNameFromHost(processID) except (ImportError, AttributeError, LookupError): @@ -162,23 +160,21 @@ def fetchAppModule(processID,appName): @param processID: process ID for it to be associated with @type processID: integer @param appName: the application name for which an appModule should be found. - @type appName: unicode or str + @type appName: str @returns: the appModule, or None if not found @rtype: AppModule """ # First, check whether the module exists. # We need to do this separately because even though an ImportError is raised when a module can't be found, it might also be raised for other reasons. - # Python 2.x can't properly handle unicode module names, so convert them. - modName = appName.encode("mbcs") + modName = appName if doesAppModuleExist(modName): try: return importlib.import_module("appModules.%s" % modName, package="appModules").AppModule(processID, appName) except: log.error("error in appModule %r"%modName, exc_info=True) - # We can't present a message which isn't unicode, so use appName, not modName. # Translators: This is presented when errors are found in an appModule (example output: error in appModule explorer). - ui.message(_("Error in appModule %s")%appName) + ui.message(_("Error in appModule %s")%modName) # Use the base AppModule. return AppModule(processID, appName) diff --git a/source/appModules/msnmsgr.py b/source/appModules/msnmsgr.py index cefca969d55..5ec21fccf84 100755 --- a/source/appModules/msnmsgr.py +++ b/source/appModules/msnmsgr.py @@ -52,7 +52,7 @@ def _get_basicText(self): def _get_value(self): value=super(OldMSNHistory,self).value - if not isinstance(value,basestring): + if not isinstance(value,str): value="" return value diff --git a/source/appModules/powerpnt.py b/source/appModules/powerpnt.py index 9d169bc65ff..62a58bf3455 100644 --- a/source/appModules/powerpnt.py +++ b/source/appModules/powerpnt.py @@ -244,7 +244,7 @@ def getBulletText(ppBulletFormat): if t==ppBulletNumbered: return "%d."%ppBulletFormat.number #(ppBulletFormat.startValue+(ppBulletFormat.number-1)) elif t: - return unichr(ppBulletFormat.character) + return chr(ppBulletFormat.character) def walkPpShapeRange(ppShapeRange): for ppShape in ppShapeRange: diff --git a/source/appModules/winamp.py b/source/appModules/winamp.py index 5e252b7c373..a155fc8b766 100644 --- a/source/appModules/winamp.py +++ b/source/appModules/winamp.py @@ -115,7 +115,11 @@ def _get_name(self): winKernel.readProcessMemory(self.processHandle,internalInfo,byref(info),sizeof(info),None) finally: winKernel.virtualFreeEx(self.processHandle,internalInfo,0,winKernel.MEM_RELEASE) - return unicode("%d.\t%s\t%s"%(curIndex+1,info.filetitle,info.filelength), errors="replace", encoding=locale.getlocale()[1]) + # file title is fetched in the current locale encoding. + # We need to decode it to unicode first. + encoding=locale.getlocale()[1] + fileTitle=info.filetitle.decode(encoding,errors="replace") + return "%d.\t%s\t%s"%(curIndex+1,fileTitle,info.filelength) def _get_role(self): return controlTypes.ROLE_LISTITEM diff --git a/source/baseObject.py b/source/baseObject.py index 865ff75cd17..0781a1403db 100755 --- a/source/baseObject.py +++ b/source/baseObject.py @@ -197,7 +197,7 @@ class ScriptableObject(with_metaclass(ScriptableType, AutoPropertyObject)): e.g. in the Input Gestures dialog. This can be overridden for individual scripts by setting a C{category} attribute on the script method. - @type scriptCategory: basestring + @type scriptCategory: str """ def __init__(self): diff --git a/source/browseMode.py b/source/browseMode.py index ae969d34a13..255ce94d576 100644 --- a/source/browseMode.py +++ b/source/browseMode.py @@ -1025,7 +1025,7 @@ def onTreeChar(self, evt): else: # Search the list. # We have to implement this ourselves, as tree views don't accept space as a search character. - char = unichr(evt.UnicodeKey).lower() + char = chr(evt.UnicodeKey).lower() # IF the same character is typed twice, do the same search. if self._searchText != char: self._searchText += char @@ -1648,7 +1648,12 @@ def _get_shouldRememberCaretPositionAcrossLoads(self): docConstId = self.documentConstantIdentifier # Return True if the URL indicates that this is probably a web browser document. # We do this check because we don't want to remember caret positions for email messages, etc. - return isinstance(docConstId, basestring) and docConstId.split("://", 1)[0] in ("http", "https", "ftp", "ftps", "file") + if isinstance(docConstId, str): + protocols=("http", "https", "ftp", "ftps", "file") + protocol=docConstId.split("://", 1)[0] + return protocol in protocols + return False + def _getInitialCaretPos(self): """Retrieve the initial position of the caret after the buffer has been loaded. diff --git a/source/buildVersion.py b/source/buildVersion.py index 130bc3072d4..975583b1be4 100644 --- a/source/buildVersion.py +++ b/source/buildVersion.py @@ -63,8 +63,6 @@ def formatVersionForGUI(year, major, minor): return "{y}.{M}.{m}".format(y=year, M=major, m=minor) -# ticket:3763#comment:19: name must be str, not unicode. -# Otherwise, py2exe will break. name="NVDA" version_year=2019 version_major=4 diff --git a/source/characterProcessing.py b/source/characterProcessing.py index 6a55f61dc8d..f0f1d3b9dfa 100644 --- a/source/characterProcessing.py +++ b/source/characterProcessing.py @@ -618,7 +618,7 @@ def deleteSymbol(self, symbol): def isBuiltin(self, symbolIdentifier): """Determine whether a symbol is built in. @param symbolIdentifier: The identifier of the symbol in question. - @type symbolIdentifier: unicode + @type symbolIdentifier: str @return: C{True} if the symbol is built in, C{False} if it was added by the user. @rtype: bool diff --git a/source/compoundDocuments.py b/source/compoundDocuments.py index 360609c5fc7..c424ba1bec2 100644 --- a/source/compoundDocuments.py +++ b/source/compoundDocuments.py @@ -268,7 +268,7 @@ def getTextWithFields(self, formatConfig=None): embedIndex = None for ti in self._getTextInfos(): for field in ti._iterTextWithEmbeddedObjects(True, formatConfig=formatConfig): - if isinstance(field, basestring): + if isinstance(field, str): fields.append(field) elif isinstance(field, int): # Embedded object if embedIndex is None: diff --git a/source/config/__init__.py b/source/config/__init__.py index 8ad389f09a0..f3a3984d41a 100644 --- a/source/config/__init__.py +++ b/source/config/__init__.py @@ -94,7 +94,7 @@ def isInstalledCopy(): #: When setting it manually, a DWORD value is prefered. #: A value of 0 will evaluate to loading the configuration from the roaming application data (default). #: A value of 1 means loading the configuration from the local application data folder. -#: @type: unicode +#: @type: str CONFIG_IN_LOCAL_APPDATA_SUBKEY=u"configInLocalAppData" def getInstalledUserConfigPath(): @@ -153,7 +153,7 @@ def initConfigPath(configPath=None): """ Creates the current configuration path if it doesn't exist. Also makes sure that various sub directories also exist. @param configPath: an optional path which should be used instead (only useful when being called from outside of NVDA) - @type configPath: basestring + @type configPath: str """ if not configPath: configPath=globalVars.appArgs.configPath @@ -338,8 +338,6 @@ def addConfigDirsToPythonPackagePath(module, subdir=None): if not subdir: subdir = module.__name__ fullPath=os.path.join(getScratchpadDir(),subdir) - # Python 2.x doesn't properly handle unicode import paths, so convert them. - fullPath=fullPath.encode("mbcs") # Insert this path at the beginning of the module's search paths. # The module's search paths may not be a mutable list, so replace it with a new one pathList=[fullPath] @@ -505,7 +503,7 @@ def getProfile(self, name): """Get a profile given its name. This is useful for checking whether a profile has been manually activated or triggered. @param name: The name of the profile. - @type name: basestring + @type name: str @return: The profile object. @raise KeyError: If the profile is not loaded. """ @@ -517,7 +515,7 @@ def manualActivateProfile(self, name): If another profile was manually activated, deactivate it first. If C{name} is C{None}, a profile will not be activated. @param name: The name of the profile or C{None} for no profile. - @type name: basestring + @type name: str """ if len(self.profiles) > 1: profile = self.profiles[-1] @@ -577,7 +575,7 @@ def reset(self, factoryDefaults=False): def createProfile(self, name): """Create a profile. @param name: The name of the profile to create. - @type name: basestring + @type name: str @raise ValueError: If a profile with this name already exists. """ if globalVars.appArgs.secure: @@ -596,7 +594,7 @@ def createProfile(self, name): def deleteProfile(self, name): """Delete a profile. @param name: The name of the profile to delete. - @type name: basestring + @type name: str @raise LookupError: If the profile doesn't exist. """ if globalVars.appArgs.secure: @@ -644,9 +642,9 @@ def deleteProfile(self, name): def renameProfile(self, oldName, newName): """Rename a profile. @param oldName: The current name of the profile. - @type oldName: basestring + @type oldName: str @param newName: The new name for the profile. - @type newName: basestring + @type newName: str @raise LookupError: If the profile doesn't exist. @raise ValueError: If a profile with the new name already exists. """ @@ -1131,7 +1129,7 @@ class ProfileTrigger(object): def spec(self): """The trigger specification. This is a string used to search for this trigger in the user's configuration. - @rtype: basestring + @rtype: str """ raise NotImplementedError diff --git a/source/contentRecog/uwpOcr.py b/source/contentRecog/uwpOcr.py index 119470fb774..2db83e5cae4 100644 --- a/source/contentRecog/uwpOcr.py +++ b/source/contentRecog/uwpOcr.py @@ -21,7 +21,7 @@ def getLanguages(): @return: A list of language codes suitable to be passed to L{UwpOcr}'s constructor. These need to be normalized with L{languageHandler.normalizeLanguage} for use as NVDA language codes. - @rtype: list of unicode + @rtype: list of str """ dll = NVDAHelper.getHelperLocalWin10Dll() dll.uwpOcr_getLanguages.restype = NVDAHelper.bstrReturn diff --git a/source/core.py b/source/core.py index 3503a4a3c0e..608fbc1dadc 100644 --- a/source/core.py +++ b/source/core.py @@ -376,7 +376,7 @@ def handlePowerStatusChange(self): #Translators: Reported when the battery is no longer plugged in, and now is not charging. ui.message(_("Not charging battery. %d percent") %sps.BatteryLifePercent) - messageWindow = MessageWindow(unicode(versionInfo.name)) + messageWindow = MessageWindow(versionInfo.name) # initialize wxpython localization support locale = wx.Locale() diff --git a/source/displayModel.py b/source/displayModel.py index deda6365cd5..854ee9480d7 100644 --- a/source/displayModel.py +++ b/source/displayModel.py @@ -42,7 +42,7 @@ def normalizeRtlString(s): d=unicodedata.decomposition(c) d=d.split(' ') if d else None if d and len(d)==2 and d[0] in ('','','',''): - c=unichr(int(d[1],16)) + c=chr(int(d[1],16)) l.append(c) return u"".join(l) @@ -56,7 +56,7 @@ def processWindowChunksInLine(commandList,rects,startIndex,startOffset,endIndex, lastHwnd=None for index in range(startIndex,endIndex+1): item=commandList[index] if index=1: if curObject.TextInfo!=NVDAObjectTextInfo: textList=[] - if curObject.name and isinstance(curObject.name, basestring) and not curObject.name.isspace(): - textList.append(curObject.name) + name = curObject.name + if isinstance(name, str) and not name.isspace(): + textList.append(name) try: info=curObject.makeTextInfo(textInfos.POSITION_SELECTION) if not info.isCollapsed: @@ -793,7 +794,10 @@ def script_navigatorObject_current(self,gesture): # No caret or selection on this object. pass else: - textList=[prop for prop in (curObject.name, curObject.value) if prop and isinstance(prop, basestring) and not prop.isspace()] + textList=[] + for prop in (curObject.name, curObject.value): + if isinstance(prop,str) and not prop.isspace(): + textList.append(prop) text=" ".join(textList) if len(text)>0 and not text.isspace(): if scriptHandler.getLastScriptRepeatCount()==1: @@ -1498,9 +1502,9 @@ def script_toggleMouseTextResolution(self,gesture): def script_title(self,gesture): obj=api.getForegroundObject() title=obj.name - if not isinstance(title,basestring) or not title or title.isspace(): + if not isinstance(title,str) or not title or title.isspace(): title=obj.appModule.appName if obj.appModule else None - if not isinstance(title,basestring) or not title or title.isspace(): + if not isinstance(title,str) or not title or title.isspace(): # Translators: Reported when there is no title text for current program or window. title=_("No title") repeatCount=scriptHandler.getLastScriptRepeatCount() @@ -1920,7 +1924,7 @@ def script_reportClipboardText(self,gesture): text = api.getClipData() except: text = None - if not text or not isinstance(text,basestring) or text.isspace(): + if not text or not isinstance(text,str) or text.isspace(): # Translators: Presented when there is no text on the clipboard. ui.message(_("There is no text on the clipboard")) return diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 143dba8c699..1e13fbf7342 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -3270,7 +3270,7 @@ def onTreeSelect(self, evt): return data = self.tree.GetItemData(item) isCommand = isinstance(data, inputCore.AllGesturesScriptInfo) - isGesture = isinstance(data, basestring) + isGesture = isinstance(data, str) self.addButton.Enabled = isCommand or isGesture self.removeButton.Enabled = isGesture diff --git a/source/inputCore.py b/source/inputCore.py index 793b8917070..5b248d8084b 100644 --- a/source/inputCore.py +++ b/source/inputCore.py @@ -84,7 +84,7 @@ def _get_identifiers(self): Subclasses must implement this method. @return: One or more identifiers which uniquely identify this gesture. - @rtype: list or tuple of basestring + @rtype: list or tuple of str """ raise NotImplementedError @@ -95,7 +95,7 @@ def _get_normalizedIdentifiers(self): These normalized identifiers can be directly looked up in input gesture maps. Subclasses should not override this method. @return: One or more normalized identifiers which uniquely identify this gesture. - @rtype: list of basestring + @rtype: list of str """ return [normalizeGestureIdentifier(identifier) for identifier in self.identifiers] @@ -167,9 +167,9 @@ def getDisplayTextForIdentifier(cls, identifier): the gesture's source (e.g. "laptop keyboard") and the specific gesture (e.g. "alt+tab"). @param identifier: The normalized gesture identifier in question. - @type identifier: basestring + @type identifier: str @return: A tuple of (source, specificGesture). - @rtype: tuple of (basestring, basestring) + @rtype: tuple of (str, str) @raise Exception: If no display text can be determined. """ raise NotImplementedError @@ -191,7 +191,7 @@ def __init__(self, entries=None): #: @type: bool self.lastUpdateContainedError = False #: The file name for this gesture map, if any. - #: @type: basestring + #: @type: str self.fileName = None if entries: self.update(entries) @@ -280,7 +280,7 @@ def update(self, entries): script = None if gestures == "": gestures = () - elif isinstance(gestures, basestring): + elif isinstance(gestures, str): gestures = [gestures] for gesture in gestures: try: @@ -733,7 +733,7 @@ def registerGestureSource(source, gestureCls): "br" will be used if it is registered. This registration is used, for example, to get the display text for a gesture identifier. @param source: The source prefix for associated gesture identifiers. - @type source: basestring + @type source: str @param gestureCls: The input gesture class. @type gestureCls: L{InputGesture} """ @@ -761,9 +761,9 @@ def getDisplayTextForGestureIdentifier(identifier): the gesture's source (e.g. "laptop keyboard") and the specific gesture (e.g. "alt+tab"). @param identifier: The normalized gesture identifier in question. - @type identifier: basestring + @type identifier: str @return: A tuple of (source, specificGesture). - @rtype: tuple of (basestring, basestring) + @rtype: tuple of (str, str) @raise LookupError: If no display text can be determined. """ gcls = _getGestureClsForIdentifier(identifier) diff --git a/source/installer.py b/source/installer.py index cd53ddb85b6..a368ebc9194 100644 --- a/source/installer.py +++ b/source/installer.py @@ -358,7 +358,7 @@ def tryRemoveFile(path,numRetries=6,retryInterval=0.5,rebootOK=False): time.sleep(retryInterval) if rebootOK: log.debugWarning("Failed to delete file %s, marking for delete on reboot"%tempPath) - MoveFileEx=windll.kernel32.MoveFileExW if isinstance(tempPath,unicode) else windll.kernel32.MoveFileExA + MoveFileEx=windll.kernel32.MoveFileExW MoveFileEx("\\\\?\\"+tempPath,None,4) return try: diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index b30dc8fdf45..6a95812c007 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -395,16 +395,16 @@ def _get_mainKeyName(self): return name if 32 < self.vkCode < 128: - return unichr(self.vkCode).lower() + return chr(self.vkCode).lower() if self.vkCode == vkCodes.VK_PACKET: # Unicode character from non-keyboard input. - return unichr(self.scanCode) + return chr(self.scanCode) vkChar = winUser.user32.MapVirtualKeyExW(self.vkCode, winUser.MAPVK_VK_TO_CHAR, getInputHkl()) if vkChar>0: if vkChar == 43: # "+" # A gesture identifier can't include "+" except as a separator. return "plus" - return unichr(vkChar).lower() + return chr(vkChar).lower() if self.vkCode == 0xFF: # #3468: This key is unknown to Windows. diff --git a/source/languageHandler.py b/source/languageHandler.py index 10ec72ee191..72cf24c0250 100644 --- a/source/languageHandler.py +++ b/source/languageHandler.py @@ -37,7 +37,7 @@ def localeNameToWindowsLCID(localeName): # Windows Vista (NT 6.0) and later is able to convert locale names to LCIDs. # Because NVDA supports Windows 7 (NT 6.1) SP1 and later, just use it directly. localeName=localeName.replace('_','-') - LCID=ctypes.windll.kernel32.LocaleNameToLCID(unicode(localeName),0) + LCID=ctypes.windll.kernel32.LocaleNameToLCID(localeName,0) # #6259: In Windows 10, LOCALE_CUSTOM_UNSPECIFIED is returned for any locale name unknown to Windows. # This was observed for Aragonese ("an"). # See https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.lcid(v=vs.110).aspx. diff --git a/source/louisHelper.py b/source/louisHelper.py index 1cd21f42c58..c89064a03cc 100644 --- a/source/louisHelper.py +++ b/source/louisHelper.py @@ -52,10 +52,10 @@ def terminate(): def translate(tableList, inbuf, typeform=None, cursorPos=None, mode=0): """ Convenience wrapper for louis.translate that: - * returns a list of integers instead of an string with cells, and + * returns a list of integers instead of a string with cells, and * distinguishes between cursor position 0 (cursor at first character) and None (no cursor at all) """ - text = unicode(inbuf).replace('\0','') + text = inbuf.replace('\0','') braille, brailleToRawPos, rawToBraillePos, brailleCursorPos = louis.translate( tableList, text, diff --git a/source/mathPres/__init__.py b/source/mathPres/__init__.py index cf0cb52c823..5b55d706985 100644 --- a/source/mathPres/__init__.py +++ b/source/mathPres/__init__.py @@ -29,16 +29,16 @@ class MathPresentationProvider(object): def getSpeechForMathMl(self, mathMl): """Get speech output for specified MathML markup. @param mathMl: The MathML markup. - @type mathMl: basestring + @type mathMl: str @return: A speech sequence. - @rtype: list of unicode and/or L{speech.SpeechCommand} + @rtype: list of str and/or L{speech.SpeechCommand} """ raise NotImplementedError def getBrailleForMathMl(self, mathMl): """Get braille output for specified MathML markup. @param mathMl: The MathML markup. - @type mathMl: basestring + @type mathMl: str @return: A string of Unicode braille. @rtype: unicode """ @@ -136,7 +136,7 @@ def getMathMlFromTextInfo(pos): @param pos: The TextInfo in question. @type pos: L{textInfos.TextInfo} @return: The MathML or C{None} if there is no math. - @rtype: basestring + @rtype: str """ pos = pos.copy() pos.expand(textInfos.UNIT_CHARACTER) @@ -172,7 +172,7 @@ def interactWithMathMl(mathMl): def getLanguageFromMath(mathMl): """Get the language specified in a math tag. @return: The language or C{None} if unspeicifed. - @rtype: basestring + @rtype: str """ m = RE_MATH_LANG.search(mathMl) if m: diff --git a/source/nvda.pyw b/source/nvda.pyw index 42ad41eab07..4fbe401ebb7 100755 --- a/source/nvda.pyw +++ b/source/nvda.pyw @@ -54,14 +54,14 @@ class NoConsoleOptionParser(argparse.ArgumentParser): def print_help(self, file=None): """Shows help in a standard Windows message dialog""" - winUser.MessageBox(0, unicode(self.format_help()), u"Help", 0) + winUser.MessageBox(0, self.format_help(), u"Help", 0) def error(self, message): """Shows an error in a standard Windows message dialog, and then exits NVDA""" out = "" out = self.format_usage() out += "\nerror: %s" % message - winUser.MessageBox(0, unicode(out), u"Error", 0) + winUser.MessageBox(0, out, u"Error", 0) sys.exit(2) globalVars.startTime=time.time() diff --git a/source/nvda_slave.pyw b/source/nvda_slave.pyw index e4fc0d79431..33d6fec4b3c 100755 --- a/source/nvda_slave.pyw +++ b/source/nvda_slave.pyw @@ -69,7 +69,7 @@ def main(): shellapi.ShellExecute(0,None,path,None,None,winUser.SW_SHOWNORMAL) elif action == "addons_installAddonPackage": try: - addonPath=unicode(args[0], "mbcs") + addonPath=args[0] except IndexError: raise ValueError("Addon path was not provided.") #Load nvdaHelperRemote.dll but with an altered search path so it can pick up other dlls in lib diff --git a/source/nvwave.py b/source/nvwave.py index 076f25eafb1..6e61b685b18 100644 --- a/source/nvwave.py +++ b/source/nvwave.py @@ -117,7 +117,7 @@ def __init__(self, channels, samplesPerSec, bitsPerSample, @param bitsPerSample: The number of bits per sample. @type bitsPerSample: int @param outputDevice: The device ID or name of the audio output device to use. - @type outputDevice: int or basestring + @type outputDevice: int or str @param closeWhenIdle: If C{True}, close the output device when no audio is being played. @type closeWhenIdle: bool @param wantDucking: if true then background audio will be ducked on Windows 8 and higher @@ -130,7 +130,7 @@ def __init__(self, channels, samplesPerSec, bitsPerSample, self.channels=channels self.samplesPerSec=samplesPerSec self.bitsPerSample=bitsPerSample - if isinstance(outputDevice, basestring): + if isinstance(outputDevice, str): outputDevice = outputDeviceNameToID(outputDevice, True) self.outputDeviceID = outputDevice if wantDucking: @@ -146,7 +146,7 @@ def __init__(self, channels, samplesPerSec, bitsPerSample, BITS_PER_BYTE = 8 MS_PER_SEC = 1000 self._minBufferSize = samplesPerSec * channels * (bitsPerSample / BITS_PER_BYTE) / MS_PER_SEC * self.MIN_BUFFER_MS - self._buffer = "" + self._buffer = b"" else: self._minBufferSize = None #: Function to call when the previous chunk of audio has finished playing. @@ -198,7 +198,7 @@ def feed(self, data, onDone=None): # so we can accurately call onDone at the end of this chunk. if onDone or len(self._buffer) > self._minBufferSize: self._feedUnbuffered(self._buffer, onDone=onDone) - self._buffer = "" + self._buffer = b"" def _feedUnbuffered(self, data, onDone=None): if self._audioDucker and not self._audioDucker.enable(): @@ -277,7 +277,7 @@ def idle(self): return self._idleUnbuffered() if self._buffer: self._feedUnbuffered(self._buffer) - self._buffer = "" + self._buffer = b"" return self._idleUnbuffered() def _idleUnbuffered(self): @@ -295,7 +295,7 @@ def stop(self): """ if self._audioDucker: self._audioDucker.disable() if self._minBufferSize: - self._buffer = "" + self._buffer = b"" with self._waveout_lock: if not self._waveout: return diff --git a/source/oleacc.py b/source/oleacc.py index d97ec999dbf..260470df755 100644 --- a/source/oleacc.py +++ b/source/oleacc.py @@ -192,7 +192,7 @@ def CreateStdAccessibleProxy(hwnd,className,objectID,interface=IAccessible): @param hwnd: the handle of the window this accessible object should represent. @type hwnd: int @param className: the window class name to use. - @type className: basestring + @type className: str @param objectID: an OBJID_* constant or custom value stating the specific object in the window. @type objectID: int @param interface: the requested COM interface for this object. Defaults to IAccessible. diff --git a/source/scriptHandler.py b/source/scriptHandler.py index 39e78ee90b5..aeb5038078c 100644 --- a/source/scriptHandler.py +++ b/source/scriptHandler.py @@ -32,9 +32,6 @@ def _makeKbEmulateScript(scriptName): keyName = scriptName[3:] emuGesture = keyboardHandler.KeyboardInputGesture.fromName(keyName) func = lambda gesture: inputCore.manager.emulateGesture(emuGesture) - if isinstance(scriptName, unicode): - # __name__ must be str; i.e. can't be unicode. - scriptName = scriptName.encode("mbcs") func.__name__ = "script_%s" % scriptName func.__doc__ = _("Emulates pressing %s on the system keyboard") % emuGesture.displayName return func diff --git a/source/speech/__init__.py b/source/speech/__init__.py index b3162c54cc1..64a9752a6d9 100755 --- a/source/speech/__init__.py +++ b/source/speech/__init__.py @@ -138,7 +138,7 @@ def spellTextInfo(info,useCharacterDescriptions=False,priority=None): return curLanguage=None for field in info.getTextWithFields({}): - if isinstance(field,basestring): + if isinstance(field,str): speakSpelling(field,curLanguage,useCharacterDescriptions=useCharacterDescriptions,priority=priority) elif isinstance(field,textInfos.FieldCommand) and field.command=="formatChange": curLanguage=field.field.get('language') @@ -430,9 +430,9 @@ def speakText(text,reason=controlTypes.REASON_MESSAGE,symbolLevel=None,priority= def splitTextIndentation(text): """Splits indentation from the rest of the text. @param text: The text to split. - @type text: basestring + @type text: str @return: Tuple of indentation and content. - @rtype: (basestring, basestring) + @rtype: (str, str) """ return RE_INDENTATION_SPLIT.match(text).groups() @@ -443,11 +443,11 @@ def splitTextIndentation(text): def getIndentationSpeech(indentation, formatConfig): """Retrieves the phrase to be spoken for a given string of indentation. @param indentation: The string of indentation. - @type indentation: unicode + @type indentation: str @param formatConfig: The configuration to use. @type formatConfig: dict @return: The phrase to be spoken. - @rtype: unicode + @rtype: str """ speechIndentConfig = formatConfig["reportLineIndentation"] toneIndentConfig = formatConfig["reportLineIndentationWithTones"] and speechMode == speechMode_talk @@ -502,7 +502,7 @@ def speak(speechSequence, symbolLevel=None, priority=None): import speechViewer if speechViewer.isActive: for item in speechSequence: - if isinstance(item, basestring): + if isinstance(item, str): speechViewer.appendText(item) global beenCanceled if speechMode==speechMode_off: @@ -528,7 +528,7 @@ def speak(speechSequence, symbolLevel=None, priority=None): curLanguage=item.lang if not curLanguage or (not autoDialectSwitching and curLanguage.split('_')[0]==defaultLanguageRoot): curLanguage=defaultLanguage - elif isinstance(item,basestring): + elif isinstance(item,str): if not item: continue if autoLanguageSwitching and curLanguage!=prevLanguage: speechSequence.append(LangChangeCommand(curLanguage)) @@ -553,7 +553,7 @@ def speak(speechSequence, symbolLevel=None, priority=None): inCharacterMode=item.state if autoLanguageSwitching and isinstance(item,LangChangeCommand): curLanguage=item.lang - if isinstance(item,basestring): + if isinstance(item,str): speechSequence[index]=processText(curLanguage,item,symbolLevel) if not inCharacterMode: speechSequence[index]+=CHUNK_SEPARATOR @@ -884,7 +884,7 @@ def speakTextInfo(info, useCache=True, formatConfig=None, unit=None, reason=cont if onlyInitialFields or (unit in (textInfos.UNIT_CHARACTER,textInfos.UNIT_WORD) and len(textWithFields)>0 and len(textWithFields[0])==1 and all((isinstance(x,textInfos.FieldCommand) and x.command=="controlEnd") for x in itertools.islice(textWithFields,1,None) )): if not onlyCache: - if onlyInitialFields or any(isinstance(x,basestring) for x in speechSequence): + if onlyInitialFields or any(isinstance(x,str) for x in speechSequence): speak(speechSequence,priority=priority) if not onlyInitialFields: speakSpelling(textWithFields[0],locale=language if autoLanguageSwitching else None,priority=priority) @@ -906,7 +906,7 @@ def speakTextInfo(info, useCache=True, formatConfig=None, unit=None, reason=cont allIndentation="" indentationDone=False for command in textWithFields: - if isinstance(command,basestring): + if isinstance(command,str): # Text should break a run of clickables inClickable=False if reportIndentation and not indentationDone: @@ -985,7 +985,7 @@ def speakTextInfo(info, useCache=True, formatConfig=None, unit=None, reason=cont # Don't add this text if it is blank. relativeBlank=True for x in relativeSpeechSequence: - if isinstance(x,basestring) and not isBlank(x): + if isinstance(x,str) and not isBlank(x): relativeBlank=False break if not relativeBlank: @@ -1412,9 +1412,9 @@ def getFormatFieldSpeech(attrs,attrsCache=None,formatConfig=None,reason=None,uni backgroundColor2=attrs.get("background-color2") oldBackgroundColor2=attrsCache.get("background-color2") if attrsCache is not None else None bgColorChanged=backgroundColor!=oldBackgroundColor or backgroundColor2!=oldBackgroundColor2 - bgColorText=backgroundColor.name if isinstance(backgroundColor,colors.RGB) else unicode(backgroundColor) + bgColorText=backgroundColor.name if isinstance(backgroundColor,colors.RGB) else backgroundColor if backgroundColor2: - bg2Name=backgroundColor2.name if isinstance(backgroundColor2,colors.RGB) else unicode(backgroundColor2) + bg2Name=backgroundColor2.name if isinstance(backgroundColor2,colors.RGB) else backgroundColor2 # Translators: Reported when there are two background colors. # This occurs when, for example, a gradient pattern is applied to a spreadsheet cell. # {color1} will be replaced with the first background color. @@ -1425,12 +1425,12 @@ def getFormatFieldSpeech(attrs,attrsCache=None,formatConfig=None,reason=None,uni # {color} will be replaced with the text color. # {backgroundColor} will be replaced with the background color. textList.append(_("{color} on {backgroundColor}").format( - color=color.name if isinstance(color,colors.RGB) else unicode(color), + color=color.name if isinstance(color,colors.RGB) else color, backgroundColor=bgColorText)) elif color and color!=oldColor: # Translators: Reported when the text color changes (but not the background color). # {color} will be replaced with the text color. - textList.append(_("{color}").format(color=color.name if isinstance(color,colors.RGB) else unicode(color))) + textList.append(_("{color}").format(color=color.name if isinstance(color,colors.RGB) else color)) elif backgroundColor and bgColorChanged: # Translators: Reported when the background color changes (but not the text color). # {backgroundColor} will be replaced with the background color. @@ -1772,7 +1772,7 @@ def speakWithoutPauses(speechSequence,detectBreaks=True): #And place the final incomplete phrase in pendingSpeechSequence for index in range(len(speechSequence)-1,-1,-1): item=speechSequence[index] - if isinstance(item,basestring): + if isinstance(item,str): m=re_last_pause.match(item) if m: before,after=m.groups() diff --git a/source/speech/commands.py b/source/speech/commands.py index 0578db6bc3c..2aa1e10687a 100644 --- a/source/speech/commands.py +++ b/source/speech/commands.py @@ -214,11 +214,11 @@ class PhonemeCommand(SynthCommand): def __init__(self, ipa, text=None): """ @param ipa: Unicode IPA characters. - @type ipa: unicode + @type ipa: str @param text: Text to speak if the synthesizer does not support some or all of the specified IPA characters, C{None} to ignore this command instead. - @type text: unicode + @type text: str """ self.ipa = ipa self.text = text diff --git a/source/speechViewer.py b/source/speechViewer.py index d2e60f55f43..d520b720fb1 100644 --- a/source/speechViewer.py +++ b/source/speechViewer.py @@ -90,7 +90,7 @@ def _setActive(isNowActive, speechViewerFrame=None): def appendText(text): if not isActive: return - if not isinstance(text,basestring): + if not isinstance(text,str): return #If the speech viewer text control has the focus, we want to disable updates #Otherwise it would be impossible to select text, or even just read it (as a blind person). diff --git a/source/speechXml.py b/source/speechXml.py index 3453d0bee12..0abe0be00ac 100644 --- a/source/speechXml.py +++ b/source/speechXml.py @@ -28,7 +28,7 @@ def _buildInvalidXmlRegexp(): # Ranges of invalid characters. # Both start and end are inclusive; i.e. they are both themselves considered invalid. ranges = ((0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84), (0x86, 0x9F), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF)) - rangeExprs = [u"%s-%s" % (unichr(start), unichr(end)) + rangeExprs = [u"%s-%s" % (chr(start), chr(end)) for start, end in ranges] leadingSurrogate = u"[\uD800-\uDBFF]" trailingSurrogate = u"[\uDC00-\uDFFF]" @@ -73,7 +73,7 @@ def toXmlLang(nvdaLang): StandAloneTagCommand = namedtuple("StandAloneTagCommand", ("tag", "attrs", "content")) def _escapeXml(text): - text = unicode(text).translate(XML_ESCAPES) + text = text.translate(XML_ESCAPES) text = RE_INVALID_XML_CHARS.sub(REPLACEMENT_CHAR, text) return text @@ -112,7 +112,9 @@ def _openTag(self, tag, attrs, empty=False): self._out.append("<%s" % tag) for attr, val in attrs.items(): self._out.append(' %s="' % attr) - self._out.append(_escapeXml(val)) + # Attribute values could be ints, floats etc, not just strings. + # Therefore coerce the value to a string, as well as escaping xml characters. + self._out.append(_escapeXml(str(val))) self._out.append('"') self._out.append("/>" if empty else ">") @@ -154,7 +156,7 @@ def generateXml(self, commands): """Generate XML from a sequence of balancer commands and text. """ for command in commands: - if isinstance(command, basestring): + if isinstance(command, str): self._outputTags() self._text(command) elif isinstance(command, EncloseAllCommand): @@ -206,7 +208,7 @@ def generateBalancerCommands(self, speechSequence): @rtype: generator """ for item in speechSequence: - if isinstance(item, basestring): + if isinstance(item, str): yield item elif isinstance(item, speech.SpeechCommand): name = type(item).__name__ diff --git a/source/synthDriverHandler.py b/source/synthDriverHandler.py index a2b35cb2ecf..d4574bd3953 100644 --- a/source/synthDriverHandler.py +++ b/source/synthDriverHandler.py @@ -275,7 +275,7 @@ def speak(self,speechSequence): if item is None: # No more items. break - if isinstance(item,basestring): + if isinstance(item,str): # Merge the text between commands into a single chunk. text+=item elif isinstance(item,speech.IndexCommand): diff --git a/source/synthDrivers/_espeak.py b/source/synthDrivers/_espeak.py index b63977a1898..3cefb3aaf4b 100755 --- a/source/synthDrivers/_espeak.py +++ b/source/synthDrivers/_espeak.py @@ -122,6 +122,12 @@ def __eq__(self, other): CALLBACK_CONTINUE_SYNTHESIS=0 CALLBACK_ABORT_SYNTHESIS=1 +def encodeEspeakString(text): + return text.encode('utf8') + +def decodeEspeakString(data): + return data.decode('utf8') + t_espeak_callback=CFUNCTYPE(c_int,POINTER(c_short),c_int,POINTER(espeak_EVENT)) @t_espeak_callback @@ -133,12 +139,12 @@ def callback(wav,numsamples,event): indexes = [] for e in event: if e.type==espeakEVENT_MARK: - indexNum = int(e.id.name) + indexNum = int(decodeEspeakString(e.id.name)) # e.audio_position is ms since the start of this utterance. # Convert to bytes since the start of the utterance. BYTES_PER_SAMPLE = 2 MS_PER_SEC = 1000 - bytesPerMS = player.samplesPerSec * BYTES_PER_SAMPLE / MS_PER_SEC + bytesPerMS = player.samplesPerSec * BYTES_PER_SAMPLE // MS_PER_SEC indexByte = e.audio_position * bytesPerMS # Subtract bytes in the utterance that have already been handled # to give us the byte offset into the samples for this callback. @@ -151,7 +157,7 @@ def callback(wav,numsamples,event): onIndexReached(None) isSpeaking = False return CALLBACK_CONTINUE_SYNTHESIS - wav = string_at(wav, numsamples * sizeof(c_short)) if numsamples>0 else "" + wav = string_at(wav, numsamples * sizeof(c_short)) if numsamples>0 else b"" prevByte = 0 for indexNum, indexByte in indexes: player.feed(wav[prevByte:indexByte], @@ -261,10 +267,11 @@ def setVoice(voice): setVoiceByName(voice.identifier) def setVoiceByName(name): - _execWhenDone(espeakDLL.espeak_SetVoiceByName,name) + _execWhenDone(espeakDLL.espeak_SetVoiceByName,encodeEspeakString(name)) def _setVoiceAndVariant(voice=None, variant=None): - res = getCurrentVoice().identifier.split("+") + v=getCurrentVoice() + res = decodeEspeakString(v.identifier).split("+") if not voice: voice = res[0] if not variant: @@ -273,12 +280,12 @@ def _setVoiceAndVariant(voice=None, variant=None): else: variant = "none" if variant == "none": - espeakDLL.espeak_SetVoiceByName(voice) + espeakDLL.espeak_SetVoiceByName(encodeEspeakString(voice)) else: try: - espeakDLL.espeak_SetVoiceByName("%s+%s" % (voice, variant)) + espeakDLL.espeak_SetVoiceByName(encodeEspeakString("%s+%s" % (voice, variant))) except: - espeakDLL.espeak_SetVoiceByName(voice) + espeakDLL.espeak_SetVoiceByName(encodeEspeakString(voice)) def setVoiceAndVariant(voice=None, variant=None): _execWhenDone(_setVoiceAndVariant, voice=voice, variant=variant) @@ -286,11 +293,11 @@ def setVoiceAndVariant(voice=None, variant=None): def _setVoiceByLanguage(lang): v=espeak_VOICE() lang=lang.replace('_','-') - v.languages=lang + v.languages=encodeEspeakString(lang) try: espeakDLL.espeak_SetVoiceByProperties(byref(v)) except: - v.languages="en" + v.languages=encodeEspeakString("en") espeakDLL.espeak_SetVoiceByProperties(byref(v)) def setVoiceByLanguage(lang): @@ -318,8 +325,9 @@ def initialize(indexCallback=None): espeakDLL.espeak_ListVoices.restype=POINTER(POINTER(espeak_VOICE)) espeakDLL.espeak_GetCurrentVoice.restype=POINTER(espeak_VOICE) espeakDLL.espeak_SetVoiceByName.argtypes=(c_char_p,) + eSpeakPath=os.path.abspath("synthDrivers") sampleRate=espeakDLL.espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,300, - os.path.abspath("synthDrivers"),0) + os.fsencode(eSpeakPath),0) if sampleRate<0: raise OSError("espeak_Initialize %d"%sampleRate) player = nvwave.WavePlayer(channels=1, samplesPerSec=sampleRate, bitsPerSample=16, diff --git a/source/synthDrivers/espeak.py b/source/synthDrivers/espeak.py index a72a7c950e1..2f2ad27b54c 100644 --- a/source/synthDrivers/espeak.py +++ b/source/synthDrivers/espeak.py @@ -72,7 +72,6 @@ def _get_language(self): } def _processText(self, text): - text = unicode(text) # We need to make several replacements. return text.translate({ 0x1: None, # used for embedded commands @@ -90,7 +89,7 @@ def speak(self,speechSequence): # . # However, eSpeak doesn't seem to mind. for item in speechSequence: - if isinstance(item,basestring): + if isinstance(item,str): textList.append(self._processText(item)) elif isinstance(item,speech.IndexCommand): textList.append(""%item.index) @@ -123,7 +122,7 @@ def speak(self,speechSequence): textList.append(' %s="%d%%"'%(attr,val)) textList.append(">") elif isinstance(item,speech.PhonemeCommand): - # We can't use unicode.translate because we want to reject unknown characters. + # We can't use str.translate because we want to reject unknown characters. try: phonemes="".join([self.IPA_TO_ESPEAK[char] for char in item.ipa]) # There needs to be a space after the phoneme command. @@ -199,11 +198,11 @@ def _set_volume(self,volume): def _getAvailableVoices(self): voices=OrderedDict() for v in _espeak.getVoiceList(): - l=v.languages[1:] + l=_espeak.decodeEspeakString(v.languages[1:]) # #7167: Some languages names contain unicode characters EG: Norwegian Bokmål - name=v.name.decode("UTF-8") + name=_espeak.decodeEspeakString(v.name) # #5783: For backwards compatibility, voice identifies should always be lowercase - identifier=os.path.basename(v.identifier).lower() + identifier=os.path.basename(_espeak.decodeEspeakString(v.identifier)).lower() voices[identifier]=VoiceInfo(identifier,name,l) return voices @@ -214,7 +213,7 @@ def _get_voice(self): if not curVoice: return "" # #5783: For backwards compatibility, voice identifies should always be lowercase - return curVoice.identifier.split('+')[0].lower() + return _espeak.decodeEspeakString(curVoice.identifier).split('+')[0].lower() def _set_voice(self, identifier): if not identifier: diff --git a/source/synthDrivers/oneCore.py b/source/synthDrivers/oneCore.py index 11894bef05f..02d3f888eb5 100644 --- a/source/synthDrivers/oneCore.py +++ b/source/synthDrivers/oneCore.py @@ -204,7 +204,7 @@ def cancel(self): if self.supportsProsodyOptions: # In this case however, we must keep any parameter changes. self._queuedSpeech = [item for item in self._queuedSpeech - if not isinstance(item, basestring)] + if not isinstance(item, str)] else: self._queuedSpeech = [] if self._player: @@ -405,7 +405,7 @@ def _isVoiceValid(self,ID): except WindowsError as e: log.debugWarning("Could not open registry value 'langDataPath', %r" % e) return False - if not langDataPath or not isinstance(langDataPath[0], basestring): + if not langDataPath or not isinstance(langDataPath[0], str): log.debugWarning("Invalid langDataPath value") return False if not os.path.isfile(os.path.expandvars(langDataPath[0])): @@ -416,7 +416,7 @@ def _isVoiceValid(self,ID): except WindowsError as e: log.debugWarning("Could not open registry value 'langDataPath', %r" % e) return False - if not voicePath or not isinstance(voicePath[0],basestring): + if not voicePath or not isinstance(voicePath[0],str): log.debugWarning("Invalid voicePath value") return False if not os.path.isfile(os.path.expandvars(voicePath[0] + '.apm')): diff --git a/source/synthDrivers/sapi4.py b/source/synthDrivers/sapi4.py index 4e75af9b783..21d33cd8ee9 100755 --- a/source/synthDrivers/sapi4.py +++ b/source/synthDrivers/sapi4.py @@ -88,7 +88,7 @@ def speak(self,speechSequence): charMode=False item=None for item in speechSequence: - if isinstance(item,basestring): + if isinstance(item,str): textList.append(item.replace('\\','\\\\')) elif isinstance(item,speech.IndexCommand): textList.append("\\mrk=%d\\"%item.index) diff --git a/source/synthDrivers/sapi5.py b/source/synthDrivers/sapi5.py index d183007742b..36c412301be 100644 --- a/source/synthDrivers/sapi5.py +++ b/source/synthDrivers/sapi5.py @@ -286,7 +286,7 @@ def outputTags(): volume = self.volume for item in speechSequence: - if isinstance(item, basestring): + if isinstance(item, str): outputTags() textList.append(item.replace("<", "<")) elif isinstance(item, speech.IndexCommand): diff --git a/source/textInfos/__init__.py b/source/textInfos/__init__.py index e0a0364c1f0..8c1e7b87389 100755 --- a/source/textInfos/__init__.py +++ b/source/textInfos/__init__.py @@ -257,7 +257,7 @@ def _get_text(self): """The text with in this range. Subclasses must implement this. @return: The text. - @rtype: unicode + @rtype: str @note: The text is not guaranteed to be the exact length of the range in offsets. """ raise NotImplementedError @@ -268,7 +268,7 @@ def getTextWithFields(self,formatConfig=None): @param formatConfig: Document formatting configuration, useful if you wish to force a particular configuration for a particular task. @type formatConfig: dict @return: A sequence of text strings interspersed with associated field commands. - @rtype: list of unicode and L{FieldCommand} + @rtype: list of str and L{FieldCommand} """ return [self.text] @@ -484,7 +484,7 @@ def getFormatFieldSpeech(self, attrs, attrsCache=None, formatConfig=None, reason If extended, the superclass should be called first. @param separator: The text used to separate chunks of format information; defaults to L{speech.CHUNK_SEPARATOR}. - @type separator: basestring + @type separator: str """ # Import late to avoid circular import. import speech diff --git a/source/textInfos/offsets.py b/source/textInfos/offsets.py index 15c9bea218f..8fbcbcb517f 100755 --- a/source/textInfos/offsets.py +++ b/source/textInfos/offsets.py @@ -71,7 +71,7 @@ def findStartOfLine(text,offset,lineLength=None): def findEndOfLine(text,offset,lineLength=None): """Searches forwards through the given text from the given offset, until it finds the offset that is the start of the next line. With out a set line length, it searches for new line / cariage return characters, with a set line length it simply moves forward to sit on a multiple of the line length. @param text: the text to search -@type text: unicode +@type text: str @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @@ -98,7 +98,7 @@ def findEndOfLine(text,offset,lineLength=None): def findStartOfWord(text,offset,lineLength=None): """Searches backwards through the given text from the given offset, until it finds the offset that is the start of the word. It checks to see if a character is alphanumeric, or is another symbol , or is white space. @param text: the text to search -@type text: unicode +@type text: str @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @@ -120,7 +120,7 @@ def findStartOfWord(text,offset,lineLength=None): def findEndOfWord(text,offset,lineLength=None): """Searches forwards through the given text from the given offset, until it finds the offset that is the start of the next word. It checks to see if a character is alphanumeric, or is another symbol , or is white space. @param text: the text to search -@type text: unicode +@type text: str @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @@ -270,7 +270,7 @@ def _getStoryLength(self): def _getStoryText(self): """Retrieve the entire text of the object. @return: The entire text of the object. - @rtype: unicode + @rtype: str """ raise NotImplementedError @@ -281,7 +281,7 @@ def _getTextRange(self,start,end): @param end: The end offset (exclusive). @type end: int @return: The text contained in the requested range. - @rtype: unicode + @rtype: str """ text=self._getStoryText() return text[start:end] if text else u"" diff --git a/source/ui.py b/source/ui.py index eab3dc45070..ca19d3c9bf6 100644 --- a/source/ui.py +++ b/source/ui.py @@ -36,9 +36,9 @@ def browseableMessage(message,title=None,isHtml=False): """Present a message to the user that can be read in browse mode. The message will be presented in an HTML document. @param message: The message in either html or text. - @type message: unicode + @type message: str @param title: The title for the message. - @type title: unicode + @type title: str @param isHtml: Whether the message is html @type isHtml: boolean """ @@ -46,7 +46,7 @@ def browseableMessage(message,title=None,isHtml=False): if not os.path.isfile(htmlFileName ): raise LookupError(htmlFileName ) moniker = POINTER(IUnknown)() - windll.urlmon.CreateURLMonikerEx(0, unicode( htmlFileName ) , byref(moniker), URL_MK_UNIFORM) + windll.urlmon.CreateURLMonikerEx(0, htmlFileName, byref(moniker), URL_MK_UNIFORM) if not title: # Translators: The title for the dialog used to present general NVDA messages in browse mode. title = _("NVDA Message") @@ -54,7 +54,14 @@ def browseableMessage(message,title=None,isHtml=False): dialogString = u"{isHtml};{title};{message}".format( isHtml = isHtmlArgument , title=title , message=message ) dialogArguements = automation.VARIANT( dialogString ) gui.mainFrame.prePopup() - windll.mshtml.ShowHTMLDialogEx( gui.mainFrame.Handle , moniker , HTMLDLG_MODELESS , addressof( dialogArguements ) , unicode(DIALOG_OPTIONS ), None) + windll.mshtml.ShowHTMLDialogEx( + gui.mainFrame.Handle , + moniker , + HTMLDLG_MODELESS , + addressof( dialogArguements ) , + DIALOG_OPTIONS, + None + ) gui.mainFrame.postPopup() def message(text): diff --git a/source/virtualBuffers/MSHTML.py b/source/virtualBuffers/MSHTML.py index df759ba70dc..fcb93c6d908 100644 --- a/source/virtualBuffers/MSHTML.py +++ b/source/virtualBuffers/MSHTML.py @@ -57,7 +57,7 @@ def _normalizeControlField(self,attrs): if placeholder: attrs['placeholder']=placeholder accRole=attrs.get('IAccessible::role',0) - accRole=int(accRole) if isinstance(accRole,basestring) and accRole.isdigit() else accRole + accRole=int(accRole) if isinstance(accRole,str) and accRole.isdigit() else accRole nodeName=attrs.get('IHTMLDOMNode::nodeName',"") ariaRoles=attrs.get("HTMLAttrib::role", "").split(" ") #choose role diff --git a/source/virtualBuffers/__init__.py b/source/virtualBuffers/__init__.py index 2e39ccb6264..b6b13b5b77f 100644 --- a/source/virtualBuffers/__init__.py +++ b/source/virtualBuffers/__init__.py @@ -44,7 +44,7 @@ VBufRemote_nodeHandle_t=ctypes.c_ulonglong -class VBufStorage_findMatch_word(unicode): +class VBufStorage_findMatch_word(str): pass VBufStorage_findMatch_notEmpty = object() @@ -57,7 +57,7 @@ class VBufStorage_findMatch_word(unicode): # Symbols that must be escaped for a regular expression. FINDBYATTRIBS_ESCAPE_TABLE.update({(ord(s), u"\\" + s) for s in u"^$.*+?()[]{}|"}) def _prepareForFindByAttributes(attribs): - escape = lambda text: unicode(text).translate(FINDBYATTRIBS_ESCAPE_TABLE) + escape = lambda text: text.translate(FINDBYATTRIBS_ESCAPE_TABLE) reqAttrs = [] regexp = [] if isinstance(attribs, dict): @@ -67,7 +67,7 @@ def _prepareForFindByAttributes(attribs): # so first build the list of requested attributes. for option in attribs: for name in option: - reqAttrs.append(unicode(name)) + reqAttrs.append(name) # Now build the regular expression. for option in attribs: optRegexp = [] @@ -436,7 +436,11 @@ def _loadBuffer(self): try: if log.isEnabledFor(log.DEBUG): startTime = time.time() - self.VBufHandle=NVDAHelper.localLib.VBuf_createBuffer(self.rootNVDAObject.appModule.helperLocalBindingHandle,self.rootDocHandle,self.rootID,unicode(self.backendName)) + self.VBufHandle=NVDAHelper.localLib.VBuf_createBuffer( + self.rootNVDAObject.appModule.helperLocalBindingHandle, + self.rootDocHandle,self.rootID, + self.backendName + ) if not self.VBufHandle: raise RuntimeError("Could not remotely create virtualBuffer") except: @@ -477,7 +481,7 @@ def unloadBuffer(self): def isNVDAObjectPartOfLayoutTable(self,obj): docHandle,ID=self.getIdentifierFromNVDAObject(obj) - ID=unicode(ID) + ID=str(ID) info=self.makeTextInfo(obj) info.collapse() info.expand(textInfos.UNIT_CHARACTER) @@ -682,7 +686,7 @@ def _handleUpdate(self): def getControlFieldForNVDAObject(self, obj): docHandle, objId = self.getIdentifierFromNVDAObject(obj) - objId = unicode(objId) + objId = str(objId) info = self.makeTextInfo(obj) info.collapse() info.expand(textInfos.UNIT_CHARACTER) diff --git a/source/winConsoleHandler.py b/source/winConsoleHandler.py index a434d56af3c..bf06cf96828 100755 --- a/source/winConsoleHandler.py +++ b/source/winConsoleHandler.py @@ -147,7 +147,7 @@ def consoleWinEventHook(handle,eventID,window,objectID,childID,threadID,timestam y=winUser.GET_Y_LPARAM(objectID) consoleScreenBufferInfo=wincon.GetConsoleScreenBufferInfo(consoleOutputHandle) if x