mirror of https://gitlab.com/pamhyr/pamhyr2
183 lines
5.2 KiB
Python
183 lines
5.2 KiB
Python
# Window.py -- Pamhyr
|
|
# Copyright (C) 2023-2026 INRAE
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import psutil
|
|
import logging
|
|
import traceback
|
|
|
|
from tools import trace, timer
|
|
|
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
|
from View.Tools.PamhyrPythonEditor import PamhyrPythonEditor
|
|
from View.Debug.Table import TableModel
|
|
|
|
from PyQt5.QtGui import (
|
|
QKeySequence,
|
|
)
|
|
|
|
from PyQt5.QtCore import (
|
|
Qt, QVariant, QAbstractTableModel,
|
|
QCoreApplication, QModelIndex, QRect, QThread,
|
|
QTimer, pyqtSlot, pyqtSignal,
|
|
)
|
|
|
|
from PyQt5.QtWidgets import (
|
|
QDialogButtonBox, QPushButton, QLineEdit,
|
|
QFileDialog, QTableView, QAbstractItemView,
|
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
|
QProgressBar, QLabel, QTextEdit, QHBoxLayout,
|
|
)
|
|
|
|
from PyQt5.Qsci import QsciScintilla, QsciLexerPython
|
|
|
|
logger = logging.getLogger()
|
|
|
|
_translate = QCoreApplication.translate
|
|
|
|
|
|
class ReplWindow(PamhyrWindow):
|
|
_pamhyr_ui = "DebugRepl"
|
|
_pamhyr_name = "Debug REPL"
|
|
|
|
def __init__(self, study=None, config=None,
|
|
solver=None, parent=None):
|
|
title = _translate("Debug", "Debug REPL")
|
|
|
|
super(ReplWindow, self).__init__(
|
|
title=title,
|
|
study=study,
|
|
config=config,
|
|
options=[],
|
|
parent=parent
|
|
)
|
|
|
|
self.__debug_exec_result__ = None
|
|
self._history = []
|
|
self._history_ind = 0
|
|
|
|
self.setup_editor()
|
|
self.setup_connections()
|
|
|
|
def setup_editor(self):
|
|
layout = self.find(QHBoxLayout, "horizontalLayout")
|
|
self._editor = PamhyrPythonEditor()
|
|
layout.insertWidget(0, self._editor)
|
|
|
|
def setup_connections(self):
|
|
self.find(QPushButton, "pushButton").clicked.connect(self.eval_python)
|
|
|
|
def eval_python(self):
|
|
code = self._editor.text()
|
|
|
|
# Code to rich_code
|
|
rich_code = code.strip().split("\n")
|
|
# Add return variable for results display at last row
|
|
rich_code[-1] = "self.__debug_exec_result__ = " + rich_code[-1]
|
|
rich_code = "\n".join(rich_code)
|
|
logger.debug(f"User debug command : \n{rich_code}")
|
|
try:
|
|
value = exec(rich_code)
|
|
value = self.__debug_exec_result__
|
|
except Exception as e:
|
|
value = f"<font color=\"red\">" + str(e) + "</font>\n"
|
|
value += f"<font color=\"grey\">{traceback.format_exc()}</font>"
|
|
|
|
# Display code
|
|
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
|
self.find(QTextEdit, "textEdit").append(msg)
|
|
# Display results
|
|
self.find(QTextEdit, "textEdit").append(str(value))
|
|
|
|
|
|
class TimerWindow(PamhyrWindow):
|
|
_pamhyr_ui = "DebugTimer"
|
|
_pamhyr_name = "Debug Timer"
|
|
|
|
def __init__(self, study=None, config=None,
|
|
solver=None, parent=None):
|
|
title = _translate("Debug", "Debug Timer")
|
|
|
|
super(TimerWindow, self).__init__(
|
|
title=title,
|
|
study=study,
|
|
config=config,
|
|
options=[],
|
|
parent=parent
|
|
)
|
|
|
|
self._process = psutil.Process(os.getpid())
|
|
|
|
self.setup_table()
|
|
self.setup_label()
|
|
self.setup_alarm()
|
|
self.setup_connections()
|
|
|
|
def setup_table(self):
|
|
table = self.find(QTableView, f"tableView")
|
|
self._table = TableModel(
|
|
table_view=table,
|
|
table_headers={
|
|
"name": "Function name",
|
|
"time": "Time (sec)",
|
|
"calls": "Number of calls"
|
|
},
|
|
data=None,
|
|
)
|
|
|
|
def setup_label(self):
|
|
label = self.find(QLabel, "label")
|
|
label.setText(
|
|
f" Memory usage:\t" +
|
|
"<b>" +
|
|
f"{self._process.memory_info().rss / (1000 * 1000):.3f}" +
|
|
"</b> MB"
|
|
)
|
|
|
|
def setup_alarm(self):
|
|
self._alarm = QTimer()
|
|
self._alarm.start(2000)
|
|
|
|
def setup_connections(self):
|
|
# self.find(QAction, "action_reset").triggered.connect(self.reset)
|
|
self.find(QAction, "action_export").triggered.connect(self.export)
|
|
|
|
self._alarm.timeout.connect(self.update)
|
|
|
|
def update(self):
|
|
self._table.update_lst()
|
|
self.setup_label()
|
|
|
|
# def reset(self):
|
|
# self._table.reset_timers()
|
|
|
|
def export(self):
|
|
self.file_dialog(
|
|
select_file="AnyFile",
|
|
callback=lambda f: self.export_to(f[0]),
|
|
default_suffix=".csv",
|
|
file_filter=["CSV file (*.csv)"],
|
|
)
|
|
|
|
def export_to(self, filename):
|
|
csv = self._table.to_csv()
|
|
|
|
with open(filename, 'w', newline='') as csvfile:
|
|
csvfile.write(csv)
|