Tue, 23 Jun 2020 17:24:18 +0200
Removed some more Python2 related code.
--- a/eric6/DebugClients/Python/DebugBase.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/DebugClients/Python/DebugBase.py Tue Jun 23 17:24:18 2020 +0200 @@ -18,14 +18,8 @@ from BreakpointWatch import Breakpoint, Watch -if sys.version_info[0] == 2: - import thread as _thread - from inspect import getargvalues, formatargvalues -else: - import _thread - from DebugUtilities import getargvalues, formatargvalues - unicode = str - basestring = str +import _thread +from DebugUtilities import getargvalues, formatargvalues gRecursionLimit = 64 @@ -383,10 +377,7 @@ if frame is None: frame = sys._getframe().f_back # Skip set_trace method - if sys.version_info[0] == 2: - stopOnHandleCommand = self._dbgClient.handleJsonCommand.func_code - else: - stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ + stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ frame.f_trace = self.trace_dispatch while frame.f_back is not None: @@ -621,10 +612,7 @@ lineNo = frame.f_code.co_firstlineno lineNumbers = [lineNo] - if sys.version_info[0] == 2: - co_lnotab = map(ord, frame.f_code.co_lnotab[1::2]) - else: - co_lnotab = frame.f_code.co_lnotab[1::2] + co_lnotab = frame.f_code.co_lnotab[1::2] # No need to handle special case if a lot of lines between # (e.g. closure), because the additional lines won't cause a bp @@ -870,13 +858,7 @@ else: exctypetxt = str(exctype) - if sys.version_info[0] == 2: - try: - excvaltxt = unicode(excval).encode(self._dbgClient.getCoding()) - except UnicodeError: - excvaltxt = str(excval) - else: - excvaltxt = str(excval) + excvaltxt = str(excval) # Don't step into libraries, which are used by our debugger methods if exctb is not None: @@ -920,14 +902,7 @@ @param exctype type of the exception @return exception name (string) """ - if sys.version_info[0] == 2: - if type(exctype) in [types.ClassType, # Python up to 2.4 - types.TypeType]: # Python 2.5+ - return exctype.__name__ - else: - return exctype - else: - return str(exctype).replace("<class '", "").replace("'>", "") + return str(exctype).replace("<class '", "").replace("'>", "") def __extract_stack(self, exctb): """ @@ -957,7 +932,7 @@ if excval is None: exitcode = 0 message = "" - elif isinstance(excval, basestring): + elif isinstance(excval, str): exitcode = 1 message = excval elif isinstance(excval, bytes): @@ -968,7 +943,7 @@ message = "" elif isinstance(excval, SystemExit): code = excval.code - if isinstance(code, basestring): + if isinstance(code, str): exitcode = 1 message = code elif isinstance(code, bytes):
--- a/eric6/DebugClients/Python/DebugClientBase.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/DebugClients/Python/DebugClientBase.py Tue Jun 23 17:24:18 2020 +0200 @@ -31,78 +31,37 @@ from DebugUtilities import prepareJsonCommand from BreakpointWatch import Breakpoint, Watch -if sys.version_info[0] == 2: - from inspect import getargvalues, formatargvalues -else: - unichr = chr - from DebugUtilities import getargvalues, formatargvalues +from DebugUtilities import getargvalues, formatargvalues DebugClientInstance = None ############################################################################### -def DebugClientRawInput(prompt="", echo=True): +def DebugClientRawInput(prompt=""): """ - Replacement for the standard raw_input() builtin (Python 2) and - the standard input() builtin (Python 3). + Replacement for the standard input() builtin. This function works with the split debugger. @param prompt prompt to be shown @type str - @param echo flag indicating echoing of the input - @type bool @return result of the raw_input()/input() call @rtype str """ if DebugClientInstance is None or not DebugClientInstance.redirect: - return DebugClientOrigRawInput(prompt) - - return DebugClientInstance.raw_input(prompt, echo) - - -def DebugClientInput(prompt=""): - """ - Replacement for the standard input() builtin (Python 2). - - This function works with the split debugger. - - @param prompt prompt to be shown - @type str - @return result of the input() call - @rtype str - """ - if DebugClientInstance is None or not DebugClientInstance.redirect: return DebugClientOrigInput(prompt) return DebugClientInstance.input(prompt) -# Use our own input() and on Python 2 raw_input(). -if sys.version_info[0] == 2: - try: - DebugClientOrigRawInput = __builtins__.__dict__['raw_input'] - __builtins__.__dict__['raw_input'] = DebugClientRawInput - except (AttributeError, KeyError): - import __main__ - DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input'] - __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput - - try: - DebugClientOrigInput = __builtins__.__dict__['input'] - __builtins__.__dict__['input'] = DebugClientInput - except (AttributeError, KeyError): - import __main__ - DebugClientOrigInput = __main__.__builtins__.__dict__['input'] - __main__.__builtins__.__dict__['input'] = DebugClientInput -else: - try: - DebugClientOrigInput = __builtins__.__dict__['input'] - __builtins__.__dict__['input'] = DebugClientRawInput - except (AttributeError, KeyError): - import __main__ - DebugClientOrigInput = __main__.__builtins__.__dict__['input'] - __main__.__builtins__.__dict__['input'] = DebugClientRawInput +# Use our own input(). +try: + DebugClientOrigInput = __builtins__.__dict__['input'] + __builtins__.__dict__['input'] = DebugClientRawInput +except (AttributeError, KeyError): + import __main__ + DebugClientOrigInput = __main__.__builtins__.__dict__['input'] + __main__.__builtins__.__dict__['input'] = DebugClientRawInput ############################################################################### @@ -274,9 +233,9 @@ return self.__coding = default - def raw_input(self, prompt, echo): + def input(self, prompt): """ - Public method to implement raw_input() / input() using the event loop. + Public method to implement input() using the event loop. @param prompt the prompt to be shown (string) @param echo Flag indicating echoing of the input (boolean) @@ -284,20 +243,11 @@ """ self.sendJsonCommand("RequestRaw", { "prompt": prompt, - "echo": echo, + "echo": True, }) self.eventLoop(True) return self.rawLine - def input(self, prompt): - """ - Public method to implement input() (Python 2) using the event loop. - - @param prompt the prompt to be shown (string) - @return the entered string evaluated as a Python expresion - """ - return eval(self.raw_input(prompt, True)) # secok - def sessionClose(self, terminate=True): """ Public method to close the session with the debugger and optionally @@ -334,13 +284,6 @@ with codecs.open(filename, encoding=self.__coding) as fp: statement = fp.read() - if sys.version_info[0] == 2: - lines = statement.splitlines(True) - for lineno, line in enumerate(lines[:2]): - lines[lineno] = self.coding_re.sub('', line) - - statement = unicode('').join(lines) # __IGNORE_WARNING__ - try: code = compile(statement + '\n', filename, mode) except SyntaxError: @@ -382,9 +325,6 @@ method = commandDict["method"] params = commandDict["params"] - if "filename" in params and sys.version_info[0] == 2: - params["filename"] = params["filename"].encode( - sys.getfilesystemencoding()) if method == "RequestVariables": self.__dumpVariables( @@ -408,7 +348,7 @@ }) elif method == "RequestCapabilities": - clientType = "Python2" if sys.version_info[0] == 2 else "Python3" + clientType = "Python3" self.sendJsonCommand("ResponseCapabilities", { "capabilities": self.__clientCapabilities(), "clientType": clientType @@ -583,13 +523,10 @@ self.debugMod.__dict__['__file__'] = sys.argv[0] sys.modules['__main__'] = self.debugMod script = '' - if sys.version_info[0] == 2: - script = 'execfile({0!r})'.format(sys.argv[0]) - else: - with codecs.open(sys.argv[0], encoding=self.__coding) as fp: - script = fp.read() - if script and not script.endswith('\n'): - script += '\n' + with codecs.open(sys.argv[0], encoding=self.__coding) as fp: + script = fp.read() + if script and not script.endswith('\n'): + script += '\n' if script: self.running = sys.argv[0] @@ -1372,9 +1309,6 @@ @return the converted filename (string) """ if os.path.isabs(fn): - if sys.version_info[0] == 2: - fn = fn.decode(sys.getfilesystemencoding()) - return fn # Check the cache. @@ -1387,9 +1321,6 @@ nafn = os.path.normcase(afn) if os.path.exists(nafn): - if sys.version_info[0] == 2: - afn = afn.decode(sys.getfilesystemencoding()) - self._fncache[fn] = afn d = os.path.dirname(afn) if (d not in sys.path) and (d not in self.dircache): @@ -1601,7 +1532,7 @@ varlist = [] if qttype == 'QChar': varlist.append( - ("", "QChar", "{0}".format(unichr(value.unicode())))) + ("", "QChar", "{0}".format(chr(value.unicode())))) varlist.append(("", "int", "{0:d}".format(value.unicode()))) elif qttype == 'QByteArray': varlist.append(
--- a/eric6/DebugClients/Python/DebugVariables.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/DebugClients/Python/DebugVariables.py Tue Jun 23 17:24:18 2020 +0200 @@ -7,17 +7,12 @@ Module implementing classes and functions to dump variable contents. """ -import sys - from DebugConfig import ConfigQtNames, ConfigKnownQtTypes, BatchSize # # This code was inspired by pydevd. # -if sys.version_info[0] > 2: - basestring = str - ############################################################ ## Classes implementing resolvers for various compund types ############################################################ @@ -141,7 +136,7 @@ @return string representation of the given key @rtype str """ - if isinstance(key, basestring): + if isinstance(key, str): key = repr(key) # Special handling for Python2 unicode strings and bytes object # Raw and f-Strings are always converted to (unicode) str
--- a/eric6/DebugClients/Python/PyProfile.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/DebugClients/Python/PyProfile.py Tue Jun 23 17:24:18 2020 +0200 @@ -11,7 +11,6 @@ import profile import atexit import pickle # secok -import sys class PyProfile(profile.Profile): @@ -119,10 +118,7 @@ @param frame the frame object @return fixed up file name (string) """ - if sys.version_info[0] == 2: - versionExt = '.py2' - else: - versionExt = '.py3' + versionExt = '.py3' # get module name from __file__ if (not isinstance(frame, profile.Profile.fake_frame) and
--- a/eric6/DebugClients/Python/ThreadExtension.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/DebugClients/Python/ThreadExtension.py Tue Jun 23 17:24:18 2020 +0200 @@ -11,11 +11,7 @@ import sys import importlib -if sys.version_info[0] == 2: - import thread as _thread -else: - import _thread - +import _thread import threading from DebugBase import DebugBase @@ -54,13 +50,8 @@ # special objects representing the main scripts thread and frame self.mainThread = self - if sys.version_info[0] == 2: - self.threadModName = 'thread' - else: - self.threadModName = '_thread' - # reset already imported thread module to apply hooks at next import - del sys.modules[self.threadModName] + del sys.modules['_thread'] del sys.modules['threading'] sys.meta_path.insert(0, self) @@ -260,7 +251,7 @@ if fullname in sys.modules or not self.debugging: return None - if fullname in [self.threadModName, 'PyQt5.QtCore', 'PySide2.QtCore', + if fullname in ['_thread', 'PyQt5.QtCore', 'PySide2.QtCore', 'greenlet', 'threading' ] and self.enableImportHooks: # Disable hook to be able to import original module @@ -280,7 +271,7 @@ """ module = importlib.import_module(fullname) sys.modules[fullname] = module - if (fullname == self.threadModName and + if (fullname == '_thread' and self._original_start_new_thread is None): # make thread hooks available to system self._original_start_new_thread = module.start_new_thread @@ -337,10 +328,7 @@ module.Thread = ThreadWrapper # Special handling of threading.(_)Timer - if sys.version_info[0] == 2: - timer = module._Timer - else: - timer = module.Timer + timer = module.Timer class TimerWrapper(timer, ThreadWrapper): """ @@ -353,10 +341,7 @@ super(TimerWrapper, self).__init__( interval, function, *args, **kwargs) - if sys.version_info[0] == 2: - module._Timer = TimerWrapper - else: - module.Timer = TimerWrapper + module.Timer = TimerWrapper # Special handling of threading._DummyThread class DummyThreadWrapper(module._DummyThread, ThreadWrapper):
--- a/eric6/Debugger/DebuggerInterfacePython.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Debugger/DebuggerInterfacePython.py Tue Jun 23 17:24:18 2020 +0200 @@ -347,8 +347,7 @@ interpreter = venvManager.getVirtualenvInterpreter(venvName) execPath = venvManager.getVirtualenvExecPath(venvName) if (interpreter == "" and - project.getProjectLanguage().startswith("Python") and - sys.version_info[0] == int(project.getProjectLanguage()[-1])): + project.getProjectLanguage().startswith("Python")): interpreter = sys.executable.replace("w.exe", ".exe") if interpreter == "": E5MessageBox.critical( @@ -1318,8 +1317,7 @@ py3Exts.append(".{0}".format(ext)) registryData = [] - if py3Exts and (Preferences.getDebugger("Python3VirtualEnv") or - sys.version_info[0] >= 3): + if py3Exts: registryData.append( ("Python3", ClientDefaultCapabilities, py3Exts, createDebuggerInterfacePython3)
--- a/eric6/Graphics/ApplicationDiagramBuilder.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Graphics/ApplicationDiagramBuilder.py Tue Jun 23 17:24:18 2020 +0200 @@ -54,7 +54,6 @@ """ import Utilities.ModuleParser extensions = ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") + ['.rb'] )
--- a/eric6/Graphics/ImportsDiagramBuilder.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Graphics/ImportsDiagramBuilder.py Tue Jun 23 17:24:18 2020 +0200 @@ -79,13 +79,11 @@ """ import Utilities.ModuleParser extensions = ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") ) moduleDict = {} modules = [] for ext in ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") ): modules.extend(glob.glob(Utilities.normjoinpath(
--- a/eric6/Graphics/PackageDiagramBuilder.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Graphics/PackageDiagramBuilder.py Tue Jun 23 17:24:18 2020 +0200 @@ -75,13 +75,10 @@ supportedExt = ( ['*{0}'.format(ext) for ext in - Preferences.getPython("PythonExtensions")] + - ['*{0}'.format(ext) for ext in Preferences.getPython("Python3Extensions")] + ['*.rb'] ) extensions = ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") + ['.rb'] ) @@ -131,13 +128,10 @@ supportedExt = ( ['*{0}'.format(ext) for ext in - Preferences.getPython("PythonExtensions")] + - ['*{0}'.format(ext) for ext in Preferences.getPython("Python3Extensions")] + ['*.rb'] ) extensions = ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") + ['.rb'] )
--- a/eric6/Graphics/UMLClassDiagramBuilder.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Graphics/UMLClassDiagramBuilder.py Tue Jun 23 17:24:18 2020 +0200 @@ -73,7 +73,6 @@ try: extensions = ( - Preferences.getPython("PythonExtensions") + Preferences.getPython("Python3Extensions") + ['.rb'] )
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/AnnotationsChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/AnnotationsChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -163,13 +163,6 @@ @rtype ast.Module """ source = "".join(self.__source) - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - source = source.encode('utf-8') - except UnicodeError: - pass - return compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST) def run(self):
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/AstUtilities.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/AstUtilities.py Tue Jun 23 17:24:18 2020 +0200 @@ -135,10 +135,7 @@ @return flag indicating a bytes @rtype bool """ - return ( - sys.version_info[0] >= 3 and - isinstance(node, ast.Bytes) - ) + return isinstance(node, ast.Bytes) def isBaseString(node): """ @@ -149,10 +146,7 @@ @return flag indicating a bytes or string @rtype bool """ - typ = (ast.Str,) - if sys.version_info[0] > 2: - typ += (ast.Bytes,) - return isinstance(node, typ) + return isinstance(node, (ast.Str, ast.Bytes)) def isNameConstant(node): """ @@ -181,7 +175,7 @@ elif isinstance(node, ast.Str): return node.s - elif sys.version_info[0] > 2 and isinstance(node, ast.Bytes): + elif isinstance(node, ast.Bytes): return node.s elif isinstance(node, ast.NameConstant):
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -7,11 +7,7 @@ Module implementing the code style checker. """ -try: # Only for Py2 - import Queue as queue -except ImportError: - import queue - +import queue import ast import sys import multiprocessing @@ -286,12 +282,6 @@ @rtype tuple of (dict, dict) or tuple of (None, None) """ src = "".join(source) - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - src = src.encode('utf-8') - except UnicodeError: - pass try: ast.parse(src, filename, 'exec')
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py Tue Jun 23 17:24:18 2020 +0200 @@ -613,8 +613,7 @@ self.files = fn[:] elif os.path.isdir(fn): self.files = [] - extensions = set(Preferences.getPython("PythonExtensions") + - Preferences.getPython("Python3Extensions")) + extensions = set(Preferences.getPython("Python3Extensions")) for ext in extensions: self.files.extend(Utilities.direntries( fn, True, '*{0}'.format(ext), 0))
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/DocStyleChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/DocStyleChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -40,11 +40,7 @@ @param startLine line number the context starts in the source (integer) @param contextType type of the context object (string) """ - if sys.version_info[0] == 2: - stringTypes = (str, unicode) # __IGNORE_WARNING__ - else: - stringTypes = str - if isinstance(source, stringTypes): + if isinstance(source, str): self.__source = source.splitlines(True) else: self.__source = source[:] @@ -360,12 +356,6 @@ return source = "".join(self.__source) - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - source = source.encode('utf-8') - except UnicodeError: - pass try: compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST) except (SyntaxError, TypeError): @@ -445,62 +435,30 @@ summaries.append(line2) return summaries, lineno - if sys.version_info[0] < 3: - def __getArgNames(self, node): - """ - Private method to get the argument names of a function node. - - @param node AST node to extract arguments names from - @return tuple of two list of argument names, one for arguments - and one for keyword arguments (tuple of list of string) - """ - def unpackArgs(args): - """ - Local helper function to unpack function argument names. - - @param args list of AST node arguments - @return list of argument names (list of string) - """ - ret = [] - for arg in args: - if isinstance(arg, ast.Tuple): - ret.extend(unpackArgs(arg.elts)) - else: - ret.append(arg.id) - return ret - - arguments = unpackArgs(node.args.args) - if node.args.vararg is not None: + def __getArgNames(self, node): + """ + Private method to get the argument names of a function node. + + @param node AST node to extract arguments names from + @return tuple of two list of argument names, one for arguments + and one for keyword arguments (tuple of list of string) + """ + arguments = [] + arguments.extend([arg.arg for arg in node.args.args]) + if node.args.vararg is not None: + if sys.version_info < (3, 4, 0): arguments.append(node.args.vararg) - kwarguments = [] - if node.args.kwarg is not None: + else: + arguments.append(node.args.vararg.arg) + + kwarguments = [] + kwarguments.extend([arg.arg for arg in node.args.kwonlyargs]) + if node.args.kwarg is not None: + if sys.version_info < (3, 4, 0): kwarguments.append(node.args.kwarg) - return arguments, kwarguments - else: - def __getArgNames(self, node): # __IGNORE_WARNING__ - """ - Private method to get the argument names of a function node. - - @param node AST node to extract arguments names from - @return tuple of two list of argument names, one for arguments - and one for keyword arguments (tuple of list of string) - """ - arguments = [] - arguments.extend([arg.arg for arg in node.args.args]) - if node.args.vararg is not None: - if sys.version_info < (3, 4, 0): - arguments.append(node.args.vararg) - else: - arguments.append(node.args.vararg.arg) - - kwarguments = [] - kwarguments.extend([arg.arg for arg in node.args.kwonlyargs]) - if node.args.kwarg is not None: - if sys.version_info < (3, 4, 0): - kwarguments.append(node.args.kwarg) - else: - kwarguments.append(node.args.kwarg.arg) - return arguments, kwarguments + else: + kwarguments.append(node.args.kwarg.arg) + return arguments, kwarguments ################################################################## ## Parsing functionality below
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -151,14 +151,9 @@ self.__pep3101FormatRegex = re.compile( r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') - if sys.version_info >= (3, 0): - import builtins - self.__builtins = [b for b in dir(builtins) - if b not in self.BuiltinsWhiteList] - else: - import __builtin__ - self.__builtins = [b for b in dir(__builtin__) - if b not in self.BuiltinsWhiteList] + import builtins + self.__builtins = [b for b in dir(builtins) + if b not in self.BuiltinsWhiteList] # statistics counters self.counters = {} @@ -292,13 +287,6 @@ @rtype ast.AST """ source = "".join(self.__source) - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - source = source.encode('utf-8') - except UnicodeError: - pass - return compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST) def run(self): @@ -533,7 +521,7 @@ visitor.visit(self.__tree) for node in visitor.nodes: text = node.s - if sys.version_info[0] > 2 and isinstance(text, bytes): + if isinstance(text, bytes): try: text = text.decode(coding) except UnicodeDecodeError: @@ -711,22 +699,13 @@ elif any(isinstance(node, functionDef) for functionDef in functionDefs): # (asynchronous) function definition - if sys.version_info >= (3, 0): - for arg in node.args.args: - if ( - isinstance(arg, ast.arg) and - arg.arg in self.__builtins - ): - self.__error(arg.lineno - 1, arg.col_offset, - "M132", arg.arg) - else: - for arg in node.args.args: - if ( - isinstance(arg, ast.Name) and - arg.id in self.__builtins - ): - self.__error(arg.lineno - 1, arg.col_offset, - "M132", arg.id) + for arg in node.args.args: + if ( + isinstance(arg, ast.arg) and + arg.arg in self.__builtins + ): + self.__error(arg.lineno - 1, arg.col_offset, + "M132", arg.arg) def __checkComprehensions(self): """ @@ -962,23 +941,20 @@ """ Private method to check use of naive datetime functions. """ - if sys.version_info[0] >= 3: - # this check is only performed for Python 3 - - # step 1: generate an augmented node tree containing parent info - # for each child node - tree = self.__generateTree() - for node in ast.walk(tree): - for childNode in ast.iter_child_nodes(node): - childNode._dtCheckerParent = node - - # step 2: perform checks and report issues - visitor = DateTimeVisitor() - visitor.visit(tree) - for violation in visitor.violations: - node = violation[0] - reason = violation[1] - self.__error(node.lineno - 1, node.col_offset, reason) + # step 1: generate an augmented node tree containing parent info + # for each child node + tree = self.__generateTree() + for node in ast.walk(tree): + for childNode in ast.iter_child_nodes(node): + childNode._dtCheckerParent = node + + # step 2: perform checks and report issues + visitor = DateTimeVisitor() + visitor.visit(tree) + for violation in visitor.violations: + node = violation[0] + reason = violation[1] + self.__error(node.lineno - 1, node.col_offset, reason) def __checkSysVersion(self): """ @@ -1384,16 +1360,12 @@ @param node reference to the node to be processed @type ast.Call """ - if sys.version_info >= (3, 0): - validPaths = ("six", "future.utils", "builtins") - methodsDict = { - "M521": ("iterkeys", "itervalues", "iteritems", "iterlists"), - "M522": ("viewkeys", "viewvalues", "viewitems", "viewlists"), - "M523": ("next",), - } - else: - validPaths = () - methodsDict = {} + validPaths = ("six", "future.utils", "builtins") + methodsDict = { + "M521": ("iterkeys", "itervalues", "iteritems", "iterlists"), + "M522": ("viewkeys", "viewvalues", "viewitems", "viewlists"), + "M523": ("next",), + } if isinstance(node.func, ast.Attribute): for code, methods in methodsDict.items(): @@ -1450,13 +1422,12 @@ """ callPath = list(composeCallPath(node)) - if '.'.join(callPath) == 'sys.maxint' and sys.version_info >= (3, 0): + if '.'.join(callPath) == 'sys.maxint': self.violations.append((node, "M504")) elif ( len(callPath) == 2 and - callPath[1] == 'message' and - sys.version_info >= (2, 6) + callPath[1] == 'message' ): name = callPath[0] for elem in reversed(self.__nodeStack[:-1]): @@ -1475,7 +1446,7 @@ # By using 'hasattr' below we're ignoring starred arguments, slices # and tuples for simplicity. assignTargets = {t.id for t in node.targets if hasattr(t, 'id')} - if '__metaclass__' in assignTargets and sys.version_info >= (3, 0): + if '__metaclass__' in assignTargets: self.violations.append((node, "M524")) elif len(node.targets) == 1: @@ -1785,13 +1756,10 @@ @type ast.AST @return flag indicating the node contains a None value """ - if sys.version_info[0] > 2: - return ( - AstUtilities.isNameConstant(node) and - AstUtilities.getValue(node) is None - ) - else: - return isinstance(node, ast.Name) and node.id == "None" + return ( + AstUtilities.isNameConstant(node) and + AstUtilities.getValue(node) is None + ) def __resultExists(self): """ @@ -1850,7 +1818,6 @@ try: okNodes = (ast.Return, ast.Raise, ast.While, ast.Try) except AttributeError: - # Py2 okNodes = (ast.Return, ast.Raise, ast.While) if not isinstance(node, okNodes): self.violations.append((node, "M833"))
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/NamingStyleChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/NamingStyleChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -188,27 +188,9 @@ @param node AST node to extract arguments names from @return list of argument names (list of string) """ - if sys.version_info[0] >= 3: - posArgs = [arg.arg for arg in node.args.args] - kwOnly = [arg.arg for arg in node.args.kwonlyargs] - return posArgs + kwOnly - else: - def unpackArgs(args): - """ - Local helper function to unpack function argument names. - - @param args list of AST node arguments - @return list of argument names (list of string) - """ - ret = [] - for arg in args: - if isinstance(arg, ast.Tuple): - ret.extend(unpackArgs(arg.elts)) - else: - ret.append(arg.id) - return ret - - return unpackArgs(node.args.args) + posArgs = [arg.arg for arg in node.args.args] + kwOnly = [arg.arg for arg in node.args.kwonlyargs] + return posArgs + kwOnly def __error(self, node, code): """
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/djangoXssVulnerability.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/djangoXssVulnerability.py Tue Jun 23 17:24:18 2020 +0200 @@ -16,12 +16,9 @@ # import ast -import sys import AstUtilities -PY2 = sys.version_info[0] == 2 - def getChecks(): """ @@ -85,8 +82,7 @@ isParam = False if isinstance(parent, ast.FunctionDef): for name in parent.args.args: - argName = name.id if PY2 else name.arg - if argName == xssVar.id: + if name.arg == xssVar.id: isParam = True break @@ -179,28 +175,13 @@ assigned = self.isAssignedIn(node.body) elif isinstance(node, ast.With): - if PY2: - if node.optional_vars.id == self.__varName.id: + for withitem in node.items: + varId = getattr(withitem.optional_vars, 'id', None) + if varId == self.__varName.id: assigned = node else: assigned = self.isAssignedIn(node.body) - else: - for withitem in node.items: - varId = getattr(withitem.optional_vars, 'id', None) - if varId == self.__varName.id: - assigned = node - else: - assigned = self.isAssignedIn(node.body) - elif PY2 and isinstance(node, ast.TryFinally): - assigned = [] - assigned.extend(self.isAssignedIn(node.body)) - assigned.extend(self.isAssignedIn(node.finalbody)) - elif PY2 and isinstance(node, ast.TryExcept): - assigned = [] - assigned.extend(self.isAssignedIn(node.body)) - assigned.extend(self.isAssignedIn(node.handlers)) - assigned.extend(self.isAssignedIn(node.orelse)) - elif not PY2 and isinstance(node, ast.Try): + elif isinstance(node, ast.Try): assigned = [] assigned.extend(self.isAssignedIn(node.body)) assigned.extend(self.isAssignedIn(node.handlers)) @@ -252,8 +233,7 @@ if isinstance(xssVar, ast.Name): if isinstance(parent, ast.FunctionDef): for name in parent.args.args: - argName = name.id if PY2 else name.arg - if argName == xssVar.id: + if name.arg == xssVar.id: return False # Params are not secure analyser = DeepAssignation(xssVar, ignoreNodes) @@ -316,17 +296,11 @@ call.func.attr == 'format' ): evaluate = True - if call.keywords or (PY2 and call.kwargs): + if call.keywords: evaluate = False if evaluate: args = list(call.args) - if ( - PY2 and - call.starargs and - isinstance(call.starargs, (ast.List, ast.Tuple)) - ): - args.extend(call.starargs.elts) numSecure = 0 for arg in args: @@ -343,7 +317,6 @@ else: break elif ( - not PY2 and isinstance(arg, ast.Starred) and isinstance(arg.value, (ast.List, ast.Tuple)) ): @@ -372,19 +345,13 @@ newCall = ast.Call() newCall.args = [] newCall.args = [] - if PY2: - newCall.starargs = None newCall.keywords = None - if PY2: - newCall.kwargs = None newCall.lineno = var.lineno newCall.func = ast.Attribute() newCall.func.value = var.left newCall.func.attr = 'format' if isinstance(var.right, ast.Tuple): newCall.args = var.right.elts - elif PY2 and isinstance(var.right, ast.Dict): - newCall.kwargs = var.right else: newCall.args = [var.right]
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/exec.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/exec.py Tue Jun 23 17:24:18 2020 +0200 @@ -15,8 +15,6 @@ # SPDX-License-Identifier: Apache-2.0 # -import sys - def getChecks(): """ @@ -26,18 +24,11 @@ list of codes @rtype dict """ - if sys.version_info[0] == 2: - return { - "Exec": [ - (checkExecUsed, ("S102",)), - ], - } - else: - return { - "Call": [ - (checkExecUsed, ("S102",)), - ], - } + return { + "Call": [ + (checkExecUsed, ("S102",)), + ], + } def checkExecUsed(reportError, context, config): @@ -51,10 +42,7 @@ @param config dictionary with configuration data @type dict """ - if ( - sys.version_info[0] == 2 or - context.callFunctionNameQual == 'exec' - ): + if context.callFunctionNameQual == 'exec': reportError( context.node.lineno - 1, context.node.col_offset,
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedPassword.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedPassword.py Tue Jun 23 17:24:18 2020 +0200 @@ -17,7 +17,6 @@ import ast import re -import sys import AstUtilities @@ -154,12 +153,8 @@ # go through all (param, value)s and look for candidates for key, val in zip(context.node.args.args, defs): - isPy3Arg = True - if sys.version_info[0] > 2: - isPy3Arg = isinstance(key, ast.arg) - if isinstance(key, ast.Name) or isPy3Arg: - check = key.arg if sys.version_info[0] > 2 else key.id # Py3 - if AstUtilities.isString(val) and RE_CANDIDATES.search(check): + if isinstance(key, ast.Name) or isinstance(key, ast.arg): + if AstUtilities.isString(val) and RE_CANDIDATES.search(key.arg): reportError( context.node.lineno - 1, context.node.col_offset,
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py Tue Jun 23 17:24:18 2020 +0200 @@ -17,7 +17,6 @@ import ast import re -import sys import AstUtilities @@ -91,10 +90,7 @@ result = bool(val.keys) elif isinstance(val, ast.Name) and val.id in ['False', 'None']: result = False - elif ( - sys.version_info[0] >= 3 and - AstUtilities.isNameConstant(val) - ): + elif AstUtilities.isNameConstant(val): result = val.value else: result = True
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -224,13 +224,6 @@ @rtype ast.AST """ source = "".join(self.__source) - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - source = source.encode('utf-8') - except UnicodeError: - pass - return compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST) def getConfig(self):
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityContext.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityContext.py Tue Jun 23 17:24:18 2020 +0200 @@ -180,7 +180,6 @@ """ val = self.stringVal if val is not None: - # it's any of str or unicode in py2, or str in py3 return val.encode('unicode_escape') val = self.bytesVal @@ -267,20 +266,10 @@ elif isinstance(literal, ast.Name): literalValue = literal.id - # NameConstants are only part of the AST in Python 3. NameConstants - # tend to refer to things like True and False. This prevents them from - # being re-assigned in Python 3. - elif ( - sys.version_info[0] >= 3 and - AstUtilities.isNameConstant(literal) - ): + elif AstUtilities.isNameConstant(literal): literalValue = str(literal.value) - # Bytes are only part of the AST in Python 3 - elif ( - sys.version_info[0] >= 3 and - AstUtilities.isBytes(literal) - ): + elif AstUtilities.isBytes(literal): literalValue = literal.s else:
--- a/eric6/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheck.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheck.py Tue Jun 23 17:24:18 2020 +0200 @@ -7,14 +7,9 @@ Module implementing the syntax check for Python 2/3. """ -try: # Only for Py2 - import Queue as queue -except ImportError: - import queue - +import queue import ast import re -import sys import traceback import multiprocessing @@ -66,13 +61,6 @@ if codestring and codestring[-1] != '\n': codestring = codestring + '\n' - - # Check type for py2: if not str it's unicode - if sys.version_info[0] == 2: - try: - codestring = codestring.encode('utf-8') - except UnicodeError: - pass return codestring @@ -235,11 +223,6 @@ import __builtin__ as builtins # __IGNORE_WARNING__ try: - if sys.version_info[0] == 2: - file_enc = filename.encode(sys.getfilesystemencoding()) - else: - file_enc = filename - codestring = normalizeCode(codestring) # Check for VCS conflict markers @@ -249,7 +232,7 @@ start, i = conflict.span() lineindex = 1 + codestring.count("\n", 0, start) return [{'error': - (file_enc, lineindex, 0, "", + (filename, lineindex, 0, "", "VCS conflict marker found") }] @@ -259,18 +242,16 @@ except ImportError: return [{'error': (filename, 0, 0, '', 'Quixote plugin not found.')}] - template = quixote.ptl_compile.Template(codestring, file_enc) + template = quixote.ptl_compile.Template(codestring, filename) template.compile() else: module = builtins.compile( - codestring, file_enc, 'exec', ast.PyCF_ONLY_AST) + codestring, filename, 'exec', ast.PyCF_ONLY_AST) except SyntaxError as detail: index = 0 code = "" error = "" lines = traceback.format_exception_only(SyntaxError, detail) - if sys.version_info[0] == 2: - lines = [x.decode(sys.getfilesystemencoding()) for x in lines] match = re.match(r'\s*File "(.+)", line (\d+)', lines[0].replace('<string>', filename)) if match is not None:
--- a/eric6/Plugins/CheckerPlugins/Tabnanny/TabnannyDialog.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/Tabnanny/TabnannyDialog.py Tue Jun 23 17:24:18 2020 +0200 @@ -155,8 +155,7 @@ self.files = fn elif os.path.isdir(fn): self.files = [] - extensions = set(Preferences.getPython("PythonExtensions") + - Preferences.getPython("Python3Extensions")) + extensions = set(Preferences.getPython("Python3Extensions")) for ext in extensions: self.files.extend( Utilities.direntries(fn, True, '*{0}'.format(ext), 0))
--- a/eric6/Plugins/PluginCodeStyleChecker.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/PluginCodeStyleChecker.py Tue Jun 23 17:24:18 2020 +0200 @@ -357,8 +357,7 @@ files = [os.path.join(ppath, file) for file in project.pdata["SOURCES"] if file.endswith( - tuple(Preferences.getPython("Python3Extensions")) + - tuple(Preferences.getPython("PythonExtensions")))] + tuple(Preferences.getPython("Python3Extensions")))] from CheckerPlugins.CodeStyleChecker import CodeStyleCheckerDialog self.__projectCodeStyleCheckerDialog = (
--- a/eric6/Plugins/PluginTabnanny.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/PluginTabnanny.py Tue Jun 23 17:24:18 2020 +0200 @@ -309,8 +309,7 @@ files = [os.path.join(ppath, file) for file in project.pdata["SOURCES"] if file.endswith( - tuple(Preferences.getPython("Python3Extensions")) + - tuple(Preferences.getPython("PythonExtensions")))] + tuple(Preferences.getPython("Python3Extensions")))] from CheckerPlugins.Tabnanny.TabnannyDialog import TabnannyDialog self.__projectTabnannyDialog = TabnannyDialog(self)
--- a/eric6/Plugins/WizardPlugins/SetupWizard/SetupWizardDialog.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Plugins/WizardPlugins/SetupWizard/SetupWizardDialog.py Tue Jun 23 17:24:18 2020 +0200 @@ -9,7 +9,6 @@ import os -import sys import datetime from PyQt5.QtCore import pyqtSlot, Qt, QUrl @@ -253,8 +252,7 @@ # now generate the code if self.introCheckBox.isChecked(): - code = "#!/usr/bin/env python{0}{1}".format( - sys.version_info[0], os.linesep) + code = "#!/usr/bin/env python3{0}".format(os.linesep) code += "# -*- coding: utf-8 -*-{0}{0}".format(os.linesep) else: code = ""
--- a/eric6/Preferences/__init__.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Preferences/__init__.py Tue Jun 23 17:24:18 2020 +0200 @@ -464,7 +464,7 @@ "DefaultEncoding": "utf-8", "DefaultOpenFilter": QCoreApplication.translate( - 'Lexers', 'Python Files (*.py *.py2 *.py3)'), + 'Lexers', 'Python Files (*.py *.py3)'), "DefaultSaveFilter": QCoreApplication.translate( 'Lexers', "Python3 Files (*.py)"), "AdditionalOpenFilters": [], @@ -1578,7 +1578,6 @@ # backward compatibility fot Qt < 5.10 pass - # Avoid nasty behavior of QSettings in combination with Py2 Prefs.settings.value("UI/SingleApplicationMode")
--- a/eric6/Project/Project.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Project/Project.py Tue Jun 23 17:24:18 2020 +0200 @@ -228,7 +228,6 @@ return ['.js'] elif language == "Mixed": return (Preferences.getPython("Python3Extensions") + - Preferences.getPython("PythonExtensions") + ['.rb', '.js']) else: return [""]
--- a/eric6/QScintilla/Editor.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/QScintilla/Editor.py Tue Jun 23 17:24:18 2020 +0200 @@ -2041,7 +2041,7 @@ @return flag reporting always False @rtype bool """ - # kept to kep the API compatible for plugins + # kept to keep the API compatible for plugins return False def isPy3File(self):
--- a/eric6/QScintilla/Lexers/__init__.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/QScintilla/Lexers/__init__.py Tue Jun 23 17:24:18 2020 +0200 @@ -386,10 +386,10 @@ openFileFiltersList = [ QCoreApplication.translate( 'Lexers', - 'Python Files (*.py *.py2 *.py3)'), + 'Python Files (*.py *.py3)'), QCoreApplication.translate( 'Lexers', - 'Python GUI Files (*.pyw *.pyw2 *.pyw3)'), + 'Python GUI Files (*.pyw *.pyw3)'), QCoreApplication.translate( 'Lexers', 'Cython Files (*.pyx *.pxd *.pxi)'), @@ -816,8 +816,6 @@ "*.rc": "Properties", '*.py': "Python", '*.pyw': "Python", - '*.py2': "Python", - '*.pyw2': "Python", '*.py3': "Python", '*.pyw3': "Python", '*.pyx': "Cython",
--- a/eric6/Utilities/BackgroundClient.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Utilities/BackgroundClient.py Tue Jun 23 17:24:18 2020 +0200 @@ -87,8 +87,7 @@ data = str(data) packedData = json.dumps([fx, fn, data]) - if sys.version_info[0] >= 3: - packedData = bytes(packedData, 'utf-8') + packedData = bytes(packedData, 'utf-8') header = struct.pack( b'!II', len(packedData), adler32(packedData) & 0xffffffff) self.connection.sendall(header) @@ -164,8 +163,7 @@ if adler32(packedData) & 0xffffffff != datahash: raise RuntimeError('Hashes not equal') - if sys.version_info[0] >= 3: - packedData = packedData.decode('utf-8') + packedData = packedData.decode('utf-8') fx, fn, data = json.loads(packedData) if fx == 'INIT':
--- a/eric6/Utilities/ClassBrowsers/__init__.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Utilities/ClassBrowsers/__init__.py Tue Jun 23 17:24:18 2020 +0200 @@ -81,7 +81,6 @@ dictionary = jsclbr.readmodule_ex(module, path) jsclbr._modules.clear() elif ( - ext in Preferences.getPython("PythonExtensions") or ext in Preferences.getPython("Python3Extensions") or isPyFile ): @@ -156,8 +155,7 @@ elif ( name.lower().endswith( - tuple(Preferences.getPython("PythonExtensions") + - Preferences.getPython("Python3Extensions"))) or + tuple(Preferences.getPython("Python3Extensions"))) or isPyFile ): for p in path: # search in path
--- a/eric6/Utilities/__init__.py Mon Jun 22 17:55:06 2020 +0200 +++ b/eric6/Utilities/__init__.py Tue Jun 23 17:24:18 2020 +0200 @@ -1622,7 +1622,6 @@ source = readEncodedFile(filename)[0] flags = extractFlags(source) ext = os.path.splitext(filename)[1] - py2Ext = Preferences.getPython("PythonExtensions") py3Ext = Preferences.getPython("Python3Extensions") project = e5App().getObject('Project') basename = os.path.basename(filename) @@ -1642,11 +1641,9 @@ elif (Preferences.getProject("DeterminePyFromProject") and project.isOpen() and project.isProjectFile(filename) and - ext in py2Ext + py3Ext): + ext in py3Ext): pyVer = pyAssignment.get(project.getProjectLanguage(), 0) - elif ext in py2Ext and ext not in py3Ext: - pyVer = 2 - elif ext in py3Ext and ext not in py2Ext: + elif ext in py3Ext: pyVer = 3 elif source: if isinstance(source, str): @@ -1657,10 +1654,10 @@ if "python3" in line0: pyVer = 3 elif "python" in line0: - pyVer = 2 + pyVer = 3 - if pyVer == 0 and ext in py2Ext + py3Ext: - pyVer = sys.version_info[0] + if pyVer == 0 and ext in py3Ext: + pyVer = 3 return pyVer
--- a/scripts/install-debugclients.py Mon Jun 22 17:55:06 2020 +0200 +++ b/scripts/install-debugclients.py Tue Jun 23 17:24:18 2020 +0200 @@ -252,13 +252,9 @@ global progName, modDir, doCleanup, doCompile, distDir global sourceDir - if ( - sys.version_info < (2, 7, 0) or - (sys.version_info >= (3, 0, 0) and sys.version_info < (3, 5, 0)) or - sys.version_info >= (4, 0, 0) - ): - print('Sorry, the eric6 debugger requires Python 2.7 or' - 'Python 3.5 or better for running.') + if sys.version_info < (3, 5, 0) or sys.version_info >= (4, 0, 0): + print('Sorry, the eric6 debugger requires Python 3.5 or better' + ' for running.') exit(5) progName = os.path.basename(argv[0])
--- a/scripts/install.py Mon Jun 22 17:55:06 2020 +0200 +++ b/scripts/install.py Tue Jun 23 17:24:18 2020 +0200 @@ -1372,9 +1372,6 @@ if sys.version_info < (3, 5, 0): print('Sorry, you must have Python 3.5.0 or higher.') exit(5) - if sys.version_info[0] > 3: - print('Sorry, eric6 requires Python 3 for running.') - exit(5) try: import xml.etree # __IGNORE_WARNING__