Added capability to show information about a code object.

Wed, 23 Sep 2020 19:10:42 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 23 Sep 2020 19:10:42 +0200
changeset 7711
5e6792b85a8a
parent 7710
9aad21c7765d
child 7712
d8eedc2e5a0a

Added capability to show information about a code object.

docs/changelog file | annotate | diff | comparison | revisions
eric6/DebugClients/Python/DebugBase.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/PythonPage.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/PythonPage.ui file | annotate | diff | comparison | revisions
eric6/Preferences/__init__.py file | annotate | diff | comparison | revisions
eric6/UI/PythonDisViewer.py file | annotate | diff | comparison | revisions
--- a/docs/changelog	Tue Sep 22 19:30:03 2020 +0200
+++ b/docs/changelog	Wed Sep 23 19:10:42 2020 +0200
@@ -10,6 +10,7 @@
      source file
   -- added a viewer to visualize Python byte code generated from a Python
      traceback of an exception as an additional tab of the debug viewer
+  -- added capability to show information about a code object
 - Third Party packages
   -- updated Pygments to 2.7.0
   -- updated coverage.py to 5.3.0
--- a/eric6/DebugClients/Python/DebugBase.py	Tue Sep 22 19:30:03 2020 +0200
+++ b/eric6/DebugClients/Python/DebugBase.py	Wed Sep 23 19:10:42 2020 +0200
@@ -931,12 +931,15 @@
         @return dictionary containing the disassembly information
         @rtype dict
         """
+        co = frame.f_code
         disDict = {
             "lasti": frame.f_lasti,
-            "firstlineno": frame.f_code.co_firstlineno,
+            "firstlineno": co.co_firstlineno,
             "instructions": [],
         }
-        for instr in dis.get_instructions(frame.f_code):
+        
+        # 1. disassembly info
+        for instr in dis.get_instructions(co):
             instrDict = {
                 "lineno":
                     0 if instr.starts_line is None else instr.starts_line,
@@ -948,6 +951,25 @@
             }
             disDict["instructions"].append(instrDict)
         
+        # 2. code info
+        # Note: keep in sync with PythonDisViewer.__createCodeInfo()
+        disDict["codeinfo"] = {
+            "name": co.co_name,
+            "filename": co.co_filename,
+            "firstlineno": co.co_firstlineno,
+            "argcount": co.co_argcount,
+            "posonlyargcount": co.co_posonlyargcount,
+            "kwonlyargcount": co.co_kwonlyargcount,
+            "nlocals": co.co_nlocals,
+            "stacksize": co.co_stacksize,
+            "flags": dis.pretty_flags(co.co_flags),
+            "consts": [str(const) for const in co.co_consts],
+            "names": [str(name) for name in co.co_names],
+            "varnames": [str(name) for name in co.co_varnames],
+            "freevars": [str(var) for var in co.co_freevars],
+            "cellvars": [str(var) for var in co.co_cellvars],
+        }
+        
         return disDict
     
     def __extractSystemExitMessage(self, excinfo):
--- a/eric6/Preferences/ConfigurationPages/PythonPage.py	Tue Sep 22 19:30:03 2020 +0200
+++ b/eric6/Preferences/ConfigurationPages/PythonPage.py	Wed Sep 23 19:10:42 2020 +0200
@@ -40,6 +40,9 @@
             Preferences.getSystem("IOEncoding"))
         self.ioEncodingComboBox.setCurrentIndex(index)
         
+        self.showCodeInfoDetailsCeckBox.setChecked(
+            Preferences.getPython("DisViewerExpandCodeInfoDetails"))
+        
         # these are the same as in the debugger pages
         self.py3ExtensionsEdit.setText(
             Preferences.getDebugger("Python3Extensions"))
@@ -79,6 +82,10 @@
             "Python3Extensions",
             self.py3ExtensionsEdit.text())
         
+        Preferences.setPython(
+            "DisViewerExpandCodeInfoDetails",
+            self.showCodeInfoDetailsCeckBox.isChecked())
+        
         # colours
         self.saveColours(Preferences.setPython)
     
--- a/eric6/Preferences/ConfigurationPages/PythonPage.ui	Tue Sep 22 19:30:03 2020 +0200
+++ b/eric6/Preferences/ConfigurationPages/PythonPage.ui	Wed Sep 23 19:10:42 2020 +0200
@@ -324,6 +324,16 @@
         </property>
        </widget>
       </item>
+      <item row="3" column="0" colspan="3">
+       <widget class="QCheckBox" name="showCodeInfoDetailsCeckBox">
+        <property name="toolTip">
+         <string>Select to show code information subsections expanded</string>
+        </property>
+        <property name="text">
+         <string>Show all code information subsections</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
--- a/eric6/Preferences/__init__.py	Tue Sep 22 19:30:03 2020 +0200
+++ b/eric6/Preferences/__init__.py	Wed Sep 23 19:10:42 2020 +0200
@@ -1476,6 +1476,7 @@
         "DisViewerErrorColor": QColor(Qt.red),
         "DisViewerCurrentColor": QColor(Qt.magenta),
         "DisViewerLabeledColor": QColor(Qt.green),
+        "DisViewerExpandCodeInfoDetails": False,
     }
 
 
@@ -1808,6 +1809,9 @@
     ):
         return QColor(prefClass.settings.value(
             "Python/" + key, prefClass.pythonDefaults[key]))
+    elif key in ("DisViewerExpandCodeInfoDetails"):
+        return toBool(prefClass.settings.value(
+            "Python/" + key, prefClass.pythonDefaults[key]))
     else:
         return prefClass.settings.value(
             "Python/" + key, prefClass.pythonDefaults[key])
--- a/eric6/UI/PythonDisViewer.py	Tue Sep 22 19:30:03 2020 +0200
+++ b/eric6/UI/PythonDisViewer.py	Wed Sep 23 19:10:42 2020 +0200
@@ -20,6 +20,8 @@
     QApplication, QTreeWidgetItem, QAbstractItemView, QWidget, QMenu
 )
 
+from E5Gui.E5Application import e5App
+
 import Preferences
 
 from .Ui_PythonDisViewer import Ui_PythonDisViewer
@@ -83,6 +85,9 @@
             self.tr('Expand All'), self.__expandAllDis)
         self.__disMenu.addAction(
             self.tr('Collapse All'), self.__collapseAllDis)
+        self.__disMenu.addSeparator()
+        self.__disMenu.addAction(
+            self.tr('Configure...'), self.__configure)
         
         self.__codeInfoMenu = QMenu(self.codeInfoWidget)
         if self.__mode == PythonDisViewerModes.SourceDisassemblyMode:
@@ -92,6 +97,9 @@
             self.tr('Expand All'), self.__expandAllCodeInfo)
         self.__codeInfoMenu.addAction(
             self.tr('Collapse All'), self.__collapseAllCodeInfo)
+        self.__codeInfoMenu.addSeparator()
+        self.__codeInfoMenu.addAction(
+            self.tr('Configure...'), self.__configure)
         
         self.__errorColor = QBrush(
             Preferences.getPython("DisViewerErrorColor"))
@@ -100,7 +108,11 @@
         self.__jumpTargetColor = QBrush(
             Preferences.getPython("DisViewerLabeledColor"))
         
-        self.disWidget.itemClicked.connect(self.__disItemClicked)
+        self.__showCodeInfoDetails = Preferences.getPython(
+            "DisViewerExpandCodeInfoDetails")
+        
+        if self.__mode == PythonDisViewerModes.SourceDisassemblyMode:
+            self.disWidget.itemClicked.connect(self.__disItemClicked)
         self.disWidget.itemCollapsed.connect(self.__resizeDisColumns)
         self.disWidget.itemExpanded.connect(self.__resizeDisColumns)
         self.disWidget.customContextMenuRequested.connect(
@@ -116,7 +128,6 @@
                 self.__disViewerStateChanged)
             
             self.codeInfoWidget.hide()
-        
             self.hide()
         
         elif self.__mode == PythonDisViewerModes.TracebackMode:
@@ -408,17 +419,18 @@
         return {
             "name": co.co_name,
             "filename": co.co_filename,
+            "firstlineno": co.co_firstlineno,
             "argcount": co.co_argcount,
             "posonlyargcount": co.co_posonlyargcount,
             "kwonlyargcount": co.co_kwonlyargcount,
             "nlocals": co.co_nlocals,
             "stacksize": co.co_stacksize,
             "flags": dis.pretty_flags(co.co_flags),
-            "consts": co.co_consts,
-            "names": co.co_names,
-            "varnames": co.co_varnames,
-            "freevars": co.co_freevars,
-            "cellvars": co.co_cellvars,
+            "consts": [str(const) for const in co.co_consts],
+            "names": [str(name) for name in co.co_names],
+            "varnames": [str(name) for name in co.co_varnames],
+            "freevars": [str(var) for var in co.co_freevars],
+            "cellvars": [str(var) for var in co.co_cellvars],
         }
     
     def __loadDIS(self):
@@ -436,8 +448,9 @@
             ))
             return
         
-        self.disWidget.clear()
+        self.clear()
         self.__editor.clearAllHighlights()
+        self.codeInfoWidget.hide()
         
         source = self.__editor.text()
         if not source.strip():
@@ -541,8 +554,8 @@
                             lastInstructions[0],
                             QAbstractItemView.PositionAtCenter)
                 
-                if "codeInfo" in disassembly:
-                    self.__showCodeInfoData(disassembly["codeInfo"])
+                if "codeinfo" in disassembly:
+                    self.__showCodeInfoData(disassembly["codeinfo"])
     
     def __resizeDisColumns(self):
         """
@@ -625,7 +638,6 @@
         @param column column number of the click
         @type int
         """
-        # TODO: add code to deal with Traceback mode
         self.__editor.clearAllHighlights()
         
         if itm is not None:
@@ -713,6 +725,9 @@
         self.__jumpTargetColor = QBrush(
             Preferences.getPython("DisViewerLabeledColor"))
         
+        self.__showCodeInfoDetails = Preferences.getPython(
+            "DisViewerExpandCodeInfoDetails")
+        
         if self.isVisible():
             self.__loadDIS()
         
@@ -748,6 +763,7 @@
         Public method to clear the display.
         """
         self.disWidget.clear()
+        self.codeInfoWidget.clear()
     
     def __showCodeInfo(self):
         """
@@ -777,8 +793,7 @@
             """
             parent = QTreeWidgetItem(self.codeInfoWidget,
                                      [title, str(len(infoList))])
-            # TODO: make this a configuration item
-            parent.setExpanded(False)
+            parent.setExpanded(self.__showCodeInfoDetails)
             
             for index, value in enumerate(infoList):
                 itm = QTreeWidgetItem(parent, [str(index), str(value)])
@@ -792,6 +807,8 @@
             QTreeWidgetItem(self.codeInfoWidget, [
                 self.tr("Filename"), codeInfo["filename"]])
             QTreeWidgetItem(self.codeInfoWidget, [
+                self.tr("First Line"), str(codeInfo["firstlineno"])])
+            QTreeWidgetItem(self.codeInfoWidget, [
                 self.tr("Argument Count"), str(codeInfo["argcount"])])
             QTreeWidgetItem(self.codeInfoWidget, [
                 self.tr("Positional-only Arguments"),
@@ -860,3 +877,10 @@
             # don't show context menu on empty list
             coord = self.codeInfoWidget.mapToGlobal(coord)
             self.__codeInfoMenu.popup(coord)
+    
+    def __configure(self):
+        """
+        Private method to open the configuration dialog.
+        """
+        e5App().getObject("UserInterface").showPreferences(
+            "pythonPage")

eric ide

mercurial