Wed, 23 Sep 2020 19:10:42 +0200
Added capability to show information about a code object.
--- 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")