Merged with default branch to prepare release 21.9. maintenance release-21.09

Sat, 04 Sep 2021 11:34:54 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 04 Sep 2021 11:34:54 +0200
branch
maintenance
changeset 8576
fe1957c69854
parent 8451
d0123f020daa (current diff)
parent 8560
532068b0edb4 (diff)
child 8577
017669ce3d3f

Merged with default branch to prepare release 21.9.

docs/changelog file | annotate | diff | comparison | revisions
eric6/APIs/Python3/eric6.api file | annotate | diff | comparison | revisions
eric6/DebugClients/Python/DebugClientBase.py file | annotate | diff | comparison | revisions
eric6/DebugClients/Python/DebugVariables.py file | annotate | diff | comparison | revisions
eric6/Debugger/VariablesViewer.py file | annotate | diff | comparison | revisions
eric6/Documentation/Help/source.qch file | annotate | diff | comparison | revisions
eric6/Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/EditorAutocompletionPage.ui file | annotate | diff | comparison | revisions
eric6/Preferences/__init__.py file | annotate | diff | comparison | revisions
eric6/PyUnit/UnittestDialog.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Editor.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Shell.py file | annotate | diff | comparison | revisions
eric6/Utilities/BackgroundService.py file | annotate | diff | comparison | revisions
eric6/Utilities/ModuleParser.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
scripts/install.py file | annotate | diff | comparison | revisions
--- a/.hgignore	Sat Jul 03 11:47:48 2021 +0200
+++ b/.hgignore	Sat Sep 04 11:34:54 2021 +0200
@@ -5,6 +5,7 @@
 glob:.eric7project
 glob:.ropeproject
 glob:_ropeproject
+glob:.jedi
 glob:.directory
 glob:**.pyc
 glob:**.orig
--- a/docs/changelog	Sat Jul 03 11:47:48 2021 +0200
+++ b/docs/changelog	Sat Sep 04 11:34:54 2021 +0200
@@ -1,5 +1,12 @@
 Change Log
 ----------
+Version 21.9:
+- bug fixes
+- MicroPython
+  -- extended the list of known CircuitPython and UF2 capable devices
+- Unit Test
+  -- added support for sub-tests
+
 Version 21.7:
 - bug fixes
 
--- a/eric6/APIs/Python3/eric6.api	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/APIs/Python3/eric6.api	Sat Sep 04 11:34:54 2021 +0200
@@ -245,6 +245,7 @@
 eric6.DebugClients.Python.DCTestResult.DCTestResult.addExpectedFailure?4(test, err)
 eric6.DebugClients.Python.DCTestResult.DCTestResult.addFailure?4(test, err)
 eric6.DebugClients.Python.DCTestResult.DCTestResult.addSkip?4(test, reason)
+eric6.DebugClients.Python.DCTestResult.DCTestResult.addSubTest?4(test, subtest, err)
 eric6.DebugClients.Python.DCTestResult.DCTestResult.addUnexpectedSuccess?4(test)
 eric6.DebugClients.Python.DCTestResult.DCTestResult.startTest?4(test)
 eric6.DebugClients.Python.DCTestResult.DCTestResult.stopTest?4(test)
@@ -3718,6 +3719,7 @@
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse._Unparser.write_item?4()
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse._Unparser.write_key_value_pair?4(v)
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse._Unparser?2(*, _avoid_backslashes=False)
+eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.nullcontext?1(enter_result=None)
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.unparse?4(ast_obj)
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.translations._simplifyMessages?8
 eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.translations._simplifyMessagesSampleArgs?8
@@ -7679,6 +7681,7 @@
 eric6.PyUnit.UnittestDialog.QtTestResult.addExpectedFailure?4(test, err)
 eric6.PyUnit.UnittestDialog.QtTestResult.addFailure?4(test, err)
 eric6.PyUnit.UnittestDialog.QtTestResult.addSkip?4(test, reason)
+eric6.PyUnit.UnittestDialog.QtTestResult.addSubTest?4(test, subtest, err)
 eric6.PyUnit.UnittestDialog.QtTestResult.addUnexpectedSuccess?4(test)
 eric6.PyUnit.UnittestDialog.QtTestResult.startTest?4(test)
 eric6.PyUnit.UnittestDialog.QtTestResult.stopTest?4(test)
@@ -8686,6 +8689,7 @@
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.replaceTarget?4(replaceStr)
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.scrollVertical?4(lines)
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.selectionIsRectangle?4()
+eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.setAutoCompletionWidgetSize?4(chars, lines)
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.setCaretLineAlwaysVisible?4(alwaysVisible)
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.setContractedFolds?4(folds)
 eric6.QScintilla.QsciScintillaCompat.QsciScintillaCompat.setCurrentIndicator?4(indicator)
--- a/eric6/APIs/Python3/eric6.bas	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/APIs/Python3/eric6.bas	Sat Sep 04 11:34:54 2021 +0200
@@ -1073,3 +1073,4 @@
 ZoomValuesModel QAbstractTableModel
 _Precedence IntEnum
 _Unparser ast.NodeVisitor
+nullcontext AbstractContextManager
--- a/eric6/DebugClients/Python/DCTestResult.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/DebugClients/Python/DCTestResult.py	Sat Sep 04 11:34:54 2021 +0200
@@ -29,7 +29,7 @@
         TestResult.__init__(self)
         self.__dbgClient = dbgClient
         self.failfast = failfast
-        
+    
     def addFailure(self, test, err):
         """
         Public method called if a test failed.
@@ -44,7 +44,7 @@
             "traceback": tracebackLines,
             "id": test.id(),
         })
-        
+    
     def addError(self, test, err):
         """
         Public method called if a test errored.
@@ -59,7 +59,31 @@
             "traceback": tracebackLines,
             "id": test.id(),
         })
+    
+    def addSubTest(self, test, subtest, err):
+        """
+        Public method called for each subtest to record its result.
         
+        @param test reference to the test object
+        @param subtest reference to the subtest object
+        @param err error traceback
+        """
+        if err is not None:
+            TestResult.addSubTest(self, test, subtest, err)
+            tracebackLines = self._exc_info_to_string(err, test)
+            if issubclass(err[0], test.failureException):
+                self.__dbgClient.sendJsonCommand("ResponseUTTestFailed", {
+                    "testname": str(subtest),
+                    "traceback": tracebackLines,
+                    "id": test.id(),
+                })
+            else:
+                self.__dbgClient.sendJsonCommand("ResponseUTTestErrored", {
+                    "testname": str(subtest),
+                    "traceback": tracebackLines,
+                    "id": test.id(),
+                })
+    
     def addSkip(self, test, reason):
         """
         Public method called if a test was skipped.
@@ -73,7 +97,7 @@
             "reason": reason,
             "id": test.id(),
         })
-        
+    
     def addExpectedFailure(self, test, err):
         """
         Public method called if a test failed expected.
@@ -88,7 +112,7 @@
             "traceback": tracebackLines,
             "id": test.id(),
         })
-        
+    
     def addUnexpectedSuccess(self, test):
         """
         Public method called if a test succeeded expectedly.
@@ -100,7 +124,7 @@
             "testname": str(test),
             "id": test.id(),
         })
-        
+    
     def startTest(self, test):
         """
         Public method called at the start of a test.
@@ -112,7 +136,7 @@
             "testname": str(test),
             "description": test.shortDescription(),
         })
-
+    
     def stopTest(self, test):
         """
         Public method called at the end of a test.
--- a/eric6/DebugClients/Python/DebugClientBase.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/DebugClients/Python/DebugClientBase.py	Sat Sep 04 11:34:54 2021 +0200
@@ -922,6 +922,7 @@
                 self.cover.start()
             self.debugging = params["debug"]
             if params["debug"]:
+                self.multiprocessSupport = False
                 locals_ = locals()
                 self.threads.clear()
                 self.attachThread(mainThread=True)
--- a/eric6/DebugClients/Python/DebugVariables.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/DebugClients/Python/DebugVariables.py	Sat Sep 04 11:34:54 2021 +0200
@@ -208,7 +208,7 @@
         try:
             return var[int(attribute)]
         except Exception:
-            return getattr(var, attribute, None)
+            return getattr(var, str(attribute), None)
     
     def getDictionary(self, var):
         """
--- a/eric6/Debugger/VariablesViewer.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Debugger/VariablesViewer.py	Sat Sep 04 11:34:54 2021 +0200
@@ -192,6 +192,7 @@
             else:
                 dvalue = VariableItem.unsized
             self.hasChildren = True
+        
         elif dtype in VariableItem.arrayTypes:
             self.childCount = int(dvalue)
             dvalue = VariableItem.noOfItemsStr.format(dvalue)
@@ -211,22 +212,24 @@
             dvalue.endswith(("}", ")", "]"))
         ):
             # it is most probably a dict, tuple or list derived class
-            value = ast.literal_eval(dvalue)
-            valueTypeStr = str(type(value))[8:-2]
-            if valueTypeStr in VariableItem.arrayTypes:
-                self.childCount = len(value)
-                self.hasChildren = True
+            with contextlib.suppress(Exception):
+                value = ast.literal_eval(dvalue)
+                valueTypeStr = str(type(value))[8:-2]
+                if valueTypeStr in VariableItem.arrayTypes:
+                    self.childCount = len(value)
+                    self.hasChildren = True
         
         elif (
             (dvalue.endswith("})") and "({" in dvalue) or
             (dvalue.endswith("])") and "([" in dvalue)
         ):
             # that is probably a set derived class
-            value = ast.literal_eval(dvalue.split("(", 1)[1][:-1])
-            valueTypeStr = str(type(value))[8:-2]
-            if valueTypeStr in VariableItem.arrayTypes:
-                self.childCount = len(value)
-                self.hasChildren = True
+            with contextlib.suppress(Exception):
+                value = ast.literal_eval(dvalue.split("(", 1)[1][:-1])
+                valueTypeStr = str(type(value))[8:-2]
+                if valueTypeStr in VariableItem.arrayTypes:
+                    self.childCount = len(value)
+                    self.hasChildren = True
         
         self.value = dvalue
         
@@ -443,6 +446,7 @@
                     child.value = newItem.value
                     child.valueShort = newItem.valueShort
                     child.tooltip = newItem.tooltip
+                    child.nameWithId = newItem.nameWithId
                     
                     child.currentCount = -1
                     child.populated = False
Binary file eric6/Documentation/Help/source.qch has changed
--- a/eric6/Documentation/Help/source.qhp	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Documentation/Help/source.qhp	Sat Sep 04 11:34:54 2021 +0200
@@ -3212,6 +3212,7 @@
       <keyword name="DCTestResult.addExpectedFailure" id="DCTestResult.addExpectedFailure" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.addExpectedFailure" />
       <keyword name="DCTestResult.addFailure" id="DCTestResult.addFailure" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.addFailure" />
       <keyword name="DCTestResult.addSkip" id="DCTestResult.addSkip" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.addSkip" />
+      <keyword name="DCTestResult.addSubTest" id="DCTestResult.addSubTest" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.addSubTest" />
       <keyword name="DCTestResult.addUnexpectedSuccess" id="DCTestResult.addUnexpectedSuccess" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.addUnexpectedSuccess" />
       <keyword name="DCTestResult.startTest" id="DCTestResult.startTest" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.startTest" />
       <keyword name="DCTestResult.stopTest" id="DCTestResult.stopTest" ref="eric6.DebugClients.Python.DCTestResult.html#DCTestResult.stopTest" />
@@ -12468,6 +12469,7 @@
       <keyword name="QsciScintillaCompat.replaceTarget" id="QsciScintillaCompat.replaceTarget" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.replaceTarget" />
       <keyword name="QsciScintillaCompat.scrollVertical" id="QsciScintillaCompat.scrollVertical" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.scrollVertical" />
       <keyword name="QsciScintillaCompat.selectionIsRectangle" id="QsciScintillaCompat.selectionIsRectangle" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.selectionIsRectangle" />
+      <keyword name="QsciScintillaCompat.setAutoCompletionWidgetSize" id="QsciScintillaCompat.setAutoCompletionWidgetSize" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.setAutoCompletionWidgetSize" />
       <keyword name="QsciScintillaCompat.setCaretLineAlwaysVisible" id="QsciScintillaCompat.setCaretLineAlwaysVisible" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.setCaretLineAlwaysVisible" />
       <keyword name="QsciScintillaCompat.setContractedFolds" id="QsciScintillaCompat.setContractedFolds" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.setContractedFolds" />
       <keyword name="QsciScintillaCompat.setCurrentIndicator" id="QsciScintillaCompat.setCurrentIndicator" ref="eric6.QScintilla.QsciScintillaCompat.html#QsciScintillaCompat.setCurrentIndicator" />
@@ -12569,6 +12571,7 @@
       <keyword name="QtTestResult.addExpectedFailure" id="QtTestResult.addExpectedFailure" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.addExpectedFailure" />
       <keyword name="QtTestResult.addFailure" id="QtTestResult.addFailure" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.addFailure" />
       <keyword name="QtTestResult.addSkip" id="QtTestResult.addSkip" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.addSkip" />
+      <keyword name="QtTestResult.addSubTest" id="QtTestResult.addSubTest" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.addSubTest" />
       <keyword name="QtTestResult.addUnexpectedSuccess" id="QtTestResult.addUnexpectedSuccess" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.addUnexpectedSuccess" />
       <keyword name="QtTestResult.startTest" id="QtTestResult.startTest" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.startTest" />
       <keyword name="QtTestResult.stopTest" id="QtTestResult.stopTest" ref="eric6.PyUnit.UnittestDialog.html#QtTestResult.stopTest" />
@@ -18319,6 +18322,10 @@
       <keyword name="normcaseabspath" id="normcaseabspath" ref="eric6.Utilities.__init__.html#normcaseabspath" />
       <keyword name="normcasepath" id="normcasepath" ref="eric6.Utilities.__init__.html#normcasepath" />
       <keyword name="normjoinpath" id="normjoinpath" ref="eric6.Utilities.__init__.html#normjoinpath" />
+      <keyword name="nullcontext" id="nullcontext" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html#nullcontext" />
+      <keyword name="nullcontext (Constructor)" id="nullcontext (Constructor)" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html#nullcontext.__init__" />
+      <keyword name="nullcontext.__enter__" id="nullcontext.__enter__" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html#nullcontext.__enter__" />
+      <keyword name="nullcontext.__exit__" id="nullcontext.__exit__" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html#nullcontext.__exit__" />
       <keyword name="objectName" id="objectName" ref="eric6.Project.UicLoadUi5.html#objectName" />
       <keyword name="objectName" id="objectName" ref="eric6.Project.UicLoadUi6.html#objectName" />
       <keyword name="okToClearData" id="okToClearData" ref="eric6.E5Gui.E5MessageBox.html#okToClearData" />
--- a/eric6/Documentation/Source/eric6.DebugClients.Python.DCTestResult.html	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Documentation/Source/eric6.DebugClients.Python.DCTestResult.html	Sat Sep 04 11:34:54 2021 +0200
@@ -92,6 +92,10 @@
 <td>Public method called if a test was skipped.</td>
 </tr>
 <tr>
+<td><a href="#DCTestResult.addSubTest">addSubTest</a></td>
+<td>Public method called for each subtest to record its result.</td>
+</tr>
+<tr>
 <td><a href="#DCTestResult.addUnexpectedSuccess">addUnexpectedSuccess</a></td>
 <td>Public method called if a test succeeded expectedly.</td>
 </tr>
@@ -200,6 +204,28 @@
 reason for skipping the test (string)
 </dd>
 </dl>
+<a NAME="DCTestResult.addSubTest" ID="DCTestResult.addSubTest"></a>
+<h4>DCTestResult.addSubTest</h4>
+<b>addSubTest</b>(<i>test, subtest, err</i>)
+
+<p>
+        Public method called for each subtest to record its result.
+</p>
+<dl>
+
+<dt><i>test</i></dt>
+<dd>
+reference to the test object
+</dd>
+<dt><i>subtest</i></dt>
+<dd>
+reference to the subtest object
+</dd>
+<dt><i>err</i></dt>
+<dd>
+error traceback
+</dd>
+</dl>
 <a NAME="DCTestResult.addUnexpectedSuccess" ID="DCTestResult.addUnexpectedSuccess"></a>
 <h4>DCTestResult.addUnexpectedSuccess</h4>
 <b>addUnexpectedSuccess</b>(<i>test</i>)
--- a/eric6/Documentation/Source/eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Documentation/Source/eric6.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.ast_unparse.html	Sat Sep 04 11:34:54 2021 +0200
@@ -39,6 +39,10 @@
 <td><a href="#_Unparser">_Unparser</a></td>
 <td>Methods in this class recursively traverse an AST and output source code for the abstract syntax; original formatting is disregarded.</td>
 </tr>
+<tr>
+<td><a href="#nullcontext">nullcontext</a></td>
+<td>Context manager that does no additional processing.</td>
+</tr>
 </table>
 <h3>Functions</h3>
 
@@ -934,6 +938,71 @@
 <div align="right"><a href="#top">Up</a></div>
 <hr />
 <hr />
+<a NAME="nullcontext" ID="nullcontext"></a>
+<h2>nullcontext</h2>
+
+<p>
+Context manager that does no additional processing.
+</p>
+<p>
+        Used as a stand-in for a normal context manager, when a particular
+        block of code is only sometimes used with a normal context manager:
+</p>
+<p>
+        cm = optional_cm if condition else nullcontext()
+        with cm:
+            # Perform operation, using optional_cm if condition is True
+</p>
+<h3>Derived from</h3>
+AbstractContextManager
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#nullcontext.__init__">nullcontext</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#nullcontext.__enter__">__enter__</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#nullcontext.__exit__">__exit__</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="nullcontext.__init__" ID="nullcontext.__init__"></a>
+<h4>nullcontext (Constructor)</h4>
+<b>nullcontext</b>(<i>enter_result=None</i>)
+
+<a NAME="nullcontext.__enter__" ID="nullcontext.__enter__"></a>
+<h4>nullcontext.__enter__</h4>
+<b>__enter__</b>(<i></i>)
+
+<a NAME="nullcontext.__exit__" ID="nullcontext.__exit__"></a>
+<h4>nullcontext.__exit__</h4>
+<b>__exit__</b>(<i>*excinfo</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
 <a NAME="unparse" ID="unparse"></a>
 <h2>unparse</h2>
 <b>unparse</b>(<i>ast_obj</i>)
--- a/eric6/Documentation/Source/eric6.PyUnit.UnittestDialog.html	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Documentation/Source/eric6.PyUnit.UnittestDialog.html	Sat Sep 04 11:34:54 2021 +0200
@@ -100,6 +100,10 @@
 <td>Public method called if a test was skipped.</td>
 </tr>
 <tr>
+<td><a href="#QtTestResult.addSubTest">addSubTest</a></td>
+<td>Public method called for each subtest to record its result.</td>
+</tr>
+<tr>
 <td><a href="#QtTestResult.addUnexpectedSuccess">addUnexpectedSuccess</a></td>
 <td>Public method called if a test succeeded expectedly.</td>
 </tr>
@@ -208,6 +212,28 @@
 reason for skipping the test (string)
 </dd>
 </dl>
+<a NAME="QtTestResult.addSubTest" ID="QtTestResult.addSubTest"></a>
+<h4>QtTestResult.addSubTest</h4>
+<b>addSubTest</b>(<i>test, subtest, err</i>)
+
+<p>
+        Public method called for each subtest to record its result.
+</p>
+<dl>
+
+<dt><i>test</i></dt>
+<dd>
+reference to the test object
+</dd>
+<dt><i>subtest</i></dt>
+<dd>
+reference to the subtest object
+</dd>
+<dt><i>err</i></dt>
+<dd>
+error traceback
+</dd>
+</dl>
 <a NAME="QtTestResult.addUnexpectedSuccess" ID="QtTestResult.addUnexpectedSuccess"></a>
 <h4>QtTestResult.addUnexpectedSuccess</h4>
 <b>addUnexpectedSuccess</b>(<i>test</i>)
--- a/eric6/Documentation/Source/eric6.QScintilla.QsciScintillaCompat.html	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Documentation/Source/eric6.QScintilla.QsciScintillaCompat.html	Sat Sep 04 11:34:54 2021 +0200
@@ -442,6 +442,10 @@
 <td>Public method to check, if the current selection is rectangular.</td>
 </tr>
 <tr>
+<td><a href="#QsciScintillaCompat.setAutoCompletionWidgetSize">setAutoCompletionWidgetSize</a></td>
+<td>Public method to set the size of completion and user lists.</td>
+</tr>
+<tr>
 <td><a href="#QsciScintillaCompat.setCaretLineAlwaysVisible">setCaretLineAlwaysVisible</a></td>
 <td>Public method to set the caret line visible even if the editor doesn't have the focus.</td>
 </tr>
@@ -1990,6 +1994,24 @@
 flag indicating a rectangular selection (boolean)
 </dd>
 </dl>
+<a NAME="QsciScintillaCompat.setAutoCompletionWidgetSize" ID="QsciScintillaCompat.setAutoCompletionWidgetSize"></a>
+<h4>QsciScintillaCompat.setAutoCompletionWidgetSize</h4>
+<b>setAutoCompletionWidgetSize</b>(<i>chars, lines</i>)
+
+<p>
+        Public method to set the size of completion and user lists.
+</p>
+<dl>
+
+<dt><i>chars</i> (int)</dt>
+<dd>
+max. number of chars to show
+</dd>
+<dt><i>lines</i> (int)</dt>
+<dd>
+max. number of lines to show
+</dd>
+</dl>
 <a NAME="QsciScintillaCompat.setCaretLineAlwaysVisible" ID="QsciScintillaCompat.setCaretLineAlwaysVisible"></a>
 <h4>QsciScintillaCompat.setCaretLineAlwaysVisible</h4>
 <b>setCaretLineAlwaysVisible</b>(<i>alwaysVisible</i>)
--- a/eric6/MicroPython/MicroPythonDevices.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/MicroPython/MicroPythonDevices.py	Sat Sep 04 11:34:54 2021 +0200
@@ -40,6 +40,7 @@
     
     "circuitpython": {
         "ids": [
+            (0x04D8, 0xEA2A),       # BHDynamics DynaLoRa_USB
             (0x04D8, 0xEAD1),       # BH Dynamics DynOSSAT-EDU-EPS-v1.0
             (0x04D8, 0xEAD2),       # BH Dynamics DynOSSAT-EDU-OBC-v1.0
             (0x04D8, 0xEC44),       # maholli PyCubed
@@ -55,6 +56,7 @@
             (0x04D8, 0xEE8D),       # J&J Studios LLC datum-IMU
             (0x04D8, 0xEE8E),       # J&J Studios LLC datum-Light
             (0x04D8, 0xEE8F),       # J&J Studios LLC datum-Weather
+            (0x04D8, 0xEF67),       # senseBox MCU
             (0x054C, 0x0BC2),       # Sony Spresense
             (0x1209, 0x2017),       # Benjamin Shockley Mini SAM M4
             (0x1209, 0x3252),       # Targett Module Clip w/Wroom
@@ -62,7 +64,9 @@
             (0x1209, 0x4D43),       # Robotics Masters Robo HAT MM1 M4
             (0x1209, 0x4DDD),       # ODT CP Sapling
             (0x1209, 0x4DDE),       # ODT CP Sapling M0 w/ SPI Flash
+            (0x1209, 0x4DDF),       # ODT CP Sapling Rev B
             (0x1209, 0x5BF0),       # Foosn Fomu
+            (0x1209, 0x7150),       # Electronic Cats Hunter Cat NFC
             (0x1209, 0x805A),       # Electronic Cats BastBLE
             (0x1209, 0xBAB0),       # Electronic Cats Bast WiFi
             (0x1209, 0xBAB1),       # Electronic Cats Meow Meow
@@ -73,10 +77,18 @@
             (0x1209, 0xC051),       # Betrusted Simmel
             (0x1209, 0xE3E3),       # StackRduino M0 PRO
             (0x1209, 0xF500),       # Silicognition LLC M4-Shim
+            (0x16D0, 0x08C6),       # Pimoroni Keybow 2040
+            (0x16D0, 0x08C7),       # Pimoroni Tiny 2040
+            (0x16D0, 0x08C8),       # Pimoroni PicoSystem
             (0x1915, 0xB001),       # Makerdiary Pitaya Go
             (0x1B4F, 0x0015),       # SparkFun RedBoard Turbo Board
             (0x1B4F, 0x0016),       # SparkFun SAMD51 Thing+
             (0x1B4F, 0x0017),       # SparkFun LUMIDrive Board
+            (0x1B4F, 0x0020),       # SparkFun MicroMod SAMD51
+            (0x1B4F, 0x0021),       # SparkFun SFE_nRF52840_MicroMod
+            (0x1B4F, 0x0024),       # SparkFun MicroMod RP2040
+            (0x1B4F, 0x0025),       # SparkFun Thing Plus RP2040
+            (0x1B4F, 0x0026),       # SparkFun Pro Micro RP2040
             (0x1B4F, 0x5289),       # SparkFun SFE_nRF52840_Mini
             (0x1B4F, 0x8D22),       # SparkFun SAMD21 Mini Breakout
             (0x1B4F, 0x8D23),       # SparkFun SAMD21 Dev Breakout
@@ -94,10 +106,20 @@
             (0x2B04, 0xC00C),       # Particle Argon
             (0x2B04, 0xC00D),       # Particle Boron
             (0x2B04, 0xC00E),       # Particle Xenon
+            (0x2E8A, 0x1000),       # Cytron Maker Pi RP2040
+            (0x2E8A, 0x1002),       # Pimoroni Pico LiPo (4MB)
+            (0x2E8A, 0x1003),       # Pimoroni Pico LiPo (16MB)
+            (0x2E8A, 0x1008),       # Pimoroni PGA2040
+            (0x303A, 0x8002),       # UnexpectedMaker TinyS2
             (0x303A, 0x8007),       # LILYGO TTGO T8 ESP32-S2
-            (0x3171, 0x0101),       # 8086 Consultancy Commander
+            (0x303A, 0x80AA),       # Espressif Franzininho WIFI w/Wroom
+            (0x303A, 0x80AD),       # Espressif Franzininho WIFI w/Wrover
+            (0x303A, 0x80AF),       # Artisense Reference Design RD00
+            (0x303A, 0x80B2),       # Muselab nanoESP32-S2  w/Wrover
+            (0x3171, 0x0101),       # 8086.net Commander
             (0x31E2, 0x2001),       # BDMICRO LLC VINA-D21
             (0x31E2, 0x2011),       # BDMICRO LLC VINA-D51
+            (0x31E2, 0x2021),       # BDMICRO LLC VINA-D51
             (0x32BD, 0x3001),       # Alorium Tech. AloriumTech Evo M51
             (0x4097, 0x0001),       # TG-Boards Datalore IP M4
             
@@ -201,27 +223,36 @@
     
     availablePorts = QSerialPortInfo.availablePorts()
     for port in availablePorts:
-        supported = False
-        vid = port.vendorIdentifier()
-        pid = port.productIdentifier()
-        
-        if not port.isValid():
-            # no device detected at port
-            continue
-        
-        for board in SupportedBoards:
-            if (
-                (vid, pid) in SupportedBoards[board]["ids"] or
-                (vid, None) in SupportedBoards[board]["ids"]
-            ):
+        if port.hasVendorIdentifier() and port.hasProductIdentifier():
+            supported = False
+            vid = port.vendorIdentifier()
+            pid = port.productIdentifier()
+            
+            for board in SupportedBoards:
                 if (
-                    board in ("bbc_microbit", "calliope") and
-                    (port.description().strip() !=
-                     SupportedBoards[board]["port_description"])
+                    (vid, pid) in SupportedBoards[board]["ids"] or
+                    (vid, None) in SupportedBoards[board]["ids"]
                 ):
-                    # both boards have the same VID and PID
-                    # try to differentiate based on port description
-                    continue
+                    if (
+                        board in ("bbc_microbit", "calliope") and
+                        (port.description().strip() !=
+                         SupportedBoards[board]["port_description"])
+                    ):
+                        # both boards have the same VID and PID
+                        # try to differentiate based on port description
+                        continue
+                    foundDevices.append((
+                        board,
+                        port.description(),
+                        SupportedBoards[board]["description"],
+                        port.portName(),
+                        vid,
+                        pid,
+                    ))
+                    supported = True
+            if not supported and (vid, pid) in manualDevices:
+                # check the locally added ones next
+                board = manualDevices[(vid, pid)]["type"]
                 foundDevices.append((
                     board,
                     port.description(),
@@ -231,31 +262,19 @@
                     pid,
                 ))
                 supported = True
-        if not supported and (vid, pid) in manualDevices:
-            # check the locally added ones next
-            board = manualDevices[(vid, pid)]["type"]
-            foundDevices.append((
-                board,
-                port.description(),
-                SupportedBoards[board]["description"],
-                port.portName(),
-                vid,
-                pid,
-            ))
-            supported = True
-        if not supported:
-            if vid and pid:
-                if (vid, pid) not in IgnoredBoards:
-                    unknownDevices.append((vid, pid, port.description()))
-                    logging.debug("Unknown device: (0x%04x:0x%04x %s)",
-                                  vid, pid, port.description())
-            else:
-                # either VID or PID or both not detected
-                desc = port.description()
-                if not desc:
-                    desc = QCoreApplication.translate("MicroPythonDevice",
-                                                      "Unknown Device")
-                unknownPorts.append((vid, pid, desc, port.portName()))
+            if not supported:
+                if vid and pid:
+                    if (vid, pid) not in IgnoredBoards:
+                        unknownDevices.append((vid, pid, port.description()))
+                        logging.debug("Unknown device: (0x%04x:0x%04x %s)",
+                                      vid, pid, port.description())
+                else:
+                    # either VID or PID or both not detected
+                    desc = port.description()
+                    if not desc:
+                        desc = QCoreApplication.translate("MicroPythonDevice",
+                                                          "Unknown Device")
+                    unknownPorts.append((vid, pid, desc, port.portName()))
     
     return foundDevices, unknownDevices, unknownPorts
 
--- a/eric6/MicroPython/MicroPythonGraphWidget.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/MicroPython/MicroPythonGraphWidget.py	Sat Sep 04 11:34:54 2021 +0200
@@ -106,14 +106,19 @@
         self.__chart = QChart()
         self.__chart.legend().hide()
         self.__chart.addSeries(self.__series[0])
+        
         self.__axisX = QValueAxis()
+        self.__axisX.setLabelFormat("time")
+        self.__chart.addAxis(self.__axisX, Qt.AlignmentFlag.AlignBottom)
+        self.__series[0].attachAxis(self.__axisX)
         self.__axisX.setRange(0, self.__maxX)
-        self.__axisX.setLabelFormat("time")
+        
         self.__axisY = QValueAxis()
+        self.__axisY.setLabelFormat("%d")
+        self.__chart.addAxis(self.__axisY, Qt.AlignmentFlag.AlignLeft)
+        self.__series[0].attachAxis(self.__axisY)
         self.__axisY.setRange(-self.__maxY, self.__maxY)
-        self.__axisY.setLabelFormat("%d")
-        self.__chart.setAxisX(self.__axisX, self.__series[0])
-        self.__chart.setAxisY(self.__axisY, self.__series[0])
+        
         self.__chartView.setChart(self.__chart)
         self.__chartView.setRenderHint(QPainter.RenderHint.Antialiasing)
         self.preferencesChanged()
@@ -223,12 +228,12 @@
             valuesLen = len(values)
             seriesLen = len(self.__series)
             if valuesLen > seriesLen:
-                # add a nwe line series
+                # add a new line series
                 for _index in range(valuesLen - seriesLen):
                     newSeries = QLineSeries()
                     self.__chart.addSeries(newSeries)
-                    self.__chart.setAxisX(self.__axisX, newSeries)
-                    self.__chart.setAxisY(self.__axisY, newSeries)
+                    newSeries.attachAxis(self.__axisX)
+                    newSeries.attachAxis(self.__axisY)
                     self.__series.append(newSeries)
                     self.__data.append(deque([0] * self.__maxX))
             else:
--- a/eric6/MicroPython/UF2FlashDialog.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/MicroPython/UF2FlashDialog.py	Sat Sep 04 11:34:54 2021 +0200
@@ -85,14 +85,14 @@
             (0x16D0, 0x0CDA): [
                 "AUTOMAT",        # automat
             ],
-            (0x1B4F, 0x0019): [
-                "QwiicMicro",     # Sparkfun Qwiic Micro
+            (0x1B4F, 0x0022): [
+                "SFMM852BOOT",    # MicroMod nRF52840
             ],
             (0x1B4F, 0x0D22): [
-                "SPARKFUN",       # Sparkfun SAMD21 Mini Breakout
+                "SPARKFUN",       # SAMD21 Mini Breakout
             ],
             (0x1B4F, 0x0D23): [
-                "SPARKFUN",       # Sparkfun SAMD21 Dev Breakout
+                "SPARKFUN",       # SAMD21 Dev Breakout
             ],
             (0x1D50, 0x6110): [
                 "ROBOTICS",       # Robotics
@@ -155,7 +155,6 @@
                 "ARGONBOOT  ",    # Argon
                 "BORONBOOT  ",    # Boron
                 "FTHR840BOOT",    # Feather nRF52840 Express
-                "MDBT50QBOOT",    # Raytac MDBT50Q-RX
                 "MDK840DONGL",    # MDK nRF52840 USB Dongle
                 "WS52840EVK",     # Waveshare nRF52840 Eval
                 "XENONBOOT  ",    # Xenon
@@ -227,6 +226,9 @@
             (0x239A, 0x0065): [
                 "ND6BOOT",        # ndBit6
             ],
+            (0x239A, 0x0069): [
+                "STMF411BOOT",    # STM32F411 BlackPill
+            ],
             (0x239A, 0x006B): [
                 "shIRtty",        # shIRtty
             ],
@@ -239,6 +241,9 @@
             (0x239A, 0x0079): [
                 "ARAMBOOT",       # ARAMCON Badge 2019
             ],
+            (0x239A, 0x007B): [
+                "ARAMBOOT",       # ARAMCON2 Badge
+            ],
             (0x239A, 0x007D): [
                 "BOOKBOOT",       # The Open Book Feather
             ],
@@ -247,9 +252,11 @@
             ],
             (0x239A, 0x0081): [
                 "RT1020BOOT",     # RT1020 EVK
+                "RT1024BOOT",     # RT1024 EVK
             ],
             (0x239A, 0x0083): [
                 "RT1060BOOT",     # RT1060 EVK
+                "RT1064BOOT",     # RT1064 EVK
             ],
             (0x239A, 0x0087): [
                 "FTHRSNSBOOT",    # Feather nRF52840 Sense
@@ -296,20 +303,27 @@
             (0x239A, 0x00C7): [
                 "KALUGA1BOOT",    # Kaluga 1
             ],
+            (0x239A, 0x00C9): [
+                "MATRIXBOOT",     # Matrix Portal M4
+            ],
             (0x239A, 0x00CB): [
                 "QTPY_BOOT",      # QT Py M0
             ],
             (0x239A, 0x00CD): [
                 "FTHRCANBOOT",    # Feather M4 CAN Express
             ],
+            (0x239A, 0x00DE): [
+                "NANOESPBOOT",    # nanoESP32-S2 WROOM
+            ],
             (0x239A, 0x00DF): [
                 "METROS2BOOT",    # Metro ESP32-S2
             ],
             (0x239A, 0x00E1): [
-                "METROM7BOOT",    # Metro M7 1011
+                "METROM7BOOT",    # Metro M7 iMX RT1011
             ],
             (0x239A, 0x00E5): [
                 "MAGTAGBOOT",     # Metro MagTag 2.9 Grayscale
+                "MAGTAGBOOT",     # MagTag 2.9 Grayscale
             ],
             (0x239A, 0x00EB): [
                 "FTHRS2BOOT",     # Feather ESP32-S2
@@ -323,6 +337,27 @@
             (0x239A, 0x00F5): [
                 "STARBOOT",       # Binary Star
             ],
+            (0x239A, 0x00F9): [
+                "HOUSEBOOT",      # FunHouse
+            ],
+            (0x239A, 0x00FB): [
+                "TRINKEYBOOT",    # Rotary Trinkey M0
+            ],
+            (0x239A, 0x00FF): [
+                "TRINKEYBOOT",    # NeoKey Trinkey M0
+            ],
+            (0x239A, 0x0101): [
+                "TRINKEYBOOT",    # Slide Trinkey M0
+            ],
+            (0x239A, 0x0103): [
+                "TRINKEYBOOT",    # ProxSense Trinkey M0
+            ],
+            (0x239A, 0x010B): [
+                "MDBT50QBOOT",    # Raytac MDBT50Q-RX
+            ],
+            (0x239A, 0x800B): [
+                "ATMZBOOT",       # ATMegaZero ESP32-S2
+            ],
             (0x239A, 0xB000): [
                 "HALLOWBOOT",     # Hallowing M0
             ],
@@ -334,20 +369,29 @@
             ],
             (0x2886, 0x002F): [
                 "Seeed XIAO",     # Seeeduino XIAO
-                "Arduino",        # Seeeduino XIAO (old bootloader)
             ],
             (0x2886, 0xF00E): [
                 "PITAYAGO",       # Pitaya Go
             ],
             (0x2886, 0xF00F): [
+                "M60KEYBOARD",    # MakerDiary M60 Mechanical Keyboard
                 "nRF52840M2",     # MakerDiary nRF52840 M.2 Module
             ],
+            (0x303A, 0x8005): [
+                "TINYS2BOOT",     # TinyS2
+            ],
             (0x303A, 0x8008): [
                 "TTGOS2BOOT",     # TTGO_T8_S2_Display
             ],
             (0x303A, 0x800E): [
                 "CCMBRISBOOT",    # CucumberRIS v1.1
             ],
+            (0x303A, 0x80B0): [
+                "RD00RBOOT",      # Reference Design RD00
+            ],
+            (0x303A, 0x80B3): [
+                "NANOESPBOOT",    # nanoESP32-S2 WROVER
+            ],
             (0x3171, 0x0100): [
                 "CMDBOOT",        # COMMANDER
             ],
--- a/eric6/Preferences/ConfigurationPages/EditorAutocompletionPage.ui	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Preferences/ConfigurationPages/EditorAutocompletionPage.ui	Sat Sep 04 11:34:54 2021 +0200
@@ -144,10 +144,10 @@
            <number>20</number>
           </property>
           <property name="pageStep">
-           <number>2</number>
+           <number>5</number>
           </property>
           <property name="value">
-           <number>6</number>
+           <number>5</number>
           </property>
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
@@ -166,7 +166,7 @@
            <enum>QLCDNumber::Flat</enum>
           </property>
           <property name="intValue" stdset="0">
-           <number>6</number>
+           <number>5</number>
           </property>
          </widget>
         </item>
@@ -176,7 +176,7 @@
            <string>Move to set the maximum number of characters visible in one line.</string>
           </property>
           <property name="minimum">
-           <number>10</number>
+           <number>20</number>
           </property>
           <property name="maximum">
            <number>100</number>
--- a/eric6/Preferences/__init__.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Preferences/__init__.py	Sat Sep 04 11:34:54 2021 +0200
@@ -421,7 +421,7 @@
         "AutoCompletionCacheSize": 100,
         "AutoCompletionCacheTime": 300,     # 5 minutes
         "AutoCompletionWatchdogTime": 3000,     # ms
-        "AutoCompletionMaxLines": 6,
+        "AutoCompletionMaxLines": 5,
         "AutoCompletionMaxChars": 40,
         
         "CallTipsEnabled": False,
--- a/eric6/PyUnit/UnittestDialog.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/PyUnit/UnittestDialog.py	Sat Sep 04 11:34:54 2021 +0200
@@ -173,7 +173,7 @@
             "^Error: ",
         ]
         
-        self.__failedTests = []
+        self.__failedTests = set()
         
         # now connect the debug server signals if called from the eric IDE
         if self.__dbs:
@@ -766,13 +766,13 @@
                     clientType = "Python3"
                 sysPath = []
             if failedOnly and self.__failedTests:
-                failed = self.__failedTests[:]
+                failed = list(self.__failedTests)
                 if discover:
                     workdir = discoveryStart
                     discover = False
             else:
                 failed = []
-            self.__failedTests = []
+            self.__failedTests = set()
             self.__dbs.remoteUTPrepare(
                 testFileName, self.testName, testName, failed,
                 self.coverageCheckBox.isChecked(), coverageFile,
@@ -817,7 +817,7 @@
             try:
                 testLoader = unittest.TestLoader()
                 if failedOnly and self.__failedTests:
-                    failed = self.__failedTests[:]
+                    failed = list(self.__failedTests)
                     if discover:
                         os.chdir(discoveryStart)
                         discover = False
@@ -838,7 +838,7 @@
                             failed = [t.split(".", 1)[1]
                                       for t in self.__failedTests]
                         else:
-                            failed = self.__failedTests[:]
+                            failed = list(self.__failedTests)
                         test = testLoader.loadTestsFromNames(
                             failed, module)
                     else:
@@ -883,7 +883,7 @@
                     self.tr("Unittest"),
                     self.tr("""No unittest were found. Aborting..."""))
             else:
-                self.__failedTests = []
+                self.__failedTests = set()
                 self.__setRunningMode()
                 if cover:
                     cover.start()
@@ -1035,7 +1035,7 @@
         itm = QListWidgetItem(self.tr("Failure: {0}").format(test))
         itm.setData(UnittestDialog.ErrorsInfoRole, (test, exc))
         self.errorsListWidget.insertItem(0, itm)
-        self.__failedTests.append(testId)
+        self.__failedTests.add(testId)
     
     def testErrored(self, test, exc, testId):
         """
@@ -1050,7 +1050,7 @@
         itm = QListWidgetItem(self.tr("Error: {0}").format(test))
         itm.setData(UnittestDialog.ErrorsInfoRole, (test, exc))
         self.errorsListWidget.insertItem(0, itm)
-        self.__failedTests.append(testId)
+        self.__failedTests.add(testId)
     
     def testSkipped(self, test, reason, testId):
         """
@@ -1278,6 +1278,24 @@
         tracebackLines = self._exc_info_to_string(err, test)
         self.parent.testErrored(str(test), tracebackLines, test.id())
     
+    def addSubTest(self, test, subtest, err):
+        """
+        Public method called for each subtest to record its result.
+        
+        @param test reference to the test object
+        @param subtest reference to the subtest object
+        @param err error traceback
+        """
+        if err is not None:
+            super().addSubTest(test, subtest, err)
+            tracebackLines = self._exc_info_to_string(err, test)
+            if issubclass(err[0], test.failureException):
+                self.parent.testFailed(
+                    str(subtest), tracebackLines, test.id())
+            else:
+                self.parent.testErrored(
+                    str(subtest), tracebackLines, test.id())
+    
     def addSkip(self, test, reason):
         """
         Public method called if a test was skipped.
--- a/eric6/QScintilla/Editor.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/QScintilla/Editor.py	Sat Sep 04 11:34:54 2021 +0200
@@ -16,7 +16,7 @@
 
 from PyQt5.QtCore import (
     pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QFileInfo,
-    QCryptographicHash, QEvent, QDateTime, QPoint
+    QCryptographicHash, QEvent, QDateTime, QPoint, QSize
 )
 from PyQt5.QtGui import QPalette, QFont, QPixmap, QPainter
 from PyQt5.QtWidgets import (
@@ -585,36 +585,53 @@
         """
         Private method to register images for autocompletion lists.
         """
-        self.registerImage(self.ClassID,
-                           UI.PixmapCache.getPixmap("class"))
-        self.registerImage(self.ClassProtectedID,
-                           UI.PixmapCache.getPixmap("class_protected"))
-        self.registerImage(self.ClassPrivateID,
-                           UI.PixmapCache.getPixmap("class_private"))
-        self.registerImage(self.MethodID,
-                           UI.PixmapCache.getPixmap("method"))
-        self.registerImage(self.MethodProtectedID,
-                           UI.PixmapCache.getPixmap("method_protected"))
-        self.registerImage(self.MethodPrivateID,
-                           UI.PixmapCache.getPixmap("method_private"))
-        self.registerImage(self.AttributeID,
-                           UI.PixmapCache.getPixmap("attribute"))
-        self.registerImage(self.AttributeProtectedID,
-                           UI.PixmapCache.getPixmap("attribute_protected"))
-        self.registerImage(self.AttributePrivateID,
-                           UI.PixmapCache.getPixmap("attribute_private"))
-        self.registerImage(self.EnumID,
-                           UI.PixmapCache.getPixmap("enum"))
-        self.registerImage(self.KeywordsID,
-                           UI.PixmapCache.getPixmap("keywords"))
-        self.registerImage(self.ModuleID,
-                           UI.PixmapCache.getPixmap("module"))
-        
-        self.registerImage(self.FromDocumentID,
-                           UI.PixmapCache.getPixmap("editor"))
-        
-        self.registerImage(self.TemplateImageID,
-                           UI.PixmapCache.getPixmap("templateViewer"))
+        # finale size of the completion images
+        imageSize = QSize(22, 22)
+        
+        self.registerImage(
+            self.ClassID,
+            UI.PixmapCache.getPixmap("class", imageSize))
+        self.registerImage(
+            self.ClassProtectedID,
+            UI.PixmapCache.getPixmap("class_protected", imageSize))
+        self.registerImage(
+            self.ClassPrivateID,
+            UI.PixmapCache.getPixmap("class_private", imageSize))
+        self.registerImage(
+            self.MethodID,
+            UI.PixmapCache.getPixmap("method", imageSize))
+        self.registerImage(
+            self.MethodProtectedID,
+            UI.PixmapCache.getPixmap("method_protected", imageSize))
+        self.registerImage(
+            self.MethodPrivateID,
+            UI.PixmapCache.getPixmap("method_private", imageSize))
+        self.registerImage(
+            self.AttributeID,
+            UI.PixmapCache.getPixmap("attribute", imageSize))
+        self.registerImage(
+            self.AttributeProtectedID,
+            UI.PixmapCache.getPixmap("attribute_protected", imageSize))
+        self.registerImage(
+            self.AttributePrivateID,
+            UI.PixmapCache.getPixmap("attribute_private", imageSize))
+        self.registerImage(
+            self.EnumID,
+            UI.PixmapCache.getPixmap("enum", imageSize))
+        self.registerImage(
+            self.KeywordsID,
+            UI.PixmapCache.getPixmap("keywords", imageSize))
+        self.registerImage(
+            self.ModuleID,
+            UI.PixmapCache.getPixmap("module", imageSize))
+        
+        self.registerImage(
+            self.FromDocumentID,
+            UI.PixmapCache.getPixmap("editor", imageSize))
+        
+        self.registerImage(
+            self.TemplateImageID,
+            UI.PixmapCache.getPixmap("templateViewer", imageSize))
     
     def addClone(self, editor):
         """
@@ -4440,7 +4457,7 @@
             Preferences.getEditor("ShowMarkerMapOnRight"))
         self.__markerMap.initColors()
         
-        self.setLanguage(self.fileName)
+        self.setLanguage(self.fileName, propagate=False)
         
         self.settingsRead.emit()
     
@@ -4743,8 +4760,10 @@
             self.setAutoCompletionSource(
                 QsciScintilla.AutoCompletionSource.AcsAll)
         
-        self.maxLines = Preferences.getEditor("AutoCompletionMaxLines")
-        self.maxChars = Preferences.getEditor("AutoCompletionMaxChars")
+        self.setAutoCompletionWidgetSize(
+            Preferences.getEditor("AutoCompletionMaxChars"),
+            Preferences.getEditor("AutoCompletionMaxLines")
+        )
         
     def __setCallTips(self):
         """
--- a/eric6/QScintilla/Exporters/ExporterTEX.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/QScintilla/Exporters/ExporterTEX.py	Sat Sep 04 11:34:54 2021 +0200
@@ -223,7 +223,7 @@
                 )
                 f.write(
                     "Source File: {0}\n\n\\noindent\n\\tiny{{\n"
-                    .format(title))
+                    .format(title.replace('_','\\_')))
                 
                 styleCurrent = self.editor.styleAt(0)
                 f.write("\\eric{0}{{"
@@ -252,10 +252,10 @@
                     elif ch == b'\\':
                         f.write("{\\textbackslash}")
                     elif ch in [b'>', b'<', b'@']:
-                        f.write("${0}$".format(ch[0]))
+                        f.write("${0}$".format(ch.decode()))
                     elif ch in [b'{', b'}', b'^', b'_', b'&', b'$', b'#',
                                 b'%', b'~']:
-                        f.write("\\{0}".format(ch[0]))
+                        f.write("\\{0}".format(ch.decode()))
                     elif ch in [b'\r', b'\n']:
                         lineIdx = -1    # because incremented below
                         if (
--- a/eric6/QScintilla/QsciScintillaCompat.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/QScintilla/QsciScintillaCompat.py	Sat Sep 04 11:34:54 2021 +0200
@@ -10,7 +10,7 @@
 import contextlib
 
 from PyQt5.QtCore import pyqtSignal, Qt, QPoint
-from PyQt5.QtGui import QPalette, QColor, QFontMetrics
+from PyQt5.QtGui import QPalette, QColor
 from PyQt5.QtWidgets import QApplication, QListWidget
 from PyQt5.Qsci import (
     QsciScintillaBase, QsciScintilla,
@@ -71,11 +71,7 @@
         self.userListActivated.connect(self.__completionListSelected)
         self.modificationChanged.connect(self.__modificationChanged)
         
-        self.maxLines = 5
-        self.maxChars = 40
-        # Adjust the min. size of the autocomplete list box for short strings.
-        # Otherwise the width of the list box is at least the standard width.
-        self.SendScintilla(QsciScintilla.SCI_AUTOCSETMAXWIDTH, 5)
+        self.setAutoCompletionWidgetSize(40, 5)
     
     def __modificationChanged(self, m):
         """
@@ -373,6 +369,18 @@
     ## methods below are missing from QScintilla
     ###########################################################################
 
+    def setAutoCompletionWidgetSize(self, chars, lines):
+        """
+        Public method to set the size of completion and user lists.
+        
+        @param chars max. number of chars to show
+        @type int
+        @param lines max. number of lines to show
+        @type int
+        """
+        self.SendScintilla(QsciScintilla.SCI_AUTOCSETMAXWIDTH, chars)
+        self.SendScintilla(QsciScintilla.SCI_AUTOCSETMAXHEIGHT, lines)
+        
     def zoomIn(self, zoom=1):
         """
         Public method used to increase the zoom factor.
@@ -1543,70 +1551,25 @@
         children = self.findChildren(QListWidget)
         if children:
             userListWidget = children[-1]
-            geom = userListWidget.geometry()
-            
-            baseHeight = geom.height()
-            
-            # Workaround for getting all items instead of
-            # userListWidget.items() call with unknown mime types.
-            all_items = userListWidget.findItems(
-                '', Qt.MatchFlag.MatchStartsWith)
-            if not all_items:
-                return
-            
-            width = 0
-            maxItemHeight = 0
-            for item in all_items:
-                visualRect = userListWidget.visualItemRect(item)
-                itemWidth = visualRect.width()
-                if itemWidth > width:
-                    width = itemWidth
-                itemHeight = visualRect.height()
-                if itemHeight > maxItemHeight:
-                    maxItemHeight = itemHeight
-            
-            height = min(self.maxLines, len(all_items)) * maxItemHeight
-            # Just a fiddling factor: 2 for better readability,
-            # e.g. underscores at the end of the list.
-            height += 2
-            
-            # Borders
-            borders = geom.size() - userListWidget.contentsRect().size()
-            width += borders.width()
-            height += borders.height()
-            
-            font = userListWidget.font()
-            fm = QFontMetrics(font)
-            averageCharWidth = fm.averageCharWidth()
-            maxWidth = averageCharWidth * self.maxChars
-            if width > maxWidth:
-                width = maxWidth
-                height += (
-                    userListWidget.horizontalScrollBar().sizeHint().height()
-                )
-                # List box doesn't honor limited size to show scroll bars.
-                # So just force it.
-                userListWidget.setHorizontalScrollBarPolicy(
-                    Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
-            
-            if len(all_items) > self.maxLines:
-                width += userListWidget.verticalScrollBar().sizeHint().width()
-            
-            # Special case, where the space below current line where to less
-            yPos = geom.y()
-            charPos = self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)
-            currentYPos = self.SendScintilla(
-                QsciScintilla.SCI_POINTYFROMPOSITION, 0, charPos)
-            
-            # X position doesn't matter: set to 0
-            globalPos = self.mapToGlobal(QPoint(0, currentYPos))
-            if yPos < globalPos.y():
-                deltaHeight = baseHeight - height
-                geom.setY(yPos + deltaHeight - 4)
-            
-            geom.setWidth(width)
-            geom.setHeight(height)
-            userListWidget.setGeometry(geom)
+            hScrollbar = userListWidget.horizontalScrollBar()
+            if hScrollbar.isVisible():
+                hScrollbarHeight = hScrollbar.sizeHint().height()
+                
+                geom = userListWidget.geometry()
+                geom.setHeight(geom.height() + hScrollbarHeight)
+                
+                charPos = self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)
+                currentYPos = self.SendScintilla(
+                    QsciScintilla.SCI_POINTYFROMPOSITION, 0, charPos)
+                if geom.y() < currentYPos:
+                    geom.setY(geom.y() - hScrollbarHeight)
+                    moveY = True
+                else:
+                    moveY = False
+                
+                userListWidget.setGeometry(geom)
+                if moveY:
+                    userListWidget.move(geom.x(), geom.y() - hScrollbarHeight)
     
     def __completionListSelected(self, listId, txt):
         """
--- a/eric6/QScintilla/Shell.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/QScintilla/Shell.py	Sat Sep 04 11:34:54 2021 +0200
@@ -571,8 +571,10 @@
         
         self.racEnabled = Preferences.getShell("AutoCompletionEnabled")
         
-        self.maxLines = Preferences.getEditor("AutoCompletionMaxLines")
-        self.maxChars = Preferences.getEditor("AutoCompletionMaxChars")
+        self.setAutoCompletionWidgetSize(
+            Preferences.getEditor("AutoCompletionMaxChars"),
+            Preferences.getEditor("AutoCompletionMaxLines")
+        )
         
     def __setCallTips(self, language='Python'):
         """
--- a/eric6/Utilities/BackgroundService.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Utilities/BackgroundService.py	Sat Sep 04 11:34:54 2021 +0200
@@ -46,6 +46,8 @@
         @param parent reference to the parent object
         @type QObject
         """
+        super().__init__(parent)
+
         self.processes = {}
         self.connections = {}
         self.isWorking = None
@@ -53,8 +55,6 @@
         self.__queue = []
         self.services = {}
 
-        super().__init__(parent)
-
         networkInterface = Preferences.getDebugger("NetworkInterface")
         if networkInterface == "all" or '.' in networkInterface:
             self.hostAddress = '127.0.0.1'
@@ -426,9 +426,9 @@
             self.isWorking = None
         self.connections[lang] = connection
         connection.readyRead.connect(
-            lambda x=lang: self.__receive(x))
+            lambda: self.__receive(lang))
         connection.disconnected.connect(
-            lambda x=lang: self.on_disconnectSocket(x))
+            lambda: self.on_disconnectSocket(lang))
             
         for (fx, lng), args in self.services.items():
             if lng == lang:
@@ -481,9 +481,10 @@
         self.close()
         
         for connection in self.connections.values():
-            # Prevent calling of on_disconnectSocket
-            connection.blockSignals(True)
+            connection.readyRead.disconnect()
+            connection.disconnected.disconnect()
             connection.close()
+            connection.deleteLater()
         
         for process, _interpreter in self.processes.values():
             process.close()
--- a/eric6/Utilities/ClassBrowsers/pyclbr.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Utilities/ClassBrowsers/pyclbr.py	Sat Sep 04 11:34:54 2021 +0200
@@ -416,8 +416,9 @@
         # start with zero based line after start line
         while lineno < len(lines):
             line = lines[lineno]
-            if line.strip():
-                # line contains some text
+            if line.strip() and not line.lstrip().startswith("#"):
+                # line contains some text and does not start with
+                # a comment sign
                 lineIndent = _indent(line.replace(line.lstrip(), ""))
                 if lineIndent <= indent:
                     return lineno
--- a/eric6/Utilities/ModuleParser.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/Utilities/ModuleParser.py	Sat Sep 04 11:34:54 2021 +0200
@@ -543,8 +543,9 @@
             # start with zero based line after start line
             while lineno < len(lines):
                 line = lines[lineno]
-                if line.strip():
-                    # line contains some text
+                if line.strip() and not line.lstrip().startswith("#"):
+                    # line contains some text and does not start with
+                    # a comment sign
                     lineIndent = _indent(line.replace(line.lstrip(), ""))
                     if lineIndent <= indent:
                         return lineno
--- a/eric6/WebBrowser/FeaturePermissions/FeaturePermissionsDialog.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/WebBrowser/FeaturePermissions/FeaturePermissionsDialog.py	Sat Sep 04 11:34:54 2021 +0200
@@ -281,7 +281,7 @@
         while currentList.topLevelItemCount() > 0:
             itm = currentList.takeTopLevelItem(0)      # __IGNORE_WARNING__
             del itm
-        self.__updateGeoButtons()
+        self.__updateButtons()
     
     def getData(self):
         """
--- a/eric6/WebBrowser/VirusTotal/VirusTotalApi.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/WebBrowser/VirusTotal/VirusTotalApi.py	Sat Sep 04 11:34:54 2021 +0200
@@ -169,7 +169,7 @@
             WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager()
         )
         reply = nam.post(request, params)
-        reply.finished.connect(self.__submitUrlFinished)
+        reply.finished.connect(lambda: self.__submitUrlFinished(reply))
         self.__replies.append(reply)
     
     def __submitUrlFinished(self, reply):
@@ -216,7 +216,8 @@
             WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager()
         )
         reply = nam.post(request, params)
-        reply.finished.connect(self.__getUrlScanReportUrlFinished)
+        reply.finished.connect(
+            lambda: self.__getUrlScanReportUrlFinished(reply))
         self.__replies.append(reply)
     
     def __getUrlScanReportUrlFinished(self, reply):
@@ -252,7 +253,8 @@
             WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager()
         )
         reply = nam.post(request, params)
-        reply.finished.connect(self.__getFileScanReportUrlFinished)
+        reply.finished.connect(
+            lambda: self.__getFileScanReportUrlFinished(reply))
         self.__replies.append(reply)
     
     def __getFileScanReportUrlFinished(self, reply):
@@ -293,7 +295,8 @@
             WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager()
         )
         reply = nam.get(request)
-        reply.finished.connect(self.__getIpAddressReportFinished)
+        reply.finished.connect(
+            lambda: self.__getIpAddressReportFinished(reply))
         self.__replies.append(reply)
     
     def __getIpAddressReportFinished(self, reply):
--- a/eric6/WebBrowser/WebBrowserWindow.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/eric6/WebBrowser/WebBrowserWindow.py	Sat Sep 04 11:34:54 2021 +0200
@@ -4381,7 +4381,7 @@
         feedsManager.newWindow.connect(self.openUrlNewWindow)
         feedsManager.newPrivateWindow.connect(self.openUrlNewPrivateWindow)
         feedsManager.rejected.connect(
-            lambda fm: self.__feedsManagerClosed(fm))
+            lambda: self.__feedsManagerClosed(feedsManager))
         feedsManager.show()
     
     def __feedsManagerClosed(self, feedsManager):
--- a/scripts/install.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/scripts/install.py	Sat Sep 04 11:34:54 2021 +0200
@@ -1544,7 +1544,6 @@
         "EditorConfig": ("editorconfig", ""),
         "Send2Trash": ("send2trash", ""),
         "Pygments": ("pygments", ""),
-        "mercurial": ("mercurial", ""),
         "pyenchant": ("enchant", ""),
     }
     # dict with tuples of package name and install constraint
--- a/setup.py	Sat Jul 03 11:47:48 2021 +0200
+++ b/setup.py	Sat Sep 04 11:34:54 2021 +0200
@@ -349,7 +349,6 @@
         "EditorConfig",
         "Send2Trash",
         "Pygments",
-        "mercurial",
         "pywin32>=1.0;platform_system=='Windows'",
     ],
     data_files=getDataFiles(),

eric ide

mercurial