diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/Utilities/__init__.py --- a/src/eric7/Utilities/__init__.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/Utilities/__init__.py Wed Jul 13 14:55:47 2022 +0200 @@ -18,14 +18,14 @@ import pathlib import re import shlex -import subprocess # secok +import subprocess # secok import sys def __showwarning(message, category, filename, lineno, file=None, line=""): """ Module function to raise a SyntaxError for a SyntaxWarning. - + @param message warning object @param category type object of the warning @param filename name of the file causing the warning (string) @@ -39,24 +39,40 @@ err.filename = filename err.lineno = lineno raise err - + + import warnings + warnings.showwarning = __showwarning from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF32 from PyQt6.QtCore import ( - qVersion, PYQT_VERSION_STR, QDir, QProcess, QByteArray, QCoreApplication, - QCryptographicHash + qVersion, + PYQT_VERSION_STR, + QDir, + QProcess, + QByteArray, + QCoreApplication, + QCryptographicHash, ) from PyQt6.Qsci import QSCINTILLA_VERSION_STR, QsciScintilla # import these methods into the Utilities namespace from Globals import ( # __IGNORE_WARNING__ - isWindowsPlatform, isLinuxPlatform, isMacPlatform, desktopName, - sessionType, getConfigDir, setConfigDir, getPythonLibraryDirectory, - getPyQt6ModulesDirectory, getQtBinariesPath, getPyQtToolsPath, - qVersionTuple, getPythonExecutable + isWindowsPlatform, + isLinuxPlatform, + isMacPlatform, + desktopName, + sessionType, + getConfigDir, + setConfigDir, + getPythonLibraryDirectory, + getPyQt6ModulesDirectory, + getQtBinariesPath, + getPyQtToolsPath, + qVersionTuple, + getPythonExecutable, ) from EricWidgets.EricApplication import ericApp @@ -66,57 +82,110 @@ import Preferences from Plugins.CheckerPlugins.SyntaxChecker.SyntaxCheck import ( # __IGNORE_WARNING__ - normalizeCode) + normalizeCode, +) from eric7config import getConfig configDir = None codingBytes_regexps = [ - (5, re.compile(br'''coding[:=]\s*([-\w_.]+)''')), - (1, re.compile(br'''<\?xml.*\bencoding\s*=\s*['"]([-\w_.]+)['"]\?>''')), + (5, re.compile(rb"""coding[:=]\s*([-\w_.]+)""")), + (1, re.compile(rb"""<\?xml.*\bencoding\s*=\s*['"]([-\w_.]+)['"]\?>""")), ] coding_regexps = [ - (5, re.compile(r'''coding[:=]\s*([-\w_.]+)''')), - (1, re.compile(r'''<\?xml.*\bencoding\s*=\s*['"]([-\w_.]+)['"]\?>''')), + (5, re.compile(r"""coding[:=]\s*([-\w_.]+)""")), + (1, re.compile(r"""<\?xml.*\bencoding\s*=\s*['"]([-\w_.]+)['"]\?>""")), ] supportedCodecs = [ - 'utf-8', - - 'iso-8859-1', 'iso-8859-2', 'iso-8859-3', - 'iso-8859-4', 'iso-8859-5', 'iso-8859-6', 'iso-8859-7', - 'iso-8859-8', 'iso-8859-9', 'iso-8859-10', 'iso-8859-11', - 'iso-8859-13', 'iso-8859-14', 'iso-8859-15', 'iso-8859-16', - 'latin-1', - - 'koi8-r', 'koi8-t', 'koi8-u', - - 'utf-7', - 'utf-16', 'utf-16-be', 'utf-16-le', - 'utf-32', 'utf-32-be', 'utf-32-le', - - 'cp037', 'cp273', 'cp424', 'cp437', 'cp500', 'cp720', - 'cp737', 'cp775', 'cp850', 'cp852', 'cp855', 'cp856', - 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', 'cp863', - 'cp864', 'cp865', 'cp866', 'cp869', 'cp874', 'cp875', - 'cp932', 'cp949', 'cp950', 'cp1006', 'cp1026', 'cp1125', - 'cp1140', - - 'windows-1250', 'windows-1251', 'windows-1252', 'windows-1253', - 'windows-1254', 'windows-1255', 'windows-1256', 'windows-1257', - 'windows-1258', - - 'gb2312', 'hz', 'gb18030', 'gbk', - - 'iso-2022-jp', 'iso-2022-jp-1', 'iso-2022-jp-2', 'iso-2022-jp-2004', - 'iso-2022-jp-3', 'iso-2022-jp-ext', 'iso-2022-kr', - - 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', - 'mac-roman', 'mac-turkish', - - 'ascii', - 'big5-tw', 'big5-hkscs', + "utf-8", + "iso-8859-1", + "iso-8859-2", + "iso-8859-3", + "iso-8859-4", + "iso-8859-5", + "iso-8859-6", + "iso-8859-7", + "iso-8859-8", + "iso-8859-9", + "iso-8859-10", + "iso-8859-11", + "iso-8859-13", + "iso-8859-14", + "iso-8859-15", + "iso-8859-16", + "latin-1", + "koi8-r", + "koi8-t", + "koi8-u", + "utf-7", + "utf-16", + "utf-16-be", + "utf-16-le", + "utf-32", + "utf-32-be", + "utf-32-le", + "cp037", + "cp273", + "cp424", + "cp437", + "cp500", + "cp720", + "cp737", + "cp775", + "cp850", + "cp852", + "cp855", + "cp856", + "cp857", + "cp858", + "cp860", + "cp861", + "cp862", + "cp863", + "cp864", + "cp865", + "cp866", + "cp869", + "cp874", + "cp875", + "cp932", + "cp949", + "cp950", + "cp1006", + "cp1026", + "cp1125", + "cp1140", + "windows-1250", + "windows-1251", + "windows-1252", + "windows-1253", + "windows-1254", + "windows-1255", + "windows-1256", + "windows-1257", + "windows-1258", + "gb2312", + "hz", + "gb18030", + "gbk", + "iso-2022-jp", + "iso-2022-jp-1", + "iso-2022-jp-2", + "iso-2022-jp-2004", + "iso-2022-jp-3", + "iso-2022-jp-ext", + "iso-2022-kr", + "mac-cyrillic", + "mac-greek", + "mac-iceland", + "mac-latin2", + "mac-roman", + "mac-turkish", + "ascii", + "big5-tw", + "big5-hkscs", ] @@ -125,44 +194,45 @@ Class implementing an exception, which is raised, if a given coding is incorrect. """ + def __init__(self, coding): """ Constructor - + @param coding coding to include in the message (string) """ self.errorMessage = QCoreApplication.translate( - "CodingError", - "The coding '{0}' is wrong for the given text.").format(coding) - + "CodingError", "The coding '{0}' is wrong for the given text." + ).format(coding) + def __repr__(self): """ Special method returning a representation of the exception. - + @return string representing the error message """ return str(self.errorMessage) - + def __str__(self): """ Special method returning a string representation of the exception. - + @return string representing the error message """ return str(self.errorMessage) - + def get_codingBytes(text): """ Function to get the coding of a bytes text. - + @param text bytes text to inspect (bytes) @return coding string """ lines = text.splitlines() for coding in codingBytes_regexps: coding_re = coding[1] - head = lines[:coding[0]] + head = lines[: coding[0]] for line in head: m = coding_re.search(line) if m: @@ -173,14 +243,14 @@ def get_coding(text): """ Function to get the coding of a text. - + @param text text to inspect (string) @return coding string """ lines = text.splitlines() for coding in coding_regexps: coding_re = coding[1] - head = lines[:coding[0]] + head = lines[: coding[0]] for line in head: m = coding_re.search(line) if m: @@ -191,7 +261,7 @@ def readEncodedFile(filename): """ Function to read a file and decode its contents into proper text. - + @param filename name of the file to read (string) @return tuple of decoded text and encoding (string, string) """ @@ -204,85 +274,85 @@ """ Function to read a file, calculate a hash value and decode its contents into proper text. - + @param filename name of the file to read (string) @return tuple of decoded text, encoding and hash value (string, string, string) """ with open(filename, "rb") as f: text = f.read() - hashStr = str(QCryptographicHash.hash( - QByteArray(text), QCryptographicHash.Algorithm.Md5).toHex(), - encoding="ASCII") - return decode(text) + (hashStr, ) + hashStr = str( + QCryptographicHash.hash( + QByteArray(text), QCryptographicHash.Algorithm.Md5 + ).toHex(), + encoding="ASCII", + ) + return decode(text) + (hashStr,) def decode(text): """ Function to decode some byte text into a string. - + @param text byte text to decode (bytes) @return tuple of decoded text and encoding (string, string) """ with contextlib.suppress(UnicodeError, LookupError): if text.startswith(BOM_UTF8): # UTF-8 with BOM - return str(text[len(BOM_UTF8):], 'utf-8'), 'utf-8-bom' + return str(text[len(BOM_UTF8) :], "utf-8"), "utf-8-bom" elif text.startswith(BOM_UTF16): # UTF-16 with BOM - return str(text[len(BOM_UTF16):], 'utf-16'), 'utf-16' + return str(text[len(BOM_UTF16) :], "utf-16"), "utf-16" elif text.startswith(BOM_UTF32): # UTF-32 with BOM - return str(text[len(BOM_UTF32):], 'utf-32'), 'utf-32' + return str(text[len(BOM_UTF32) :], "utf-32"), "utf-32" coding = get_codingBytes(text) if coding: return str(text, coding), coding - + # Assume UTF-8 with contextlib.suppress(UnicodeError, LookupError): - return str(text, 'utf-8'), 'utf-8-guessed' - + return str(text, "utf-8"), "utf-8-guessed" + guess = None if Preferences.getEditor("AdvancedEncodingDetection"): # Try the universal character encoding detector try: import chardet + guess = chardet.detect(text) - if ( - guess and - guess['confidence'] > 0.95 and - guess['encoding'] is not None - ): - codec = guess['encoding'].lower() - return str(text, codec), '{0}-guessed'.format(codec) + if guess and guess["confidence"] > 0.95 and guess["encoding"] is not None: + codec = guess["encoding"].lower() + return str(text, codec), "{0}-guessed".format(codec) except (UnicodeError, LookupError): pass except ImportError: pass - + # Try default encoding with contextlib.suppress(UnicodeError, LookupError): codec = Preferences.getEditor("DefaultEncoding") - return str(text, codec), '{0}-default'.format(codec) - + return str(text, codec), "{0}-default".format(codec) + if ( - Preferences.getEditor("AdvancedEncodingDetection") and - guess and - guess['encoding'] is not None + Preferences.getEditor("AdvancedEncodingDetection") + and guess + and guess["encoding"] is not None ): # Use the guessed one even if confidence level is low with contextlib.suppress(UnicodeError, LookupError): - codec = guess['encoding'].lower() - return str(text, codec), '{0}-guessed'.format(codec) - + codec = guess["encoding"].lower() + return str(text, codec), "{0}-guessed".format(codec) + # Assume UTF-8 loosing information - return str(text, "utf-8", "ignore"), 'utf-8-ignore' + return str(text, "utf-8", "ignore"), "utf-8-ignore" def readEncodedFileWithEncoding(filename, encoding): """ Function to read a file and decode its contents into proper text. - + @param filename name of the file to read (string) @param encoding encoding to be used to read the file (string) @return tuple of decoded text and encoding (string, string) @@ -291,15 +361,15 @@ text = f.read() if encoding: with contextlib.suppress(UnicodeError, LookupError): - return str(text, encoding), '{0}-selected'.format(encoding) - + return str(text, encoding), "{0}-selected".format(encoding) + # Try default encoding with contextlib.suppress(UnicodeError, LookupError): codec = Preferences.getEditor("DefaultEncoding") - return str(text, codec), '{0}-default'.format(codec) - + return str(text, codec), "{0}-default".format(codec) + # Assume UTF-8 loosing information - return str(text, "utf-8", "ignore"), 'utf-8-ignore' + return str(text, "utf-8", "ignore"), "utf-8-ignore" else: return decode(text) @@ -307,7 +377,7 @@ def writeEncodedFile(filename, text, origEncoding, forcedEncoding=""): """ Function to write a file with properly encoded text. - + @param filename name of the file to read @type str @param text text to be written @@ -321,17 +391,17 @@ @rtype str """ etext, encoding = encode(text, origEncoding, forcedEncoding=forcedEncoding) - + with open(filename, "wb") as f: f.write(etext) - + return encoding def encode(text, origEncoding, forcedEncoding=""): """ Function to encode text into a byte text. - + @param text text to be encoded @type str @param origEncoding type of the original encoding @@ -344,8 +414,8 @@ @exception CodingError raised to indicate an invalid encoding """ encoding = None - if origEncoding == 'utf-8-bom': - etext, encoding = BOM_UTF8 + text.encode("utf-8"), 'utf-8-bom' + if origEncoding == "utf-8-bom": + etext, encoding = BOM_UTF8 + text.encode("utf-8"), "utf-8-bom" else: # Try declared coding spec coding = get_coding(text) @@ -358,46 +428,45 @@ else: if forcedEncoding: with contextlib.suppress(UnicodeError, LookupError): - etext, encoding = ( - text.encode(forcedEncoding), forcedEncoding) + etext, encoding = (text.encode(forcedEncoding), forcedEncoding) # if forced encoding is incorrect, ignore it - + if encoding is None: # Try the original encoding if origEncoding and origEncoding.endswith( - ('-selected', '-default', '-guessed', '-ignore')): + ("-selected", "-default", "-guessed", "-ignore") + ): coding = ( - origEncoding - .replace("-selected", "") + origEncoding.replace("-selected", "") .replace("-default", "") .replace("-guessed", "") .replace("-ignore", "") ) with contextlib.suppress(UnicodeError, LookupError): etext, encoding = text.encode(coding), coding - + if encoding is None: # Try configured default with contextlib.suppress(UnicodeError, LookupError): codec = Preferences.getEditor("DefaultEncoding") etext, encoding = text.encode(codec), codec - + if encoding is None: # Try saving as ASCII with contextlib.suppress(UnicodeError): - etext, encoding = text.encode('ascii'), 'ascii' - + etext, encoding = text.encode("ascii"), "ascii" + if encoding is None: # Save as UTF-8 without BOM - etext, encoding = text.encode('utf-8'), 'utf-8' - + etext, encoding = text.encode("utf-8"), "utf-8" + return etext, encoding def decodeString(text): """ Function to decode a string containing Unicode encoded characters. - + @param text text containing encoded chars (string) @return decoded text (string) """ @@ -405,7 +474,7 @@ index = 0 while index < len(text): if text[index] == "\\": - qb = QByteArray.fromHex(text[index:index + 4].encode()) + qb = QByteArray.fromHex(text[index : index + 4].encode()) buf += bytes(qb) index += 4 else: @@ -413,12 +482,12 @@ index += 1 buf = buf.replace(b"\x00", b"") return decodeBytes(buf) - + def decodeBytes(buffer): """ Function to decode some byte text into a string. - + @param buffer byte buffer to decode (bytes) @return decoded text (string) """ @@ -426,44 +495,45 @@ with contextlib.suppress(UnicodeError, LookupError): if buffer.startswith(BOM_UTF8): # UTF-8 with BOM - return str(buffer[len(BOM_UTF8):], encoding='utf-8') + return str(buffer[len(BOM_UTF8) :], encoding="utf-8") elif buffer.startswith(BOM_UTF16): # UTF-16 with BOM - return str(buffer[len(BOM_UTF16):], encoding='utf-16') + return str(buffer[len(BOM_UTF16) :], encoding="utf-16") elif buffer.startswith(BOM_UTF32): # UTF-32 with BOM - return str(buffer[len(BOM_UTF32):], encoding='utf-32') - + return str(buffer[len(BOM_UTF32) :], encoding="utf-32") + # try UTF-8 with contextlib.suppress(UnicodeError): return str(buffer, encoding="utf-8") - + # try codec detection try: import chardet + guess = chardet.detect(buffer) - if guess and guess['encoding'] is not None: - codec = guess['encoding'].lower() + if guess and guess["encoding"] is not None: + codec = guess["encoding"].lower() return str(buffer, encoding=codec) except (UnicodeError, LookupError): pass except ImportError: pass - + return str(buffer, encoding="utf-8", errors="ignore") def readStringFromStream(stream): """ Module function to read a string from the given stream. - + @param stream data stream opened for reading (QDataStream) @return string read from the stream (string) """ data = stream.readString() if data is None: data = b"" - return data.decode('utf-8') + return data.decode("utf-8") _escape = re.compile("[&<>\"'\u0080-\uffff]") @@ -480,7 +550,7 @@ def escape_entities(m, escmap=_escape_map): """ Function to encode html entities. - + @param m the match object @param escmap the map of entities to encode @return the converted text (string) @@ -490,12 +560,12 @@ if text is None: text = "&#{0:d};".format(ord(char)) return text - + def html_encode(text, pattern=_escape): """ Function to correctly encode a text for html. - + @param text text to be encoded (string) @param pattern search pattern for text to be encoded (string) @return the encoded text (string) @@ -505,25 +575,26 @@ text = pattern.sub(escape_entities, text) return text -_uescape = re.compile('[\u0080-\uffff]') + +_uescape = re.compile("[\u0080-\uffff]") def escape_uentities(m): """ Function to encode html entities. - + @param m the match object @return the converted text (string) """ char = m.group() text = "&#{0:d};".format(ord(char)) return text - + def html_uencode(text, pattern=_uescape): """ Function to correctly encode a unicode text for html. - + @param text text to be encoded (string) @param pattern search pattern for text to be encoded (string) @return the encoded text (string) @@ -533,13 +604,14 @@ text = pattern.sub(escape_uentities, text) return text -_uunescape = re.compile(r'&#\d+;') + +_uunescape = re.compile(r"&#\d+;") def unescape_uentities(m): """ Function to decode html entities. - + @param m the match object @return the converted text (string) """ @@ -551,7 +623,7 @@ def html_udecode(text, pattern=_uunescape): """ Function to correctly decode a html text to a unicode text. - + @param text text to be decoded (string) @param pattern search pattern for text to be decoded (string) @return the decoded text (string) @@ -565,20 +637,20 @@ def convertLineEnds(text, eol): """ Function to convert the end of line characters. - + @param text text to be converted (string) @param eol new eol setting (string) @return text with converted eols (string) """ - if eol == '\r\n': + if eol == "\r\n": regexp = re.compile(r"""(\r(?!\n)|(?<!\r)\n)""") - return regexp.sub(lambda m, eol='\r\n': eol, text) - elif eol == '\n': + return regexp.sub(lambda m, eol="\r\n": eol, text) + elif eol == "\n": regexp = re.compile(r"""(\r\n|\r)""") - return regexp.sub(lambda m, eol='\n': eol, text) - elif eol == '\r': + return regexp.sub(lambda m, eol="\n": eol, text) + elif eol == "\r": regexp = re.compile(r"""(\r\n|\n)""") - return regexp.sub(lambda m, eol='\r': eol, text) + return regexp.sub(lambda m, eol="\r": eol, text) else: return text @@ -586,7 +658,7 @@ def linesep(): """ Function to return the line separator used by the editor. - + @return line separator used by the editor (string) """ eolMode = Preferences.getEditor("EOLMode") @@ -601,7 +673,7 @@ def extractFlags(text): """ Function to extract eric specific flags out of the given text. - + Flags are contained in comments and are introduced by 'eflag:'. The rest of the line is interpreted as 'key = value'. value is analyzed for being an integer or float value. If that fails, it @@ -609,7 +681,7 @@ character, it is assumed to be a boolean flag. Flags are expected at the very end of a file. The search is ended, if a line without the 'eflag:' marker is found. - + @param text text to be scanned (string) @return dictionary of string, boolean, complex, float and int """ @@ -621,18 +693,18 @@ except ValueError: # no flag found, don't look any further break - - flag = line[index + 6:].strip() + + flag = line[index + 6 :].strip() if "=" in flag: key, value = flag.split("=", 1) key = key.strip() value = value.strip() - + if value.lower() in ["true", "false", "yes", "no", "ok"]: # it is a flag flags[key] = value.lower() in ["true", "yes", "ok"] continue - + try: # interpret as int first value = int(value) @@ -640,7 +712,7 @@ with contextlib.suppress(ValueError): # interpret as float next value = float(value) - + flags[key] = value else: # treat it as a boolean @@ -649,14 +721,14 @@ flags[flag[1:]] = False else: flags[flag] = True - + return flags def extractFlagsFromFile(filename): """ Function to extract eric specific flags out of the given file. - + @param filename name of the file to be scanned (string) @return dictionary of string, boolean, complex, float and int """ @@ -664,7 +736,7 @@ source, encoding = readEncodedFile(filename) except (UnicodeError, OSError): return {} - + return extractFlags(source) @@ -672,7 +744,7 @@ """ Function to extract flags starting and ending with '__' from a line comment. - + @param line line to extract flags from (string) @param startComment string identifying the start of the comment (string) @param endComment string identifying the end of a comment (string) @@ -680,25 +752,27 @@ @return list containing the extracted flags (list of strings) """ flags = [] - - if not flagsLine or ( - flagsLine and line.strip().startswith(startComment)): + + if not flagsLine or (flagsLine and line.strip().startswith(startComment)): pos = line.rfind(startComment) if pos >= 0: - comment = line[pos + len(startComment):].strip() + comment = line[pos + len(startComment) :].strip() if endComment: endPos = line.rfind(endComment) if endPos >= 0: comment = comment[:endPos] - flags = [f.strip() for f in comment.split() - if (f.startswith("__") and f.endswith("__"))] + flags = [ + f.strip() + for f in comment.split() + if (f.startswith("__") and f.endswith("__")) + ] return flags def filterAnsiSequences(txt): """ Function to filter out ANSI escape sequences (color only). - + @param txt text to be filtered @type str @return text without ANSI escape sequences @@ -706,21 +780,21 @@ """ ntxt = txt[:] while True: - start = ntxt.find("\33[") # find escape character + start = ntxt.find("\33[") # find escape character if start == -1: break end = ntxt.find("m", start) if end == -1: break - ntxt = ntxt[:start] + ntxt[end + 1:] - + ntxt = ntxt[:start] + ntxt[end + 1 :] + return ntxt def toNativeSeparators(path): """ Function returning a path, that is using native separator characters. - + @param path path to be converted @type str @return path with converted separator characters @@ -732,7 +806,7 @@ def fromNativeSeparators(path): """ Function returning a path, that is using "/" separator characters. - + @param path path to be converted @type str @return path with converted separator characters @@ -745,7 +819,7 @@ """ Function returning a path, that is normalized with respect to its case and references. - + @param path file path (string) @return case normalized path (string) """ @@ -756,7 +830,7 @@ """ Function returning an absolute path, that is normalized with respect to its case and references. - + @param path file path (string) @return absolute, normalized path (string) """ @@ -766,7 +840,7 @@ def normjoinpath(a, *p): """ Function returning a normalized path of the joined parts passed into it. - + @param a first path to be joined (string) @param p variable number of path parts to be joined (string) @return normalized path (string) @@ -778,7 +852,7 @@ """ Function returning a normalized, absolute path of the joined parts passed into it. - + @param a first path to be joined (string) @param p variable number of path parts to be joind (string) @return absolute, normalized path (string) @@ -789,32 +863,31 @@ def isinpath(file): """ Function to check for an executable file. - + @param file filename of the executable to check (string) @return flag to indicate, if the executable file is accessible via the searchpath defined by the PATH environment variable. """ if os.path.isabs(file): return os.access(file, os.X_OK) - + if os.path.exists(os.path.join(os.curdir, file)): return os.access(os.path.join(os.curdir, file), os.X_OK) - - path = getEnvironmentEntry('PATH') - + + path = getEnvironmentEntry("PATH") + # environment variable not defined if path is None: return False - + dirs = path.split(os.pathsep) - return any(os.access(os.path.join(directory, file), os.X_OK) - for directory in dirs) + return any(os.access(os.path.join(directory, file), os.X_OK) for directory in dirs) def startswithPath(path, start): """ Function to check, if a path starts with a given start path. - + @param path path to be checked @type str @param start start path @@ -823,12 +896,8 @@ path @rtype bool """ - return ( - bool(start) and - ( - path == start or - normcasepath(path).startswith(normcasepath(start + "/")) - ) + return bool(start) and ( + path == start or normcasepath(path).startswith(normcasepath(start + "/")) ) @@ -836,7 +905,7 @@ """ Function to convert a file path to a path relative to a start path with universal separators. - + @param path file or directory name to convert (string) @param start start path (string) @return relative path or unchanged path, if path does not start with @@ -849,7 +918,7 @@ """ Public method to convert a path relative to a start path to an absolute path. - + @param path file or directory name to convert (string) @param start start path (string) @return absolute path (string) @@ -863,7 +932,7 @@ """ Public method to convert a path relative to a start path with universal separators to an absolute path. - + @param path file or directory name to convert (string) @param start start path (string) @return absolute path with native separators (string) @@ -876,7 +945,7 @@ def getExecutablePath(file): """ Function to build the full path of an executable file from the environment. - + @param file filename of the executable to check (string) @return full executable name, if the executable file is accessible via the searchpath defined by the PATH environment variable, or an @@ -887,49 +956,49 @@ return file else: return "" - + cur_path = os.path.join(os.curdir, file) if os.path.exists(cur_path) and os.access(cur_path, os.X_OK): return cur_path - path = os.getenv('PATH') - + path = os.getenv("PATH") + # environment variable not defined if path is None: return "" - + dirs = path.split(os.pathsep) for directory in dirs: exe = os.path.join(directory, file) if os.access(exe, os.X_OK): return exe - + return "" - + def getExecutablePaths(file): """ Function to build all full path of an executable file from the environment. - + @param file filename of the executable (string) @return list of full executable names (list of strings), if the executable file is accessible via the searchpath defined by the PATH environment variable, or an empty list otherwise. """ paths = [] - + if os.path.isabs(file): if os.access(file, os.X_OK): return [file] else: return [] - + cur_path = os.path.join(os.curdir, file) if os.path.exists(cur_path) and os.access(cur_path, os.X_OK): paths.append(cur_path) - path = os.getenv('PATH') - + path = os.getenv("PATH") + # environment variable not defined if path is not None: dirs = path.split(os.pathsep) @@ -937,19 +1006,19 @@ exe = os.path.join(directory, file) if os.access(exe, os.X_OK) and exe not in paths: paths.append(exe) - + return paths - + def getWindowsExecutablePath(file): """ Function to build the full path of an executable file from the environment on Windows platforms. - + First an executable with the extension .exe is searched for, thereafter such with the extensions .cmd or .bat and finally the given file name as is. The first match is returned. - + @param file filename of the executable to check (string) @return full executable name, if the executable file is accessible via the searchpath defined by the PATH environment variable, or an @@ -960,34 +1029,34 @@ return file else: return "" - + filenames = [file + ".exe", file + ".cmd", file + ".bat", file] - + for filename in filenames: cur_path = os.path.join(os.curdir, filename) if os.path.exists(cur_path) and os.access(cur_path, os.X_OK): return os.path.abspath(cur_path) - path = os.getenv('PATH') - + path = os.getenv("PATH") + # environment variable not defined if path is None: return "" - + dirs = path.split(os.pathsep) for directory in dirs: for filename in filenames: exe = os.path.join(directory, filename) if os.access(exe, os.X_OK): return exe - + return "" - + def isExecutable(exe): """ Function to check, if a file is executable. - + @param exe filename of the executable to check (string) @return flag indicating executable status (boolean) """ @@ -997,7 +1066,7 @@ def isDrive(path): """ Function to check, if a path is a Windows drive. - + @param path path name to be checked @type str @return flag indicating a Windows drive @@ -1006,20 +1075,20 @@ isDrive = False drive, directory = os.path.splitdrive(path) if ( - drive and - len(drive) == 2 and - drive.endswith(":") and - directory in ["", "\\", "/"] + drive + and len(drive) == 2 + and drive.endswith(":") + and directory in ["", "\\", "/"] ): isDrive = True - + return isDrive - + def samepath(f1, f2): """ Function to compare two paths. - + @param f1 first path for the compare (string) @param f2 second path for the compare (string) @return flag indicating whether the two paths represent the @@ -1027,20 +1096,17 @@ """ if f1 is None or f2 is None: return False - - if ( - normcaseabspath(os.path.realpath(f1)) == - normcaseabspath(os.path.realpath(f2)) - ): + + if normcaseabspath(os.path.realpath(f1)) == normcaseabspath(os.path.realpath(f2)): return True - + return False def samefilepath(f1, f2): """ Function to compare two paths. Strips the filename. - + @param f1 first filepath for the compare (string) @param f2 second filepath for the compare (string) @return flag indicating whether the two paths represent the @@ -1048,13 +1114,15 @@ """ if f1 is None or f2 is None: return False - - if (normcaseabspath(os.path.dirname(os.path.realpath(f1))) == - normcaseabspath(os.path.dirname(os.path.realpath(f2)))): + + if normcaseabspath(os.path.dirname(os.path.realpath(f1))) == normcaseabspath( + os.path.dirname(os.path.realpath(f2)) + ): return True - + return False + try: EXTSEP = os.extsep except AttributeError: @@ -1064,7 +1132,7 @@ def splitPath(name): """ Function to split a pathname into a directory part and a file part. - + @param name path name (string) @return a tuple of 2 strings (dirname, filename). """ @@ -1079,10 +1147,10 @@ def joinext(prefix, ext): """ Function to join a file extension to a path. - + The leading "." of ext is replaced by a platform specific extension separator if necessary. - + @param prefix the basepart of the filename (string) @param ext the extension part (string) @return the complete filename (string) @@ -1096,7 +1164,7 @@ def compactPath(path, width, measure=len): """ Function to return a compacted path fitting inside the given width. - + @param path path to be compacted (string) @param width width for the compacted path (integer) @param measure reference to a function used to measure the length of the @@ -1105,9 +1173,9 @@ """ if measure(path) <= width: return path - - ellipsis = '...' - + + ellipsis = "..." + head, tail = os.path.split(path) mid = len(head) // 2 head1 = head[:mid] @@ -1128,13 +1196,14 @@ return path tail = tail[1:] return "" - + -def direntries(path, filesonly=False, pattern=None, followsymlinks=True, - checkStop=None): +def direntries( + path, filesonly=False, pattern=None, followsymlinks=True, checkStop=None +): """ Function returning a list of all files and directories. - + @param path root of the tree to check @type str @param filesonly flag indicating that only files are wanted @@ -1158,29 +1227,32 @@ for entry in entries: if checkStop and checkStop(): break - - if entry in ['.svn', - '.hg', - '.git', - '.ropeproject', - '.eric7project', - '.jedi']: + + if entry in [ + ".svn", + ".hg", + ".git", + ".ropeproject", + ".eric7project", + ".jedi", + ]: continue - + fentry = os.path.join(path, entry) if ( - pattern and - not os.path.isdir(fentry) and - not any(fnmatch.fnmatch(entry, p) for p in patterns) + pattern + and not os.path.isdir(fentry) + and not any(fnmatch.fnmatch(entry, p) for p in patterns) ): # entry doesn't fit the given pattern continue - + if os.path.isdir(fentry): if os.path.islink(fentry) and not followsymlinks: continue files += direntries( - fentry, filesonly, pattern, followsymlinks, checkStop) + fentry, filesonly, pattern, followsymlinks, checkStop + ) else: files.append(fentry) except OSError: @@ -1193,7 +1265,7 @@ def getDirs(path, excludeDirs): """ Function returning a list of all directories below path. - + @param path root of the tree to check @param excludeDirs basename of directories to ignore @return list of all directories found @@ -1205,9 +1277,8 @@ dirs = [] for name in names: - if ( - os.path.isdir(os.path.join(path, name)) and - not os.path.islink(os.path.join(path, name)) + if os.path.isdir(os.path.join(path, name)) and not os.path.islink( + os.path.join(path, name) ): exclude = 0 for e in excludeDirs: @@ -1227,7 +1298,7 @@ def findVolume(volumeName, findAll=False): """ Function to find the directory belonging to a given volume name. - + @param volumeName name of the volume to search for @type str @param findAll flag indicating to get the directories for all volumes @@ -1239,13 +1310,13 @@ """ volumeDirectories = [] volumeDirectory = None - + if isWindowsPlatform(): # we are on a Windows platform def getVolumeName(diskName): """ Local function to determine the volume of a disk or device. - + Each disk or external device connected to windows has an attribute called "volume name". This function returns the volume name for the given disk/device. @@ -1254,10 +1325,17 @@ """ volumeNameBuffer = ctypes.create_unicode_buffer(1024) ctypes.windll.kernel32.GetVolumeInformationW( - ctypes.c_wchar_p(diskName), volumeNameBuffer, - ctypes.sizeof(volumeNameBuffer), None, None, None, None, 0) + ctypes.c_wchar_p(diskName), + volumeNameBuffer, + ctypes.sizeof(volumeNameBuffer), + None, + None, + None, + None, + 0, + ) return volumeNameBuffer.value - + # # In certain circumstances, volumes are allocated to USB # storage devices which cause a Windows popup to raise if their @@ -1282,12 +1360,11 @@ # we are on a Linux or macOS platform for mountCommand in ["mount", "/sbin/mount", "/usr/sbin/mount"]: with contextlib.suppress(FileNotFoundError): - mountOutput = subprocess.run( # secok + mountOutput = subprocess.run( # secok mountCommand, check=True, capture_output=True, text=True ).stdout.splitlines() mountedVolumes = [ - x.split(" type")[0].split(maxsplit=2)[2] - for x in mountOutput + x.split(" type")[0].split(maxsplit=2)[2] for x in mountOutput ] if findAll: for volume in mountedVolumes: @@ -1302,7 +1379,7 @@ break if volumeDirectory: break - + if findAll: return volumeDirectories else: @@ -1312,11 +1389,11 @@ def getTestFileNames(fn): """ Function to build the potential file names of a test file. - + The file names for the test file is built by prepending the string "test" and "test_" to the file name passed into this function and by appending the string "_test". - + @param fn file name basis to be used for the test file names @type str @return file names of the corresponding test file @@ -1327,18 +1404,16 @@ prefixes = ["test", "test_"] postfixes = ["_test"] return [ - os.path.join(dn, "{0}{1}{2}".format(prefix, fn, ext)) - for prefix in prefixes + os.path.join(dn, "{0}{1}{2}".format(prefix, fn, ext)) for prefix in prefixes ] + [ - os.path.join(dn, "{0}{1}{2}".format(fn, postfix, ext)) - for postfix in postfixes + os.path.join(dn, "{0}{1}{2}".format(fn, postfix, ext)) for postfix in postfixes ] def getCoverageFileNames(fn): """ Function to build a list of coverage data file names. - + @param fn file name basis to be used for the coverage data file @type str @return list of existing coverage data files @@ -1355,7 +1430,7 @@ def getCoverageFileName(fn, mustExist=True): """ Function to build a file name for a coverage data file. - + @param fn file name basis to be used for the coverage data file name @type str @param mustExist flag indicating to check that the file exists (defaults @@ -1378,7 +1453,7 @@ def getProfileFileNames(fn): """ Function to build a list of profile data file names. - + @param fn file name basis to be used for the profile data file @type str @return list of existing profile data files @@ -1395,7 +1470,7 @@ def getProfileFileName(fn, mustExist=True): """ Function to build a file name for a profile data file. - + @param fn file name basis to be used for the profile data file name @type str @param mustExist flag indicating to check that the file exists (defaults @@ -1418,7 +1493,7 @@ def parseOptionString(s): """ Function used to convert an option string into a list of options. - + @param s option string @type str @return list of options @@ -1431,19 +1506,19 @@ def _percentReplacementFunc(matchobj): """ Protected function called for replacing % codes. - + @param matchobj match object for the code @type re.Match @return replacement string @rtype str """ return getPercentReplacement(matchobj.group(0)) - + def getPercentReplacement(code): """ Function to get the replacement for code. - + @param code code indicator @type str @return replacement string @@ -1517,12 +1592,12 @@ else: # unknown code, just return it return code - + def getPercentReplacementHelp(): """ Function to get the help text for the supported %-codes. - + @returns help text (string) """ return QCoreApplication.translate( @@ -1542,33 +1617,35 @@ """<tr><td>%U</td><td>username of the current user</td></tr>""" """<tr><td>%%</td><td>the percent sign</td></tr>""" """</table>""" - """</p>""") + """</p>""", + ) def getUserName(): """ Function to get the user name. - + @return user name (string) """ user = getpass.getuser() - + if isWindowsPlatform() and not user: return win32_GetUserName() - + return user def getRealName(): """ Function to get the real name of the user. - + @return real name of the user (string) """ if isWindowsPlatform(): return win32_getRealName() else: import pwd + user = getpass.getuser() return pwd.getpwnam(user).pw_gecos @@ -1576,16 +1653,16 @@ def getHomeDir(): """ Function to get a users home directory. - + @return home directory (string) """ return QDir.homePath() - + def getPythonLibPath(): """ Function to determine the path to Python's library. - + @return path to the Python library (string) """ pyFullVers = sys.version.split()[0] @@ -1604,14 +1681,14 @@ except AttributeError: syslib = "lib" libDir = sys.prefix + "/" + syslib + "/python" + pyVers - + return libDir - + def getPythonVersion(): """ Function to get the Python version (major, minor) as an integer value. - + @return An integer representing major and minor version number (integer) """ return sys.hexversion >> 16 @@ -1620,7 +1697,7 @@ def determinePythonVersion(filename, source, editor=None): """ Function to determine the python version of a given file. - + @param filename name of the file with extension (str) @param source of the file (str) @param editor reference to the editor, if the file is opened @@ -1632,11 +1709,11 @@ "MicroPython": 3, "Cython": 3, } - + if not editor: - viewManager = ericApp().getObject('ViewManager') + viewManager = ericApp().getObject("ViewManager") editor = viewManager.getOpenEditor(filename) - + # Maybe the user has changed the language if editor and editor.getFileType() in pyAssignment: return pyAssignment[editor.getFileType()] @@ -1648,25 +1725,27 @@ flags = extractFlags(source) ext = os.path.splitext(filename)[1] py3Ext = Preferences.getPython("Python3Extensions") - project = ericApp().getObject('Project') + project = ericApp().getObject("Project") basename = os.path.basename(filename) - + if "FileType" in flags: pyVer = pyAssignment.get(flags["FileType"], 0) elif project.isOpen() and project.isProjectFile(filename): language = project.getEditorLexerAssoc(basename) if not language: language = Preferences.getEditorLexerAssoc(basename) - if language == 'Python3': + if language == "Python3": pyVer = pyAssignment[language] - + if pyVer: # Skip the next tests pass - elif (Preferences.getProject("DeterminePyFromProject") and - project.isOpen() and - project.isProjectFile(filename) and - ext in py3Ext): + elif ( + Preferences.getProject("DeterminePyFromProject") + and project.isOpen() + and project.isProjectFile(filename) + and ext in py3Ext + ): pyVer = pyAssignment.get(project.getProjectLanguage(), 0) elif ext in py3Ext: pyVer = 3 @@ -1675,15 +1754,12 @@ line0 = source.splitlines()[0] else: line0 = source[0] - if ( - line0.startswith("#!") and - (("python3" in line0) or ("python" in line0)) - ): + if line0.startswith("#!") and (("python3" in line0) or ("python" in line0)): pyVer = 3 - + if pyVer == 0 and ext in py3Ext: pyVer = 3 - + return pyVer @@ -1691,7 +1767,7 @@ """ Function to get the index (start position) of a regular expression match within some text. - + @param rx regular expression object as created by re.compile() @type re.Pattern @param txt text to be scanned @@ -1714,7 +1790,7 @@ def getEnvironmentEntry(key, default=None): """ Module function to get an environment entry. - + @param key key of the requested environment entry (string) @param default value to be returned, if the environment doesn't contain the requested entry (string) @@ -1724,15 +1800,16 @@ pattern = "^{0}[ \t]*=".format(key) filterRe = ( re.compile(pattern, re.IGNORECASE) - if isWindowsPlatform() else - re.compile(pattern) + if isWindowsPlatform() + else re.compile(pattern) ) - - entries = [e for e in QProcess.systemEnvironment() - if filterRe.search(e) is not None] + + entries = [ + e for e in QProcess.systemEnvironment() if filterRe.search(e) is not None + ] if not entries: return default - + # if there are multiple entries, just consider the first one ename, value = entries[0].split("=", 1) return value.strip() @@ -1741,7 +1818,7 @@ def hasEnvironmentEntry(key): """ Module function to check, if the environment contains an entry. - + @param key key of the requested environment entry @type str @return flag indicating the presence of the requested entry @@ -1750,14 +1827,16 @@ pattern = "^{0}[ \t]*=".format(key) filterRe = ( re.compile(pattern, re.IGNORECASE) - if isWindowsPlatform() else - re.compile(pattern) + if isWindowsPlatform() + else re.compile(pattern) ) - - entries = [e for e in QProcess.systemEnvironment() - if filterRe.search(e) is not None] + + entries = [ + e for e in QProcess.systemEnvironment() if filterRe.search(e) is not None + ] return len(entries) > 0 + ############################################################################### ## Qt utility functions below ############################################################################### @@ -1767,40 +1846,41 @@ """ Module function to generate the executable name for a Qt tool like designer. - + @param toolname base name of the tool (string) @return the Qt tool name without extension (string) """ - return "{0}{1}{2}".format(Preferences.getQt("QtToolsPrefix"), - toolname, - Preferences.getQt("QtToolsPostfix") - ) + return "{0}{1}{2}".format( + Preferences.getQt("QtToolsPrefix"), + toolname, + Preferences.getQt("QtToolsPostfix"), + ) def getQtMacBundle(toolname): """ Module function to determine the correct Mac OS X bundle name for Qt tools. - + @param toolname plain name of the tool (e.g. "designer") (string) @return bundle name of the Qt tool (string) """ qtDir = getQtBinariesPath() bundles = [ - os.path.join( - qtDir, 'bin', generateQtToolName(toolname.capitalize())) + ".app", - os.path.join(qtDir, 'bin', generateQtToolName(toolname)) + ".app", - os.path.join( - qtDir, generateQtToolName(toolname.capitalize())) + ".app", + os.path.join(qtDir, "bin", generateQtToolName(toolname.capitalize())) + ".app", + os.path.join(qtDir, "bin", generateQtToolName(toolname)) + ".app", + os.path.join(qtDir, generateQtToolName(toolname.capitalize())) + ".app", os.path.join(qtDir, generateQtToolName(toolname)) + ".app", ] if toolname == "designer": # support the standalone Qt Designer installer from # https://build-system.fman.io/qt-designer-download designer = "Qt Designer.app" - bundles.extend([ - os.path.join(qtDir, 'bin', designer), - os.path.join(qtDir, designer), - ]) + bundles.extend( + [ + os.path.join(qtDir, "bin", designer), + os.path.join(qtDir, designer), + ] + ) for bundle in bundles: if os.path.exists(bundle): return bundle @@ -1831,6 +1911,7 @@ return ("open", newArgs) + ############################################################################### ## PyQt utility functions below ############################################################################### @@ -1839,7 +1920,7 @@ def generatePyQtToolPath(toolname, alternatives=None): """ Module function to generate the executable path for a PyQt tool. - + @param toolname base name of the tool @type str @param alternatives list of alternative tool names to try @@ -1858,14 +1939,15 @@ exe = getWindowsExecutablePath(toolname) else: exe = toolname - + if not isinpath(exe) and alternatives: ex_ = generatePyQtToolPath(alternatives[0], alternatives[1:]) if isinpath(ex_): exe = ex_ - + return exe + ############################################################################### ## PySide2/PySide6 utility functions below ############################################################################### @@ -1874,7 +1956,7 @@ def generatePySideToolPath(toolname, variant=2): """ Module function to generate the executable path for a PySide2/PySide6 tool. - + @param toolname base name of the tool @type str @param variant indicator for the PySide variant @@ -1886,29 +1968,30 @@ hasPyside = checkPyside(variant) if not hasPyside: return "" - + venvName = Preferences.getQt("PySide{0}VenvName".format(variant)) if not venvName: venvName = Preferences.getDebugger("Python3VirtualEnv") - interpreter = ericApp().getObject( - "VirtualEnvManager").getVirtualenvInterpreter(venvName) + interpreter = ( + ericApp().getObject("VirtualEnvManager").getVirtualenvInterpreter(venvName) + ) if interpreter == "" or not isinpath(interpreter): interpreter = getPythonExecutable() prefix = os.path.dirname(interpreter) if not prefix.endswith("Scripts"): prefix = os.path.join(prefix, "Scripts") - return os.path.join(prefix, toolname + '.exe') + return os.path.join(prefix, toolname + ".exe") else: # step 1: check, if the user has configured a tools path path = Preferences.getQt("PySide{0}ToolsDir".format(variant)) if path: return os.path.join(path, toolname) - + # step 2: determine from used Python interpreter dirName = os.path.dirname(sys.executable) if os.path.exists(os.path.join(dirName, toolname)): return os.path.join(dirName, toolname) - + return toolname @@ -1916,7 +1999,7 @@ def checkPyside(variant=2): """ Module function to check the presence of PySide2/PySide6. - + @param variant indicator for the PySide variant @type int or str @return flags indicating the presence of PySide2/PySide6 @@ -1925,13 +2008,13 @@ venvName = Preferences.getQt("PySide{0}VenvName".format(variant)) if not venvName: venvName = Preferences.getDebugger("Python3VirtualEnv") - interpreter = ericApp().getObject( - "VirtualEnvManager").getVirtualenvInterpreter(venvName) + interpreter = ( + ericApp().getObject("VirtualEnvManager").getVirtualenvInterpreter(venvName) + ) if interpreter == "" or not isinpath(interpreter): interpreter = getPythonExecutable() - - checker = os.path.join( - getConfig('ericDir'), "Utilities", "PySideImporter.py") + + checker = os.path.join(getConfig("ericDir"), "Utilities", "PySideImporter.py") args = [checker, "--variant={0}".format(variant)] proc = QProcess() proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) @@ -1939,15 +2022,16 @@ finished = proc.waitForFinished(30000) return finished and proc.exitCode() == 0 + ############################################################################### ## Other utility functions below ############################################################################### -def generateVersionInfo(linesep='\n'): +def generateVersionInfo(linesep="\n"): """ Module function to generate a string with various version infos. - + @param linesep string to be used to separate lines @type str @return string with version infos @@ -1961,34 +2045,38 @@ sip_version_str = sip.SIP_VERSION_STR except (ImportError, AttributeError): sip_version_str = "sip version not available" - + sizeStr = "64-Bit" if sys.maxsize > 2**32 else "32-Bit" - + info = ["Version Numbers:"] - + info.append(" Python {0}, {1}".format(sys.version.split()[0], sizeStr)) info.append(" Qt {0}".format(qVersion())) info.append(" PyQt6 {0}".format(PYQT_VERSION_STR)) try: from PyQt6 import QtCharts - info.append(" PyQt6-Charts {0}".format( - QtCharts.PYQT_CHART_VERSION_STR)) + + info.append(" PyQt6-Charts {0}".format(QtCharts.PYQT_CHART_VERSION_STR)) except (ImportError, AttributeError): info.append(" PyQt6-Charts not installed") try: from PyQt6 import QtWebEngineCore - info.append(" PyQt6-WebEngine {0}".format( - QtWebEngineCore.PYQT_WEBENGINE_VERSION_STR)) + + info.append( + " PyQt6-WebEngine {0}".format(QtWebEngineCore.PYQT_WEBENGINE_VERSION_STR) + ) except (ImportError, AttributeError): info.append(" PyQt6-WebEngine not installed") info.append(" PyQt6-QScintilla {0}".format(QSCINTILLA_VERSION_STR)) info.append(" sip {0}".format(sip_version_str)) with contextlib.suppress(ImportError): - from PyQt6 import QtWebEngineWidgets # __IGNORE_WARNING__ + from PyQt6 import QtWebEngineWidgets # __IGNORE_WARNING__ from WebBrowser.Tools import WebBrowserTools - chromiumVersion, chromiumSecurityVersion = ( - WebBrowserTools.getWebEngineVersions()[0:2] - ) + + ( + chromiumVersion, + chromiumSecurityVersion, + ) = WebBrowserTools.getWebEngineVersions()[0:2] info.append(" WebEngine {0}".format(chromiumVersion)) if chromiumSecurityVersion: info.append(" (Security) {0}".format(chromiumSecurityVersion)) @@ -2004,14 +2092,14 @@ if session: info.append("") info.append("Session Type: {0}".format(session)) - + return linesep.join(info) -def generatePluginsVersionInfo(linesep='\n'): +def generatePluginsVersionInfo(linesep="\n"): """ Module function to generate a string with plugins version infos. - + @param linesep string to be used to separate lines @type str @return string with plugins version infos @@ -2025,19 +2113,20 @@ versions = {} for pinfo in pm.getPluginInfos(): versions[pinfo["module_name"]] = pinfo["version"] - + info.append("Plugins Version Numbers:") for pluginModuleName in sorted(versions.keys()): - info.append(" {0} {1}".format( - pluginModuleName, versions[pluginModuleName])) - + info.append( + " {0} {1}".format(pluginModuleName, versions[pluginModuleName]) + ) + return linesep.join(info) -def generateDistroInfo(linesep='\n'): +def generateDistroInfo(linesep="\n"): """ Module function to generate a string with distribution infos. - + @param linesep string to be used to separate lines @type str @return string with distribution infos @@ -2054,18 +2143,18 @@ lines = f.read().splitlines() except OSError: continue - - info.append(' {0}'.format(rfile)) - info.extend([' {0}'.format(line) for line in lines]) + + info.append(" {0}".format(rfile)) + info.extend([" {0}".format(line) for line in lines]) info.append("") - + return linesep.join(info) def toBool(dataStr): """ Module function to convert a string to a boolean value. - + @param dataStr string to be converted (string) @return converted boolean value (boolean) """ @@ -2081,7 +2170,7 @@ """ Module function to get the Python path (sys.path) of a specific interpreter. - + @param interpreter Python interpreter executable to get sys.path for @type str @return list containing sys.path of the interpreter; an empty list @@ -2089,11 +2178,10 @@ @rtype list of str """ import json - + sysPath = [] - - getSysPathSkript = os.path.join( - os.path.dirname(__file__), "GetSysPath.py") + + getSysPathSkript = os.path.join(os.path.dirname(__file__), "GetSysPath.py") args = [getSysPathSkript] proc = QProcess() proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) @@ -2106,9 +2194,10 @@ sysPath = json.loads(sysPathResult) if "" in sysPath: sysPath.remove("") - + return sysPath + ############################################################################### ## posix compatibility functions below ############################################################################### @@ -2123,40 +2212,42 @@ def win32_Kill(pid): """ Function to provide an os.kill equivalent for Win32. - + @param pid process id (integer) @return result of the kill (boolean) """ import win32api + handle = win32api.OpenProcess(1, 0, pid) - return (0 != win32api.TerminateProcess(handle, 0)) + return 0 != win32api.TerminateProcess(handle, 0) def win32_GetUserName(): """ Function to get the user name under Win32. - + @return user name (string) """ try: import win32api + return win32api.GetUserName() except ImportError: try: - u = getEnvironmentEntry('USERNAME') + u = getEnvironmentEntry("USERNAME") except KeyError: - u = getEnvironmentEntry('username', None) + u = getEnvironmentEntry("username", None) return u def win32_getRealName(): """ Function to get the user's real name (aka. display name) under Win32. - + @return real name of the current user (string) """ import ctypes - + GetUserNameEx = ctypes.windll.secur32.GetUserNameExW NameDisplay = 3