bugfixes (#191)
All checks were successful
Build AppImage / Explore-Gitea-Actions (push) Successful in 2m2s

added basic syntax check; closes #148

Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de>
Reviewed-on: #191
This commit is contained in:
Dominik Demuth 2023-12-28 14:30:33 +00:00
parent 2cf94af2c4
commit 694d47267d
7 changed files with 73 additions and 65 deletions

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'resources/_ui/fitcreationdialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@ -51,9 +51,8 @@ class Ui_Dialog(object):
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.namespace_box)
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.tabWidget.addTab(self.namespace_box, "")
self.plainTextEdit = CodeEditor(self.splitter)
self.plainTextEdit.setEnabled(True)
self.plainTextEdit.setObjectName("plainTextEdit")
self.editor = EditorWidget(self.splitter)
self.editor.setObjectName("editor")
self.verticalLayout.addWidget(self.splitter)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
@ -63,8 +62,8 @@ class Ui_Dialog(object):
self.retranslateUi(Dialog)
self.tabWidget.setCurrentIndex(0)
self.buttonBox.accepted.connect(Dialog.accept)
self.buttonBox.rejected.connect(Dialog.reject)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
@ -74,4 +73,4 @@ class Ui_Dialog(object):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.args_box), _translate("Dialog", "Variables"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.kwargs_box), _translate("Dialog", "Multiple choice"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.namespace_box), _translate("Dialog", "Available Functions"))
from ..lib.codeeditor import CodeEditor
from ..lib.codeeditor import EditorWidget

View File

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'resources/_ui/usermodeleditor.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -20,15 +21,12 @@ class Ui_MainWindow(object):
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
self.verticalLayout.setSpacing(3)
self.verticalLayout.setObjectName("verticalLayout")
self.edit_field = CodeEditor(self.centralwidget)
font = QtGui.QFont()
font.setPointSize(10)
self.edit_field.setFont(font)
self.edit_field.setObjectName("edit_field")
self.verticalLayout.addWidget(self.edit_field)
self.widget = EditorWidget(self.centralwidget)
self.widget.setObjectName("widget")
self.verticalLayout.addWidget(self.widget)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30))
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@ -61,4 +59,4 @@ class Ui_MainWindow(object):
self.actionSave.setText(_translate("MainWindow", "Save"))
self.actionSave_as.setText(_translate("MainWindow", "Save as..."))
self.actionClose.setText(_translate("MainWindow", "Close"))
from ..lib.codeeditor import CodeEditor
from ..lib.codeeditor import EditorWidget

View File

@ -54,7 +54,7 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
return self
def update_function(self):
prev_text = self.plainTextEdit.toPlainText().split('\n')
prev_text = self.editor.toPlainText().split('\n')
func_body = ''
in_body = False
for line in prev_text:
@ -89,9 +89,12 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
else:
k += f' def func(x):\n'
if func_body:
k += func_body
else:
k += ' return x'
self.plainTextEdit.setPlainText(k)
self.editor.setPlainText(k)
except Exception as e:
QtWidgets.QMessageBox.warning(self, 'Failure', f'Error found: {e.args[0]}')
@ -215,7 +218,7 @@ class KwargsWidget(QtWidgets.QWidget):
for i in range(self.choices.count()):
kwargs.append(self.choices.widget(i).get_strings())
if kwargs:
return f" choices = {', '.join(kwargs)}\n"
return f" choices = [{', '.join(kwargs)}]\n"
else:
return ''
@ -475,12 +478,3 @@ class DescWidget(QtWidgets.QWidget):
f" equation = r'{self.eq_lineedit.text()}'\n"
return stringi
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication([])
win = QUserFitCreator()
win.show()
sys.exit(app.exec())

View File

@ -72,7 +72,8 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter):
(r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),
# 'class' followed by an identifier
(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
# @ followed by a word
# decorator @ followed by a word
(r'\s*@(\w+)\s*', 0, STYLES['property']),
# Numeric literals
@ -80,7 +81,6 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter):
(r'\b[+-]?0[xX][\dA-Fa-f]+[lL]?\b', 0, STYLES['numbers']),
(r'\b[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b', 0, STYLES['numbers']),
# Double-quoted string, possibly containing escape sequences
(r'[rf]?"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
# Single-quoted string, possibly containing escape sequences
@ -185,7 +185,6 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
self.update_width_linenumber(0)
self.highlight = PythonHighlighter(self.document())
self.textChanged.connect(self._check_syntax)
def keyPressEvent(self, evt):
if evt.key() == QtCore.Qt.Key_Tab:
@ -263,22 +262,48 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
self.setExtraSelections(extra_selections)
def color_line(self, color):
# is_valid, exception = self._check_syntax()
# if is_valid == 1:
doc = self.document()
print(doc.findBlockByLineNumber(color))
class EditorWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.editor = CodeEditor(self)
layout.addWidget(self.editor)
self.error_label = QtWidgets.QLabel(self)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.error_label.setFont(font)
self.error_label.setVisible(False)
layout.addWidget(self.error_label)
self.setLayout(layout)
for attr in ['appendPlainText', 'toPlainText', 'insertPlainText', 'setPlainText']:
setattr(self, attr, getattr(self.editor, attr))
self.editor.textChanged.connect(self._check_syntax)
def _check_syntax(self) -> (int, tuple[typing.Any]):
is_valid = True
# Compile into an AST and check for syntax errors.
try:
_ = parse(self.toPlainText(), filename='<string>')
except SyntaxError as e:
print('SyntaxError', e, e.args[0], e.lineno, e.offset, e.text)
self.color_line(e.lineno)
return 1, (e.lineno, e.offset)
except Exception as e:
print('Unexpected error', e)
return 2, (e.args[0],)
return 0, tuple()
except SyntaxError as e:
self.error_label.setText(f'Syntax error in line {e.lineno}: {e.args[0]}')
is_valid = False
except Exception as e:
self.error_label.setText(f'Unexpected error: {e.args[0]}')
is_valid = False
self.error_label.setVisible(not is_valid)

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from pathlib import Path
from ..Qt import QtWidgets, QtCore, QtGui
from ..lib.codeeditor import CodeEditor
from ..lib.codeeditor import EditorWidget
class QUsermodelEditor(QtWidgets.QMainWindow):
@ -26,7 +26,7 @@ class QUsermodelEditor(QtWidgets.QMainWindow):
layout.setContentsMargins(3, 3, 3, 3)
layout.setSpacing(3)
self.edit_field = CodeEditor(self.centralwidget)
self.edit_field = EditorWidget(self.centralwidget)
font = QtGui.QFont('default')
font.setStyleHint(font.Monospace)
font.setPointSize(10)

View File

@ -86,11 +86,7 @@
<layout class="QVBoxLayout" name="verticalLayout_6"/>
</widget>
</widget>
<widget class="CodeEditor" name="plainTextEdit">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
<widget class="EditorWidget" name="editor" native="true"/>
</widget>
</item>
<item>
@ -107,9 +103,10 @@
</widget>
<customwidgets>
<customwidget>
<class>CodeEditor</class>
<extends>QPlainTextEdit</extends>
<class>EditorWidget</class>
<extends>QWidget</extends>
<header>..lib.codeeditor</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>

View File

@ -31,13 +31,7 @@
<number>3</number>
</property>
<item>
<widget class="CodeEditor" name="edit_field">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
</widget>
<widget class="EditorWidget" name="widget" native="true"/>
</item>
</layout>
</widget>
@ -47,7 +41,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>30</height>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -85,9 +79,10 @@
</widget>
<customwidgets>
<customwidget>
<class>CodeEditor</class>
<extends>QPlainTextEdit</extends>
<class>EditorWidget</class>
<extends>QWidget</extends>
<header>..lib.codeeditor</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>