From 52d9d6340591499be6af95f8a9448ef7d748d9ee Mon Sep 17 00:00:00 2001 From: Avico Shalev Date: Sun, 17 Nov 2024 14:16:37 +0200 Subject: [PATCH 1/3] Add 'Save Profile' functionality and HTML export to GUI --- src/lineprofilergui/gui.py | 18 +++++++++++++ src/lineprofilergui/tree.py | 50 ++++++++++++++++++++++++++++++++++++ src/lineprofilergui/utils.py | 1 + 3 files changed, 69 insertions(+) diff --git a/src/lineprofilergui/gui.py b/src/lineprofilergui/gui.py index 008c230..f7f34d7 100644 --- a/src/lineprofilergui/gui.py +++ b/src/lineprofilergui/gui.py @@ -65,6 +65,8 @@ def setup_ui(self): # noqa: PLR0915 self.actionShowOutput.setIcon(ICONS["INFO"]) self.actionLoadLprof = QtGui.QAction(self) self.actionLoadLprof.setIcon(ICONS["READFILE"]) + self.actionSave = QtGui.QAction(self) + self.actionSave.setIcon(ICONS["SAVEFILE"]) self.actionQuit = QtGui.QAction(self) self.actionQuit.setIcon(ICONS["ABORT"]) self.actionConfigure = QtGui.QAction(self) @@ -93,6 +95,7 @@ def setup_ui(self): # noqa: PLR0915 self.menuProfiling.addAction(self.actionShowOutput) self.menuProfiling.addSeparator() self.menuProfiling.addAction(self.actionLoadLprof) + self.menuProfiling.addAction(self.actionSave) self.menuProfiling.addSeparator() self.menuProfiling.addAction(self.actionQuit) self.menubar.addAction(self.menuProfiling.menuAction()) @@ -164,6 +167,7 @@ def connect_signals(self): self.actionAbort.triggered.connect(self.kernprof_run.kill) self.actionShowOutput.toggled.connect(self.dockOutputWidget.setVisible) self.actionLoadLprof.triggered.connect(self.selectLprof) + self.actionSave.triggered.connect(self.saveLProfile) self.actionQuit.triggered.connect(QtWidgets.QApplication.instance().quit) self.actionLine_profiler_documentation.triggered.connect( lambda: QtGui.QDesktopServices.openUrl(QtCore.QUrl(LINE_PROFILER_DOC_URL)) @@ -197,6 +201,8 @@ def retranslate_ui(self): self.actionShowOutput.setShortcut(_("F7")) self.actionLoadLprof.setText(_("&Load data...")) self.actionLoadLprof.setShortcut(_("Ctrl+O")) + self.actionSave.setText(_("&Save profile...")) + self.actionSave.setShortcut(_("Ctrl+S")) self.actionQuit.setText(_("&Quit")) self.actionQuit.setShortcut(_("Ctrl+Q")) self.actionConfigure.setText(_("&Configuration...")) @@ -249,6 +255,18 @@ def selectLprof(self): if filename: self.load_lprof(filename) + def saveLProfile(self): + filename, _selfilter = QtWidgets.QFileDialog.getSaveFileName( + self, + _("Save line profiler data"), + "", + _("HTML") + " (*.html);; " + _("All files") + " (*.*)", + ) + if filename: + html = self.resultsTreeWidget.generate_html() + with open(filename, "w") as f: + f.write(html) + @QtCore.Slot() def configure(self): UiConfigDialog(self, self.config).exec() diff --git a/src/lineprofilergui/tree.py b/src/lineprofilergui/tree.py index ac52526..8b7e28d 100644 --- a/src/lineprofilergui/tree.py +++ b/src/lineprofilergui/tree.py @@ -312,6 +312,56 @@ def updateColonsVisible(self): col, not settings.value(f"column{col+1}Visible", True, bool) ) + def generate_html(self): + def get_text_color(item): + color = item.foreground(0).color() + return color.name() + + def get_background_color(item: QtWidgets.QTreeWidgetItem): + color = item.background(0).color().name(QtGui.QColor.HexArgb) + return color[0] + color[3:] + color[1:3] # Swap alpha and color + + html = "" + + for i in range(self.topLevelItemCount()): + top_item = self.topLevelItem(i) + html += '" + + html += "" + return html + @QtCore.Slot(QtWidgets.QTreeWidgetItem) def item_activated(self, item): # Skip parent lines diff --git a/src/lineprofilergui/utils.py b/src/lineprofilergui/utils.py index a85679e..206e1bc 100644 --- a/src/lineprofilergui/utils.py +++ b/src/lineprofilergui/utils.py @@ -19,6 +19,7 @@ "SETTINGS": QtWidgets.QStyle.SP_FileDialogListView, # actionSettings "BLANKFILE": QtWidgets.QStyle.SP_FileIcon, # statsButton "READFILE": QtWidgets.QStyle.SP_FileDialogContentsView, # scriptButton, kernprofButton + "SAVEFILE": QtWidgets.QStyle.SP_DialogSaveButton, # scriptButton, kernprofButton "DIRECTORY": QtWidgets.QStyle.SP_DirIcon, # wdirButton "EXPAND": QtWidgets.QStyle.SP_ToolBarVerticalExtensionButton, # actionExpand_all "COLLAPSE": QtWidgets.QStyle.SP_ToolBarHorizontalExtensionButton, # actionCollapse_all From 4f4cdd382bd3bc38348ac922899451eed09bb01f Mon Sep 17 00:00:00 2001 From: Avico Shalev Date: Sun, 17 Nov 2024 14:25:53 +0200 Subject: [PATCH 2/3] Add type hint for get_text_color function in ResultsTreeWidget --- src/lineprofilergui/tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lineprofilergui/tree.py b/src/lineprofilergui/tree.py index 8b7e28d..f2a909b 100644 --- a/src/lineprofilergui/tree.py +++ b/src/lineprofilergui/tree.py @@ -313,7 +313,7 @@ def updateColonsVisible(self): ) def generate_html(self): - def get_text_color(item): + def get_text_color(item: QtWidgets.QTreeWidgetItem): color = item.foreground(0).color() return color.name() From 1799bc12228620662300c3ca18b60978aba6ab44 Mon Sep 17 00:00:00 2001 From: Avico Shalev Date: Mon, 9 Dec 2024 10:44:48 +0200 Subject: [PATCH 3/3] Rename 'Save Profile' action to 'Export as HTML' and update related functionality --- src/lineprofilergui/gui.py | 16 ++++++++-------- src/lineprofilergui/utils.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lineprofilergui/gui.py b/src/lineprofilergui/gui.py index f7f34d7..c90bcf6 100644 --- a/src/lineprofilergui/gui.py +++ b/src/lineprofilergui/gui.py @@ -65,8 +65,8 @@ def setup_ui(self): # noqa: PLR0915 self.actionShowOutput.setIcon(ICONS["INFO"]) self.actionLoadLprof = QtGui.QAction(self) self.actionLoadLprof.setIcon(ICONS["READFILE"]) - self.actionSave = QtGui.QAction(self) - self.actionSave.setIcon(ICONS["SAVEFILE"]) + self.actionExport = QtGui.QAction(self) + self.actionExport.setIcon(ICONS["EXPORT2HTML"]) self.actionQuit = QtGui.QAction(self) self.actionQuit.setIcon(ICONS["ABORT"]) self.actionConfigure = QtGui.QAction(self) @@ -95,7 +95,7 @@ def setup_ui(self): # noqa: PLR0915 self.menuProfiling.addAction(self.actionShowOutput) self.menuProfiling.addSeparator() self.menuProfiling.addAction(self.actionLoadLprof) - self.menuProfiling.addAction(self.actionSave) + self.menuProfiling.addAction(self.actionExport) self.menuProfiling.addSeparator() self.menuProfiling.addAction(self.actionQuit) self.menubar.addAction(self.menuProfiling.menuAction()) @@ -167,7 +167,7 @@ def connect_signals(self): self.actionAbort.triggered.connect(self.kernprof_run.kill) self.actionShowOutput.toggled.connect(self.dockOutputWidget.setVisible) self.actionLoadLprof.triggered.connect(self.selectLprof) - self.actionSave.triggered.connect(self.saveLProfile) + self.actionExport.triggered.connect(self.exportLProfile) self.actionQuit.triggered.connect(QtWidgets.QApplication.instance().quit) self.actionLine_profiler_documentation.triggered.connect( lambda: QtGui.QDesktopServices.openUrl(QtCore.QUrl(LINE_PROFILER_DOC_URL)) @@ -201,8 +201,8 @@ def retranslate_ui(self): self.actionShowOutput.setShortcut(_("F7")) self.actionLoadLprof.setText(_("&Load data...")) self.actionLoadLprof.setShortcut(_("Ctrl+O")) - self.actionSave.setText(_("&Save profile...")) - self.actionSave.setShortcut(_("Ctrl+S")) + self.actionExport.setText(_("&Export as HTML...")) + self.actionExport.setShortcut(_("Ctrl+E")) self.actionQuit.setText(_("&Quit")) self.actionQuit.setShortcut(_("Ctrl+Q")) self.actionConfigure.setText(_("&Configuration...")) @@ -255,10 +255,10 @@ def selectLprof(self): if filename: self.load_lprof(filename) - def saveLProfile(self): + def exportLProfile(self): filename, _selfilter = QtWidgets.QFileDialog.getSaveFileName( self, - _("Save line profiler data"), + _("Export line profiler data as HTML"), "", _("HTML") + " (*.html);; " + _("All files") + " (*.*)", ) diff --git a/src/lineprofilergui/utils.py b/src/lineprofilergui/utils.py index 206e1bc..239053d 100644 --- a/src/lineprofilergui/utils.py +++ b/src/lineprofilergui/utils.py @@ -19,7 +19,7 @@ "SETTINGS": QtWidgets.QStyle.SP_FileDialogListView, # actionSettings "BLANKFILE": QtWidgets.QStyle.SP_FileIcon, # statsButton "READFILE": QtWidgets.QStyle.SP_FileDialogContentsView, # scriptButton, kernprofButton - "SAVEFILE": QtWidgets.QStyle.SP_DialogSaveButton, # scriptButton, kernprofButton + "EXPORT2HTML": QtWidgets.QStyle.SP_DialogSaveButton, # scriptButton, kernprofButton "DIRECTORY": QtWidgets.QStyle.SP_DirIcon, # wdirButton "EXPAND": QtWidgets.QStyle.SP_ToolBarVerticalExtensionButton, # actionExpand_all "COLLAPSE": QtWidgets.QStyle.SP_ToolBarHorizontalExtensionButton, # actionCollapse_all