From 61b3869f03e66c990167b69f973afc9bdcd724d3 Mon Sep 17 00:00:00 2001 From: Stephen Nneji Date: Fri, 28 Nov 2025 10:25:20 +0000 Subject: [PATCH 1/2] Enable docsting linting in ruff and cleans up some docstrings --- packaging/build_exe.py | 2 +- pyproject.toml | 11 +++++- rascal2/config.py | 14 +++---- rascal2/core/commands.py | 13 ++++--- rascal2/core/worker.py | 3 +- rascal2/dialogs/about_dialog.py | 15 +++++--- rascal2/dialogs/settings_dialog.py | 46 ++++++++++++----------- rascal2/dialogs/startup_dialog.py | 19 +++++----- rascal2/main.py | 3 +- rascal2/settings.py | 2 +- rascal2/ui/model.py | 3 +- rascal2/ui/presenter.py | 7 ++-- rascal2/ui/view.py | 22 +++++------ rascal2/widgets/controls.py | 2 +- rascal2/widgets/inputs.py | 18 ++++----- rascal2/widgets/plot.py | 18 ++++----- rascal2/widgets/project/lists.py | 4 +- rascal2/widgets/project/project.py | 22 ++++------- rascal2/widgets/project/slider_view.py | 19 +++++----- rascal2/widgets/project/tables.py | 9 +++-- rascal2/widgets/startup.py | 23 +++--------- rascal2/widgets/terminal.py | 2 +- tests/core/test_runner.py | 1 - tests/core/test_writer.py | 1 - tests/dialogs/test_about_dialog.py | 23 ++++-------- tests/dialogs/test_custom_file_editor.py | 5 +-- tests/dialogs/test_project_dialog.py | 22 +++-------- tests/ui/test_view.py | 6 +-- tests/widgets/project/test_lists.py | 5 --- tests/widgets/project/test_models.py | 1 - tests/widgets/project/test_project.py | 22 +++-------- tests/widgets/project/test_slider_view.py | 10 ++--- tests/widgets/test_inputs.py | 1 - tests/widgets/test_widgets.py | 8 +--- 34 files changed, 163 insertions(+), 219 deletions(-) diff --git a/packaging/build_exe.py b/packaging/build_exe.py index 84421196..85096e0d 100644 --- a/packaging/build_exe.py +++ b/packaging/build_exe.py @@ -57,7 +57,7 @@ def build_exe(): - """Builds the executable for the rascal-2 application""" + """Builds the executable for the rascal-2 application.""" os.environ["DELAY_MATLAB_START"] = "1" work_path = PACKAGING_PATH / "temp" dist_path = PACKAGING_PATH / "bundle" diff --git a/pyproject.toml b/pyproject.toml index 657eb4e3..3f71866b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,15 @@ line-length = 120 extend-exclude = ["examples/*", "doc/*"] [tool.ruff.lint] -select = ["E", "F", "UP", "B", "SIM", "I", "N", "TD003", "A"] -ignore = ["SIM108", "N817"] +select = ["E", "F", "UP", "B", "SIM", "I", "N", "TD003", "A", "D"] +ignore = ["SIM108", "N817", "D100", "D102", "D104", "D105", "D107", "D203", "D401"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + +# ignore docstring lints in the tests and install script +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["D101", "D103"] [tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false diff --git a/rascal2/config.py b/rascal2/config.py index 83c7d4ac..c7f8648d 100644 --- a/rascal2/config.py +++ b/rascal2/config.py @@ -26,7 +26,7 @@ def handle_scaling(): - """Changes settings to handle UI scaling""" + """Changes settings to handle UI scaling.""" if platform.system() == "Windows": from ctypes import windll @@ -121,7 +121,7 @@ def get_logger(): def log_uncaught_exceptions(exc_type, exc_value, exc_traceback): - """Qt slots swallows exceptions but this ensures exceptions are logged""" + """Qt slots swallows exceptions but this ensures exceptions are logged.""" logger = get_logger() logger.addHandler(logging.StreamHandler(stream=sys.stderr)) # print emergency crashes to terminal logger.critical("An unhandled exception occurred!", exc_info=(exc_type, exc_value, exc_traceback)) @@ -130,7 +130,7 @@ def log_uncaught_exceptions(exc_type, exc_value, exc_traceback): def run_matlab(ready_event, close_event, engine_output): - """Start a new matlab engine instance and waits until closed + """Start a new matlab engine instance and waits until closed. Parameters ---------- @@ -162,7 +162,7 @@ def run_matlab(ready_event, close_event, engine_output): def get_matlab_engine(engine_ready, engine_output, is_local=False): - """Get a MATLAB engine from the MatlabHelper or exception if no engine is available + """Get a MATLAB engine from the MatlabHelper or exception if no engine is available. Parameters ---------- @@ -204,7 +204,7 @@ def get_matlab_engine(engine_ready, engine_output, is_local=False): class MatlabHelper: - """Helper to start MATLAB on another process""" + """Helper to start MATLAB on another process.""" _instance = None @@ -220,7 +220,7 @@ def __new__(cls): return cls._instance def async_start(self): - """Start MATLAB on a new process""" + """Start MATLAB on a new process.""" self.manager = mp.Manager() self.engine_output = self.manager.list() @@ -257,7 +257,7 @@ def get_local_engine(self): return self.__engine def get_matlab_path(self): - """Get MATLAB install directory + """Get MATLAB install directory. Returns ------- diff --git a/rascal2/core/commands.py b/rascal2/core/commands.py index 75004134..50ccf154 100644 --- a/rascal2/core/commands.py +++ b/rascal2/core/commands.py @@ -12,7 +12,7 @@ @unique class CommandID(IntEnum): - """Unique ID for undoable commands""" + """Unique ID for undoable commands.""" EditControls = 1000 EditProject = 2000 @@ -76,8 +76,7 @@ def redo(self): self.new_result = self.old_result def mergeWith(self, command): - """Merges consecutive Edit controls commands if the attributes are the - same.""" + """Merges consecutive Edit controls commands if the attributes are the same.""" # We should think about if merging all Edit controls irrespective of # attribute is the way to go for UX if list(self.new_values.keys()) != list(command.new_values.keys()): @@ -93,11 +92,13 @@ def mergeWith(self, command): return True def id(self): - """Returns ID used for merging commands""" + """Returns ID used for merging commands.""" raise NotImplementedError class EditControls(AbstractModelEdit): + """Command for editing an attribute of the controls model.""" + attribute = "controls" @property @@ -109,6 +110,8 @@ def id(self): class EditProject(AbstractModelEdit): + """Command for editing an attribute of the project model.""" + attribute = "project" @property @@ -204,7 +207,7 @@ def update_calculation_outputs( results: ratapi.outputs.Results | ratapi.outputs.BayesResults, log: str, ): - """Updates the project, results and log in the main window model + """Updates the project, results and log in the main window model. Parameters ---------- diff --git a/rascal2/core/worker.py b/rascal2/core/worker.py index d7735712..cb863a5e 100644 --- a/rascal2/core/worker.py +++ b/rascal2/core/worker.py @@ -22,8 +22,7 @@ def __init__(self, func, args): self.stopped = False def run(self): - """This function is executed on worker thread when the ``QThread.start`` - method is called.""" + """Execute function on worker thread when the start method is called.""" if self.stopped: return diff --git a/rascal2/dialogs/about_dialog.py b/rascal2/dialogs/about_dialog.py index 9865707d..0ee9541e 100644 --- a/rascal2/dialogs/about_dialog.py +++ b/rascal2/dialogs/about_dialog.py @@ -10,9 +10,16 @@ class AboutDialog(QtWidgets.QDialog): + """Dialog to display RasCAL about information. + + Parameters + ---------- + parent : MainWindowView + An instance of MainWindowView + """ + def __init__(self, parent=None): super().__init__(parent) - # Define internal variables # Define main window self.setWindowTitle("About RasCAL 2") @@ -62,10 +69,8 @@ def __init__(self, parent=None): main_layout.addStretch(1) self.setLayout(main_layout) - def update_rascal_info(self, parent): - """Obtain info about RASCAL (version, main settings etc.) - retrieved from general class information - """ + def update_rascal_info(self): + """Obtain info about RASCAL (version, main settings etc.).""" matlab_path = MatlabHelper().get_matlab_path() if not matlab_path: matlab_path = "None" diff --git a/rascal2/dialogs/settings_dialog.py b/rascal2/dialogs/settings_dialog.py index 573eb666..16f4a89b 100644 --- a/rascal2/dialogs/settings_dialog.py +++ b/rascal2/dialogs/settings_dialog.py @@ -11,15 +11,15 @@ class SettingsDialog(QtWidgets.QDialog): - def __init__(self, parent): - """ - Dialog to adjust RasCAL-2 settings. + """Dialog to adjust RasCAL-2 settings. - Parameters - ---------- - parent : MainWindowView - The view of the RasCAL-2 GUI - """ + Parameters + ---------- + parent : MainWindowView + The view of the RasCAL-2 GUI + """ + + def __init__(self, parent): super().__init__(parent) self.setModal(True) @@ -59,7 +59,7 @@ def __init__(self, parent): self.setWindowTitle("Settings") def update_settings(self) -> None: - """Accept the changed settings""" + """Accept the changed settings.""" self.parent().settings = self.settings if self.parent().presenter.model.save_path: self.parent().settings.save(self.parent().presenter.model.save_path) @@ -67,24 +67,25 @@ def update_settings(self) -> None: self.accept() def reset_default_settings(self) -> None: - """Reset the settings to the global defaults""" + """Reset the settings to the global defaults.""" delete_local_settings(self.parent().presenter.model.save_path) self.parent().settings = Settings() self.accept() class SettingsTab(QtWidgets.QWidget): - def __init__(self, parent: SettingsDialog, group: SettingsGroups): - """A tab in the Settings Dialog tab layout. + """A tab in the Settings Dialog tab layout. - Parameters - ---------- - parent : SettingsDialog - The dialog in which this tab lies - group : SettingsGroups - The set of settings with this value in "title" field of the - Settings object's "field_info" will be included in this tab. - """ + Parameters + ---------- + parent : SettingsDialog + The dialog in which this tab lies + group : SettingsGroups + The set of settings with this value in "title" field of the + Settings object's "field_info" will be included in this tab. + """ + + def __init__(self, parent: SettingsDialog, group: SettingsGroups): super().__init__(parent) self.settings = parent.settings @@ -124,8 +125,9 @@ def modify_setting(self, setting: str): class MatlabSetupTab(QtWidgets.QWidget): + """Dialog to adjust Matlab location settings.""" + def __init__(self): - """Dialog to adjust Matlab location settings.""" super().__init__() form_layout = QtWidgets.QGridLayout() @@ -171,7 +173,7 @@ def open_folder_selector(self) -> None: self.changed = True def set_matlab_paths(self): - """Update MATLAB paths in arch file""" + """Update MATLAB paths in arch file.""" if not self.changed: return diff --git a/rascal2/dialogs/startup_dialog.py b/rascal2/dialogs/startup_dialog.py index aacbbc76..51f503c5 100644 --- a/rascal2/dialogs/startup_dialog.py +++ b/rascal2/dialogs/startup_dialog.py @@ -27,13 +27,12 @@ class StartupDialog(QtWidgets.QDialog): folder_selector = QtWidgets.QFileDialog.getExistingDirectory def __init__(self, parent): - """ - Initialize dialog. + """Initialize dialog. Parameters ---------- parent: MainWindowView - An instance of the MainWindowView + An instance of the MainWindowView """ super().__init__(parent) @@ -67,7 +66,7 @@ def compose_layout(self): self.setLayout(main_layout) def create_loading_bar(self): - """Creates non-deterministic progress bar""" + """Creates non-deterministic progress bar.""" self.loading_bar = QtWidgets.QProgressBar() self.loading_bar.setMinimum(0) self.loading_bar.setMaximum(0) @@ -245,7 +244,7 @@ def create_project(self) -> None: class DisplayWidget(QtWidgets.QWidget): - """Fancy display widget for title and description items in a list""" + """Fancy display widget for title and description items in a list.""" def __init__(self, title, desc): super().__init__() @@ -280,7 +279,7 @@ def compose_layout(self): self.setLayout(main_layout) def create_load_tab(self): - """Creates the load project widget""" + """Creates the load project widget.""" layout = QtWidgets.QVBoxLayout() layout.setSpacing(20) @@ -304,7 +303,7 @@ def create_load_tab(self): self.tabs.addTab(load_tab, "Load Project") def create_list_widget_tab(self, tab_name: str): - """Create the list widget and add it to tab with given name + """Create the list widget and add it to tab with given name. Parameters ---------- @@ -328,7 +327,7 @@ def create_list_widget_tab(self, tab_name: str): return list_widget def create_example_tab(self): - """Creates the example widget""" + """Creates the example widget.""" self.example_list_widget = self.create_list_widget_tab("Examples") for name, desc in EXAMPLES.items(): @@ -341,7 +340,7 @@ def create_example_tab(self): item.setSizeHint(item_widget.sizeHint()) def create_recent_tab(self): - """Creates the recent project widget""" + """Creates the recent project widget.""" recent_projects = update_recent_projects() recent_projects = recent_projects[:6] self.recent_list_widget = self.create_list_widget_tab("Recent Projects") @@ -396,7 +395,7 @@ def load_project(self, item=None): self.block_for_worker(True) def block_for_worker(self, disabled: bool): - """Disable UI while worker is completing + """Disable UI while worker is completing. Parameters ---------- diff --git a/rascal2/main.py b/rascal2/main.py index 73021f80..79f37ecc 100644 --- a/rascal2/main.py +++ b/rascal2/main.py @@ -10,7 +10,7 @@ def ui_execute(): - """Creates main window and executes GUI event loop + """Creates main window and executes GUI event loop. Returns ------- @@ -39,6 +39,7 @@ def ui_execute(): def main(): + """Entry point function for starting RasCAL.""" multiprocessing.freeze_support() multiprocessing.set_start_method("spawn", force=True) sys.excepthook = log_uncaught_exceptions diff --git a/rascal2/settings.py b/rascal2/settings.py index 4e079cbf..c6207400 100644 --- a/rascal2/settings.py +++ b/rascal2/settings.py @@ -41,7 +41,7 @@ def delete_local_settings(path: str | PathLike) -> None: class SettingsGroups(StrEnum): - """The groups of the RasCAL-2 settings, used to set tabs in the dialog""" + """The groups of the RasCAL-2 settings, used to set tabs in the dialog.""" General = "General" Logging = "Logging" diff --git a/rascal2/ui/model.py b/rascal2/ui/model.py index 248693b9..1efd7521 100644 --- a/rascal2/ui/model.py +++ b/rascal2/ui/model.py @@ -7,7 +7,7 @@ class MainWindowModel(QtCore.QObject): - """Manages project data and communicates to view via signals + """Manages project data and communicates to view via signals. Emits ----- @@ -83,7 +83,6 @@ def update_project(self, new_values: dict) -> None: def save_project(self): """Save the project to the save path.""" - self.controls.save(Path(self.save_path, "controls.json")) self.project.save(Path(self.save_path, "project.json")) if self.results: diff --git a/rascal2/ui/presenter.py b/rascal2/ui/presenter.py index 66ffb5ed..cee9ade0 100644 --- a/rascal2/ui/presenter.py +++ b/rascal2/ui/presenter.py @@ -17,12 +17,12 @@ class MainWindowPresenter: - """Facilitates interaction between View and Model + """Facilitates interaction between View and Model. Parameters ---------- view : MainWindow - main window view instance. + An instance of the MainWindowView """ def __init__(self, view): @@ -151,7 +151,7 @@ def ask_to_save_project(self): return proceed def export_fits(self): - """Export results into multiple csv files in a zip file""" + """Export results into multiple csv files in a zip file.""" if self.model.results is None: return @@ -172,6 +172,7 @@ def interrupt_terminal(self): def quick_run(self, project=None): """Run rat calculation with calculate procedure on the given project. + The project in the MainWindowModel is used if no project is provided. Parameters diff --git a/rascal2/ui/view.py b/rascal2/ui/view.py index a129c84d..5f9a5726 100644 --- a/rascal2/ui/view.py +++ b/rascal2/ui/view.py @@ -18,7 +18,7 @@ class MainWindowView(QtWidgets.QMainWindow): - """Creates the main view for the RasCAL app""" + """Creates the main view for the RasCAL application.""" def __init__(self): super().__init__() @@ -95,8 +95,7 @@ def show_settings_dialog(self, tab_name=""): settings_dlg.show() def create_actions(self): - """Creates the menu and toolbar actions""" - + """Creates the menu and toolbar actions.""" self.new_project_action = QtGui.QAction("&New Project", self) self.new_project_action.setStatusTip("Create a new project") self.new_project_action.setIcon(QtGui.QIcon(path_for("new-project.png"))) @@ -209,7 +208,7 @@ def create_actions(self): self.setup_matlab_action.triggered.connect(lambda: self.show_settings_dialog(tab_name="Matlab")) def create_menus(self): - """Add sub menus to the main menu bar""" + """Add sub menus to the main menu bar.""" main_menu = self.menuBar() main_menu.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.PreventContextMenu) @@ -263,21 +262,22 @@ def toggle_sliders(self): self.project_widget.show_project_view() def open_about_info(self): - """Opens about menu containing information about RASCAL gui""" + """Opens about dialog containing information about RASCAL.""" self.about_dialog.update_rascal_info(self) self.about_dialog.show() def show_undo_view(self): + """Show and raise undo view to top of parent.""" self.undo_view.showNormal() self.undo_view.raise_() def open_docs(self): - """Opens the documentation""" + """Opens the documentation.""" url = QtCore.QUrl("https://rascalsoftware.github.io/RAT-Docs/dev/index.html") QtGui.QDesktopServices.openUrl(url) def create_toolbar(self): - """Creates the toolbar""" + """Creates the toolbar.""" self.toolbar = self.addToolBar("ToolBar") self.toolbar.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.PreventContextMenu) self.toolbar.setMovable(False) @@ -291,12 +291,12 @@ def create_toolbar(self): self.toolbar.addAction(self.open_help_action) def create_status_bar(self): - """Creates the status bar""" + """Creates the status bar.""" sb = QtWidgets.QStatusBar() self.setStatusBar(sb) def setup_mdi(self): - """Creates the multi-document interface""" + """Creates the multi-document interface.""" # if windows are already created, don't set them up again, # just refresh the widget data if len(self.mdi.subWindowList()) == 4: @@ -322,9 +322,7 @@ def setup_mdi(self): self.setCentralWidget(self.mdi) def setup_mdi_widgets(self): - """ - Performs initialization of MDI widgets that rely on the Project being defined. - """ + """Performs initialization of MDI widgets that rely on the Project being defined.""" self.controls_widget.setup_controls() self.project_widget.show_project_view() self.plot_widget.clear() diff --git a/rascal2/widgets/controls.py b/rascal2/widgets/controls.py index 0158c2a3..c515c9ce 100644 --- a/rascal2/widgets/controls.py +++ b/rascal2/widgets/controls.py @@ -104,7 +104,7 @@ def setup_controls(self): self.procedure_dropdown.setCurrentIndex(init_procedure) def update_ui(self): - """Updates UI without firing signals to avoid recursion""" + """Updates UI without firing signals to avoid recursion.""" init_procedure = [p.value for p in Procedures].index(self.presenter.model.controls.procedure) self.procedure_dropdown.blockSignals(True) self.procedure_dropdown.setCurrentIndex(init_procedure) diff --git a/rascal2/widgets/inputs.py b/rascal2/widgets/inputs.py index 828efb94..c326071f 100644 --- a/rascal2/widgets/inputs.py +++ b/rascal2/widgets/inputs.py @@ -187,6 +187,7 @@ def showEvent(self, event): self.open_on_show = False def open(self): + """Open file dialog and get the selected filename.""" file_dialog = QtWidgets.QFileDialog(parent=self) file = file_dialog.getOpenFileName()[0] if file: @@ -395,8 +396,7 @@ def set_inner_limit(self, limit: Iterable[float]): class MultiSelectComboBox(QtWidgets.QComboBox): - """ - A custom combo box widget that allows for multi-select functionality. + """A custom combo box widget that allows for multi-select functionality. This widget provides the ability to select multiple items from a dropdown list and display them in a comma-separated format in the @@ -410,6 +410,8 @@ class MultiSelectComboBox(QtWidgets.QComboBox): selection_changed = QtCore.pyqtSignal() class Delegate(QtWidgets.QStyledItemDelegate): + """Styled Item Delegate for MultiSelectCombobox.""" + def sizeHint(self, option, index): size = super().sizeHint(option, index) size.setHeight(20) @@ -490,7 +492,6 @@ def addItem(self, text: str, data: str = None) -> None: The associated data. Default is None. """ - self.model().appendRow(self.create_item(text, data)) def create_item(self, text: str, data: str = None): @@ -605,7 +606,7 @@ def showEvent(self, event) -> None: class ProgressButton(QtWidgets.QPushButton): - """Creates a custom button that displays a busy indicator + """Creates a custom button that displays a busy indicator. progress_text : str text to display when showing progress. @@ -623,12 +624,12 @@ def default_text(self): @default_text.setter def default_text(self, text): - """Setter for button text""" + """Setter for button text.""" self._default_text = text self.setText(text) def show_progress(self): - """Shows busy indicator""" + """Shows busy indicator.""" self.setEnabled(False) self.setText(f"{self.progress_text} ...") @@ -636,7 +637,7 @@ def update_progress(self, current, total): self.setText(f"{self.progress_text} - {current} of {total}") def hide_progress(self): - """Hides busy indicator""" + """Hides busy indicator.""" self.setEnabled(True) self.setText(self.default_text) @@ -644,7 +645,6 @@ def hide_progress(self): class MultiSelectList(QtWidgets.QWidget): """A custom widget that allows repeat selection from a list of options. - Parameters ---------- parent : QWidget or None, default None @@ -699,7 +699,7 @@ def update_selection_list(self, items): self.select_menu.addAction(add_item_action) def add_item(self, name): - """Add an item with given name to the list + """Add an item with given name to the list. Parameters ---------- diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index 807ec736..f4335120 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -141,20 +141,20 @@ def timerEvent(self, event): self.resize_timer = 0 def draw_current_panel_plot(self): - """Draw the current panel plot (if not corner) when resizing""" + """Draw the current panel plot (if not corner) when resizing.""" if 0 < self.plot_tabs.currentIndex() < 3: self.plot_tabs.currentWidget().draw_plot() self.set_redraw_state() self.resize_timer = 0 def set_redraw_state(self): - """Set the redraw state of not visible panel plots""" + """Set the redraw state of not visible panel plots.""" index = self.plot_tabs.currentIndex() self.plot_tabs.widget(1).redraw_plot = index != 1 self.plot_tabs.widget(2).redraw_plot = index != 2 def redraw_panel_plot(self): - """Draw current panel plot if its redraw state is True""" + """Draw current panel plot if its redraw state is True.""" widget = self.plot_tabs.currentWidget() if isinstance(widget, AbstractPanelPlotWidget) and widget.redraw_plot: widget.canvas.setVisible(False) @@ -243,7 +243,7 @@ def update_figure_size(self): self.figure.set_size_inches(sx, sy) def show_result_summary(self, results): - """Show log z and log z error in summary label""" + """Show log z and log z error in summary label.""" if isinstance(results, ratapi.outputs.BayesResults) and results.from_procedure() == "ns": self.result_summary.setText( f"log (Z) = {results.nestedSamplerOutput.logZ:.5f}\n" @@ -280,7 +280,7 @@ def make_interaction_layout(self): return button_layout def toggle_settings(self, toggled_on: bool): - """Toggles the visibility of the plot controls""" + """Toggles the visibility of the plot controls.""" self.plot_controls.setVisible(toggled_on) if toggled_on: self.toggle_button.setIcon(QtGui.QIcon(path_for("hide-settings.png"))) @@ -343,7 +343,7 @@ def export(self): class RefSLDWidget(AbstractPlotWidget): - """Creates a UI for displaying the path lengths from the simulation result""" + """Creates a UI for displaying the path lengths from the simulation result.""" def make_control_layout(self): self.plot_controls = QtWidgets.QWidget() @@ -438,7 +438,7 @@ def plot(self, project: ratapi.Project, results: ratapi.outputs.Results | ratapi self.plot_event(data) def plot_event(self, data: ratapi.events.PlotEventData | None = None): - """Updates the ref and SLD plots from a provided or cached plot event + """Updates the ref and SLD plots from a provided or cached plot event. Parameters ---------- @@ -472,7 +472,7 @@ def plot_event(self, data: ratapi.events.PlotEventData | None = None): self.canvas.draw() def plot_with_blit(self, data: ratapi.events.PlotEventData | None = None): - """Updates the ref and SLD plots with blitting + """Updates the ref and SLD plots with blitting. Parameters ---------- @@ -551,7 +551,7 @@ def draw_plot(self): class AbstractPanelPlotWidget(AbstractPlotWidget): - """Abstract base widget for plotting panels of parameters (corner plot, histograms, chains) + """Abstract base widget for plotting panels of parameters (corner plot, histograms, chains). These widgets all share a parameter multi-select box, so it is defined here. diff --git a/rascal2/widgets/project/lists.py b/rascal2/widgets/project/lists.py index 645c0807..075ddc5d 100644 --- a/rascal2/widgets/project/lists.py +++ b/rascal2/widgets/project/lists.py @@ -85,7 +85,6 @@ def append_item(self, item: T = None): item : T, optional The item to append. If None, will add a blank item. """ - self.classlist.append(item if item is not None else self.item_type()) self.endResetModel() @@ -172,7 +171,7 @@ def update_model(self, classlist): ) def item_changed(self, index): - """Update widget when a new item is selected from list + """Update widget when a new item is selected from list. Parameters ---------- @@ -185,7 +184,6 @@ def item_changed(self, index): def update_item_view(self): """Update the item views to correspond with the list model.""" - self.view_stack = QtWidgets.QStackedWidget(self) layout = QtWidgets.QVBoxLayout() layout.addWidget(self.view_stack) diff --git a/rascal2/widgets/project/project.py b/rascal2/widgets/project/project.py index 449bd405..e9ceda61 100644 --- a/rascal2/widgets/project/project.py +++ b/rascal2/widgets/project/project.py @@ -24,13 +24,10 @@ class ProjectWidget(QtWidgets.QWidget): - """ - The Project MDI Widget - """ + """The Project MDI Widget.""" def __init__(self, parent): - """ - Initialize widget. + """Initialize widget. Parameters ---------- @@ -81,7 +78,7 @@ def __init__(self, parent): self.setLayout(layout) def create_project_view(self) -> QtWidgets.QWidget: - """Creates the project (non-edit) view""" + """Creates the project (non-edit) view.""" project_widget = QtWidgets.QWidget() main_layout = QtWidgets.QVBoxLayout() main_layout.setSpacing(20) @@ -149,8 +146,7 @@ def create_project_view(self) -> QtWidgets.QWidget: return project_widget def create_edit_view(self) -> QtWidgets.QWidget: - """Creates the project edit view""" - + """Creates the project edit view.""" edit_project_widget = QtWidgets.QWidget() main_layout = QtWidgets.QVBoxLayout() main_layout.setSpacing(20) @@ -269,7 +265,6 @@ def update_slider_view(self): def update_project_view(self, update_tab_index=None) -> None: """Updates the project view.""" - if update_tab_index is None: update_tab_index = self.stacked_widget.currentIndex() tab_to_update = self.view_tabs if update_tab_index == 0 else self.edit_tabs @@ -307,8 +302,7 @@ def update_project_view(self, update_tab_index=None) -> None: ) def update_draft_project(self, new_values: dict) -> None: - """ - Updates the draft project. + """Updates the draft project. Parameters ---------- @@ -378,16 +372,14 @@ def handle_model_update(self, new_entry): self.edit_tabs["Contrasts"].tables["contrasts"].update_item_view() def show_project_view(self) -> None: - """Show project view""" + """Show project view.""" self.update_project_view(1) self.setWindowTitle("Project") self.parent.controls_widget.run_button.setEnabled(True) self.stacked_widget.setCurrentIndex(0) def show_edit_view(self) -> None: - """Show edit view""" - - # will be updated according to edit changes + """Show edit view.""" self.update_project_view(0) self.setWindowTitle("Edit Project") self.parent.controls_widget.run_button.setEnabled(False) diff --git a/rascal2/widgets/project/slider_view.py b/rascal2/widgets/project/slider_view.py index 80fc0cbe..d3e285d4 100644 --- a/rascal2/widgets/project/slider_view.py +++ b/rascal2/widgets/project/slider_view.py @@ -94,6 +94,7 @@ def _add_sliders_widgets(self): self.slider_content_layout.addStretch(1) def update_result_and_plots(self): + """Update and plot result when sliders are changed.""" project = ratapi.Project() vars(project).update(self.draft_project) results = self._parent.presenter.quick_run(project) @@ -105,16 +106,16 @@ def _cancel_changes_from_sliders(self): self._parent.toggle_sliders() def _apply_changes_from_sliders(self): - """ - Apply changes obtained from sliders to the project and close slider view. - """ + """Apply changes obtained from sliders to the project and close slider view.""" self._parent.presenter.edit_project(self.draft_project) self._parent.toggle_sliders() class LabeledSlider(QtWidgets.QFrame): + """Create a LabeledSlider widget.""" + def __init__(self, param, parent): - """Create a LabeledSlider for a given RAT parameter + """Create a LabeledSlider for a given RAT parameter. Parameters ---------- @@ -123,7 +124,6 @@ def __init__(self, param, parent): parent : SliderViewWidget The container for the slider widget. """ - super().__init__() self.parent = parent self._value_label_format: str = "{:.3g}" @@ -214,13 +214,13 @@ def paintEvent(self, event): def _param_value_to_slider_value(self, param_value: float) -> int: """Convert parameter value into slider value. - Parameters: - ----------- + Parameters + ---------- param_value : float parameter value - Returns: - -------- + Returns + ------- value : int slider value that corresponds to the parameter value """ @@ -242,7 +242,6 @@ def _slider_value_to_param_value(self, value: int) -> float: param_value : float parameter value that corresponds to slider value """ - value_step = (self.param.max - self.param.min) / self._slider.maximum() param_value = self.param.min + value * value_step if param_value > self.param.max: # This should not happen but do occur due to round-off errors diff --git a/rascal2/widgets/project/tables.py b/rascal2/widgets/project/tables.py index e2d72834..c2e1d61f 100644 --- a/rascal2/widgets/project/tables.py +++ b/rascal2/widgets/project/tables.py @@ -43,7 +43,6 @@ def __init__(self, classlist: ratapi.ClassList, parent: QtWidgets.QWidget): def setup_classlist(self, classlist: ratapi.ClassList): """Setup the ClassList, type and headers for the model.""" - self.classlist = classlist self.item_type = classlist._class_handle if not issubclass(self.item_type, pydantic.BaseModel): @@ -144,8 +143,8 @@ def delete_item(self, row: int): def index_header(self, index): """Get the header for an index. - Parameters: - ----------- + Parameters + ---------- index : QModelIndex The model index for the header. @@ -211,7 +210,7 @@ def resizeEvent(self, event): super().resizeEvent(event) def resize_columns(self): - """Resize the columns of the tableview to avoid truncating content""" + """Resize the columns of the tableview to avoid truncating content.""" header = self.table.horizontalHeader() header.setStretchLastSection(False) main_col = "filename" if self.model.headers[1] == "filename" else "name" @@ -609,6 +608,8 @@ def append_item(self): class CustomFileWidget(ProjectFieldWidget): + """Subclass of field widgets for custom file.""" + classlist_model = CustomFileModel def edit(self): diff --git a/rascal2/widgets/startup.py b/rascal2/widgets/startup.py index 7df874ac..960d2a63 100644 --- a/rascal2/widgets/startup.py +++ b/rascal2/widgets/startup.py @@ -5,13 +5,10 @@ class StartUpWidget(QtWidgets.QWidget): - """ - The Start Up widget - """ + """The StartUp widget.""" def __init__(self, parent): - """ - Initialize widget. + """Initialize widget. Parameters ---------- @@ -27,9 +24,7 @@ def __init__(self, parent): self.add_widgets_to_layout() def add_widgets_to_layout(self) -> None: - """ - Add widgets to layout. - """ + """Add widgets to layout.""" startup_layout = QtWidgets.QVBoxLayout() startup_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) @@ -53,9 +48,7 @@ def add_widgets_to_layout(self) -> None: self.setLayout(startup_layout) def create_banner_and_footer(self) -> None: - """ - Create banner and footer. - """ + """Create banner and footer.""" self.banner_label = QtWidgets.QLabel() self.banner_label.setPixmap(QtGui.QPixmap(path_for("banner.png"))) self.banner_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) @@ -65,9 +58,7 @@ def create_banner_and_footer(self) -> None: self.footer_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) def create_buttons(self) -> None: - """ - Create buttons. - """ + """Create buttons.""" self.new_project_button = QtWidgets.QToolButton(objectName="NewProjectButton") self.new_project_button.clicked.connect(lambda: self.parent().show_project_dialog(NewProjectDialog)) @@ -78,9 +69,7 @@ def create_buttons(self) -> None: self.import_r1_button.clicked.connect(lambda: self.parent().show_project_dialog(LoadR1Dialog)) def create_labels(self) -> None: - """ - Create labels. - """ + """Create labels.""" self.new_project_label = QtWidgets.QLabel("New\nProject") self.new_project_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) diff --git a/rascal2/widgets/terminal.py b/rascal2/widgets/terminal.py index 092d4a35..ae37e373 100644 --- a/rascal2/widgets/terminal.py +++ b/rascal2/widgets/terminal.py @@ -104,4 +104,4 @@ def update_progress(self, event): self.progress_bar.setValue(int(event.percent * 100)) def flush(self): - """Added to make TerminalWidget an IO stream""" + """Added to make TerminalWidget an IO stream.""" diff --git a/tests/core/test_runner.py b/tests/core/test_runner.py index 819c6f02..be225ba4 100644 --- a/tests/core/test_runner.py +++ b/tests/core/test_runner.py @@ -25,7 +25,6 @@ def make_progress_event(percent): def mock_rat_main(*args, **kwargs): """Mock of RAT main that produces some signals.""" - rat.events.notify(rat.events.EventTypes.Progress, make_progress_event(0.2)) rat.events.notify(rat.events.EventTypes.Progress, make_progress_event(0.5)) rat.events.notify(rat.events.EventTypes.Message, "test message") diff --git a/tests/core/test_writer.py b/tests/core/test_writer.py index 439af36f..c03f5a6f 100644 --- a/tests/core/test_writer.py +++ b/tests/core/test_writer.py @@ -24,7 +24,6 @@ ) def test_write_zipped_csv(result_file): """Test the data is written to zipped csvs successfully.""" - result = ratapi.Results.load(DATA_PATH / result_file) with tempfile.TemporaryDirectory() as tmp: zip_path = Path(tmp, "project.zip") diff --git a/tests/dialogs/test_about_dialog.py b/tests/dialogs/test_about_dialog.py index f7e9114a..f621fb84 100644 --- a/tests/dialogs/test_about_dialog.py +++ b/tests/dialogs/test_about_dialog.py @@ -1,26 +1,19 @@ from unittest.mock import MagicMock, patch -import pytest +from PyQt6 import QtWidgets from rascal2.dialogs.about_dialog import AboutDialog -from rascal2.ui.view import MainWindowView - - -@pytest.fixture -def about(): - return AboutDialog() - - -def test_about_dialog_construction(about): - assert about._rascal_label.text() == "information about RASCAL-2" @patch("rascal2.dialogs.about_dialog.MatlabHelper", autospec=True) -def test_update_info_works(mock_matlab, about): - """Check if update rascal info add all necessary information to the rascal label""" +def test_update_info_works(mock_matlab): + """Check if `update_rascal_info` adds all necessary information to the dialog.""" mock_matlab.return_value = MagicMock() - main_windows = MainWindowView() - about.update_rascal_info(main_windows) + parent = QtWidgets.QMainWindow() + about = AboutDialog(parent) + assert about._rascal_label.text() == "information about RASCAL-2" + + about.update_rascal_info() rascal_info = about._rascal_label.text() assert "Version" in rascal_info assert "RasCAL 2" in rascal_info diff --git a/tests/dialogs/test_custom_file_editor.py b/tests/dialogs/test_custom_file_editor.py index 03742d0c..dfee58c1 100644 --- a/tests/dialogs/test_custom_file_editor.py +++ b/tests/dialogs/test_custom_file_editor.py @@ -30,8 +30,7 @@ def _dialog(language, tmpdir): @patch("rascal2.dialogs.custom_file_editor.CustomFileEditorDialog.exec") def test_edit_file(exec_mock): - """Test that the dialog is executed when edit_file() is called on a valid file""" - + """Test that the dialog is executed when edit_file() is called on a valid file.""" with tempfile.TemporaryDirectory() as tmp: file = Path(tmp, "testfile.py") file.touch() @@ -44,7 +43,6 @@ def test_edit_file(exec_mock): @patch("rascal2.dialogs.custom_file_editor.CustomFileEditorDialog") def test_edit_incorrect_file(dialog_mock, filepath, caplog): """A logger error should be emitted if a directory or nonexistent file is given to the editor.""" - with tempfile.TemporaryDirectory() as tmp: file = Path(tmp, filepath) edit_file(file, Languages.Python, parent) @@ -94,7 +92,6 @@ def test_edit_no_matlab_engine(mock_matlab, caplog): ) def test_dialog_init(custom_file_dialog, language, expected_lexer): """Ensure the custom file editor is set up correctly.""" - with tempfile.TemporaryDirectory() as tmp: dialog = custom_file_dialog(language, tmp) diff --git a/tests/dialogs/test_project_dialog.py b/tests/dialogs/test_project_dialog.py index a3d75741..1c9b1d80 100644 --- a/tests/dialogs/test_project_dialog.py +++ b/tests/dialogs/test_project_dialog.py @@ -29,9 +29,7 @@ def __init__(self): ), ) def test_project_dialog_initial_state(dialog, num_widgets): - """ - Tests that each dialog has expected initial state. - """ + """Tests that each dialog has expected initial state.""" with patch("rascal2.dialogs.startup_dialog.update_recent_projects", return_value=[]): project_dialog = dialog(view) @@ -58,9 +56,7 @@ def test_project_dialog_initial_state(dialog, num_widgets): @pytest.mark.parametrize("folder, folder_valid", [("", False), ("Folder", True)]) @pytest.mark.parametrize("other_folder_error", [True, False]) def test_create_button(name, name_valid, folder, folder_valid, other_folder_error): - """ - Tests project creation on the NewProjectDialog class. - """ + """Tests project creation on the NewProjectDialog class.""" project_dialog = NewProjectDialog(view) mock_create = view.presenter.create_project = MagicMock() @@ -84,10 +80,7 @@ def test_create_button(name, name_valid, folder, folder_valid, other_folder_erro @pytest.mark.parametrize("other_folder_error", [True, False]) @patch("rascal2.dialogs.startup_dialog.Worker", autospec=True) def test_load_button(worker_mock, widget, folder, folder_valid, other_folder_error): - """ - Tests project loading on the LoadDialog and LoadR1Dialog class. - """ - + """Tests project loading on the LoadDialog and LoadR1Dialog class.""" with patch("rascal2.dialogs.startup_dialog.update_recent_projects", return_value=[]): project_dialog = widget(view) if widget == LoadDialog: @@ -108,9 +101,7 @@ def test_load_button(worker_mock, widget, folder, folder_valid, other_folder_err @patch.object(StartupDialog, "reject") def test_cancel_button(mock_reject): - """ - Tests cancel button on the StartupDialog class. - """ + """Tests cancel button on the StartupDialog class.""" view.startup_dlg = None project_dialog = StartupDialog(view) @@ -121,9 +112,7 @@ def test_cancel_button(mock_reject): def test_folder_selector(): - """ - Tests the folder selector and verification on the StartupDialog class. - """ + """Tests the folder selector and verification on the StartupDialog class.""" project_dialog = StartupDialog(view) project_dialog.folder_selector = MagicMock() project_dialog.folder_selector.return_value = "/test/folder/path" @@ -158,7 +147,6 @@ def error(folder_path): ) def test_recent_projects(recent): """Tests that the Recent Projects list is as expected.""" - with patch("rascal2.dialogs.startup_dialog.update_recent_projects", return_value=recent): project_dialog = LoadDialog(view) diff --git a/tests/ui/test_view.py b/tests/ui/test_view.py index 70a5d128..f3828d7a 100644 --- a/tests/ui/test_view.py +++ b/tests/ui/test_view.py @@ -148,8 +148,7 @@ def change_dir(*args, **kwargs): @pytest.mark.parametrize("submenu_name", ["&File", "&Edit", "&Windows", "&Tools", "&Help"]) def test_menu_element_present(test_view, submenu_name): - """Test requested menu items are present""" - + """Test requested menu items are present.""" main_menu = test_view.menuBar() elements = main_menu.children() @@ -184,8 +183,7 @@ def test_menu_element_present(test_view, submenu_name): ], ) def test_help_menu_actions_present(test_view, submenu_name, action_names_and_layout): - """Test if menu actions are available and their layouts are as specified in parameterize""" - + """Test if menu actions are available and their layouts are as specified in parameterize.""" main_menu = test_view.menuBar() submenus = main_menu.findChildren(QtWidgets.QMenu) for menu in submenus: diff --git a/tests/widgets/project/test_lists.py b/tests/widgets/project/test_lists.py index d0867e09..e01a2862 100644 --- a/tests/widgets/project/test_lists.py +++ b/tests/widgets/project/test_lists.py @@ -148,7 +148,6 @@ def test_project_list_widget_empty_model(): @pytest.mark.parametrize("edit_mode, expected_labels", ([False, ["a", "b", "c"]], [True, ["1", "2", "3"]])) def test_project_list_widget_build(mock_project_widget, edit_mode, expected_labels): """Test that the project list widget builds correctly when given a model.""" - widget = mock_project_widget(edit_mode) assert widget.view_stack.count() == 3 @@ -162,7 +161,6 @@ def test_project_list_widget_build(mock_project_widget, edit_mode, expected_labe @pytest.mark.parametrize("edit_mode, expected_labels", ([False, ["a", "b", "c"]], [True, ["1", "2", "3"]])) def test_project_list_widget_choose(mock_project_widget, edit_mode, expected_labels): """Test that the current widget changes when the item is selected.""" - widget = mock_project_widget(edit_mode) for i, label in enumerate(expected_labels): @@ -174,7 +172,6 @@ def test_project_list_widget_choose(mock_project_widget, edit_mode, expected_lab @pytest.mark.parametrize("edit_mode, expected_label", ([False, "New Item"], [True, "0"])) def test_project_list_widget_append(mock_project_widget, edit_mode, expected_label): """Test that items are correctly appended to a project list widget.""" - widget = mock_project_widget(edit_mode) widget.append_item() @@ -187,7 +184,6 @@ def test_project_list_widget_append(mock_project_widget, edit_mode, expected_lab def test_project_list_widget_delete(mock_project_widget): """Test that items are correctly deleted from a project list widget.""" - widget = mock_project_widget() sel_mod = widget.list.selectionModel() @@ -204,7 +200,6 @@ def test_project_list_widget_delete(mock_project_widget): def test_standard_layer_widget_init(): """Test that the StandardLayerModelWidget initialises as expected.""" - widget = StandardLayerModelWidget(["a", "b", "c"], parent) assert widget.layer_list.model().stringList() == ["a", "b", "c"] diff --git a/tests/widgets/project/test_models.py b/tests/widgets/project/test_models.py index 22ddc14d..2b2925da 100644 --- a/tests/widgets/project/test_models.py +++ b/tests/widgets/project/test_models.py @@ -464,7 +464,6 @@ def test_file_model_set_filename(filename, expected_lang, expected_filenames): @pytest.mark.parametrize("filename", ["file.m", "file.py", "file.dll", ""]) def test_file_widget_edit(filename): """Test that the correct index widget is created in edit mode.""" - with tempfile.TemporaryDirectory() as tmp: Path(tmp, "file.py").touch() init_list = ratapi.ClassList([ratapi.models.CustomFile(filename="")]) diff --git a/tests/widgets/project/test_project.py b/tests/widgets/project/test_project.py index d8cd7053..b38d5496 100644 --- a/tests/widgets/project/test_project.py +++ b/tests/widgets/project/test_project.py @@ -101,9 +101,7 @@ def _param_model(protected_indices): def test_project_widget_initial_state(setup_project_widget): - """ - Tests the inital state of the ProjectWidget class. - """ + """Tests the inital state of the ProjectWidget class.""" project_widget = setup_project_widget # Check the layout of the project view @@ -155,9 +153,7 @@ def test_project_widget_initial_state(setup_project_widget): def test_edit_cancel_button_toggle(setup_project_widget): - """ - Tests clicking the edit button causes the stacked widget to change state. - """ + """Tests clicking the edit button causes the stacked widget to change state.""" project_widget = setup_project_widget assert project_widget.stacked_widget.currentIndex() == 0 @@ -177,9 +173,7 @@ def test_edit_cancel_button_toggle(setup_project_widget): def test_save_changes_to_model_project(setup_project_widget): - """ - Tests that making changes to the project settings - """ + """Tests that making changes to the project settings.""" project_widget = setup_project_widget project_widget.edit_project_button.click() @@ -197,10 +191,7 @@ def test_save_changes_to_model_project(setup_project_widget): def test_cancel_changes_to_model_project(setup_project_widget): - """ - Tests that making changes to the project settings and - not saving them reverts the changes. - """ + """Tests that making changes to the project settings and not saving them reverts the changes.""" project_widget = setup_project_widget project_widget.edit_project_button.click() @@ -225,9 +216,7 @@ def test_cancel_changes_to_model_project(setup_project_widget): def test_domains_tab(setup_project_widget): - """ - Tests that domain tab is visible. - """ + """Tests that domain tab is visible.""" project_widget = setup_project_widget project_widget.edit_project_button.click() project_widget.calculation_combobox.setCurrentText(Calculations.Domains) @@ -255,7 +244,6 @@ def test_project_tab_init(): @pytest.mark.parametrize("edit_mode", [True, False]) def test_project_tab_update_model(classlist, param_classlist, edit_mode): """Test that updating a ProjectTabEditWidget produces the desired models.""" - new_model = {"my_field": classlist, "parameters": param_classlist([])} tab = ProjectTabWidget(list(new_model), parent, edit_mode=edit_mode) diff --git a/tests/widgets/project/test_slider_view.py b/tests/widgets/project/test_slider_view.py index c57aa0d5..cb7270c3 100644 --- a/tests/widgets/project/test_slider_view.py +++ b/tests/widgets/project/test_slider_view.py @@ -53,7 +53,7 @@ def draft_project(): def test_no_sliders_creation(): - """Sliders should be created for fitted parameter only""" + """Slider view should show warning when there is no fitted parameter.""" mw = MainWindowView() draft = create_draft_project(ratapi.Project()) draft["parameters"][0].fit = False @@ -65,7 +65,7 @@ def test_no_sliders_creation(): def test_sliders_creation(draft_project): - """Sliders should be created for fitted parameter only""" + """Sliders should be created for fitted parameter only.""" mw = MainWindowView() slider_view = SliderViewWidget(draft_project, mw) @@ -81,7 +81,7 @@ def test_sliders_creation(draft_project): assert draft_project["parameters"][0].name not in slider_view._sliders -def test_slider_buttons(): +def test_accept_and_cancel_slider_buttons(): mw = MainWindowView() draft = create_draft_project(ratapi.Project()) mw.toggle_sliders = MagicMock() @@ -96,8 +96,8 @@ def test_slider_buttons(): mw.presenter.edit_project.assert_called_once_with(draft) mw.toggle_sliders.reset_mock() - reject_button = buttons[1] - reject_button.click() + cancel_button = buttons[1] + cancel_button.click() mw.toggle_sliders.assert_called_once() mw.plot_widget.update_plots.assert_called_once() diff --git a/tests/widgets/test_inputs.py b/tests/widgets/test_inputs.py index ad55db51..7ce861de 100644 --- a/tests/widgets/test_inputs.py +++ b/tests/widgets/test_inputs.py @@ -30,7 +30,6 @@ class MyEnum(StrEnum): ) def test_editor_type(field_info, expected_type, example_data): """Test that the editor type is as expected, and can be read and written.""" - widget = get_validated_input(field_info) assert isinstance(widget.editor, expected_type) widget.set_data(example_data) diff --git a/tests/widgets/test_widgets.py b/tests/widgets/test_widgets.py index 5571af06..d40fee39 100644 --- a/tests/widgets/test_widgets.py +++ b/tests/widgets/test_widgets.py @@ -12,9 +12,7 @@ def setup_startup_widget(): def test_startup_widget_initial_state(setup_startup_widget): - """ - Tests the initial state of the start up widget. - """ + """Tests the initial state of the startup widget.""" startup_widget, _ = setup_startup_widget assert startup_widget.new_project_button.isEnabled() assert startup_widget.import_project_button.isEnabled() @@ -27,9 +25,7 @@ def test_startup_widget_initial_state(setup_startup_widget): @pytest.mark.parametrize("button", ["new_project_button", "import_project_button", "import_r1_button"]) def test_show_project_dialog_called(setup_startup_widget, button): - """ - Tests the show_project_dialog method is called once. - """ + """Tests the show_project_dialog method is called once.""" startup_widget, parent = setup_startup_widget getattr(startup_widget, button).click() parent.show_project_dialog.assert_called_once() From 9924ee88578eca7e1e53f893204284aa002e605b Mon Sep 17 00:00:00 2001 From: Paul Sharp <44529197+DrPaulSharp@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:30:59 +0000 Subject: [PATCH 2/2] Apply fixes for ruff rule D401 --- packaging/build_exe.py | 2 +- rascal2/config.py | 4 ++-- rascal2/core/commands.py | 10 +++++----- rascal2/core/worker.py | 2 +- rascal2/dialogs/settings_dialog.py | 4 ++-- rascal2/dialogs/startup_dialog.py | 8 ++++---- rascal2/main.py | 2 +- rascal2/ui/model.py | 4 ++-- rascal2/ui/presenter.py | 4 ++-- rascal2/ui/view.py | 20 ++++++++++---------- rascal2/widgets/controls.py | 4 ++-- rascal2/widgets/inputs.py | 4 ++-- rascal2/widgets/plot.py | 8 ++++---- rascal2/widgets/project/project.py | 10 +++++----- rascal2/widgets/project/tables.py | 2 +- rascal2/widgets/terminal.py | 2 +- tests/core/test_runner.py | 2 +- tests/widgets/project/test_models.py | 6 +++--- tests/widgets/project/test_project.py | 6 +++--- tests/widgets/test_plot.py | 2 +- 20 files changed, 53 insertions(+), 53 deletions(-) diff --git a/packaging/build_exe.py b/packaging/build_exe.py index 85096e0d..9b29b298 100644 --- a/packaging/build_exe.py +++ b/packaging/build_exe.py @@ -57,7 +57,7 @@ def build_exe(): - """Builds the executable for the rascal-2 application.""" + """Build the executable for the rascal-2 application.""" os.environ["DELAY_MATLAB_START"] = "1" work_path = PACKAGING_PATH / "temp" dist_path = PACKAGING_PATH / "bundle" diff --git a/rascal2/config.py b/rascal2/config.py index c7f8648d..5ff8ee35 100644 --- a/rascal2/config.py +++ b/rascal2/config.py @@ -26,7 +26,7 @@ def handle_scaling(): - """Changes settings to handle UI scaling.""" + """Change settings to handle UI scaling.""" if platform.system() == "Windows": from ctypes import windll @@ -34,7 +34,7 @@ def handle_scaling(): def path_for(filename: str): - """Gets full path for the given image file. + """Get full path for the given image file. Parameters ---------- diff --git a/rascal2/core/commands.py b/rascal2/core/commands.py index 50ccf154..85e60eed 100644 --- a/rascal2/core/commands.py +++ b/rascal2/core/commands.py @@ -76,7 +76,7 @@ def redo(self): self.new_result = self.old_result def mergeWith(self, command): - """Merges consecutive Edit controls commands if the attributes are the same.""" + """Merge consecutive Edit controls commands if the attributes are the same.""" # We should think about if merging all Edit controls irrespective of # attribute is the way to go for UX if list(self.new_values.keys()) != list(command.new_values.keys()): @@ -92,7 +92,7 @@ def mergeWith(self, command): return True def id(self): - """Returns ID used for merging commands.""" + """Return ID used for merging commands.""" raise NotImplementedError @@ -155,7 +155,7 @@ def __init__( self.setText("Save calculation results") def get_parameter_values(self, problem: ratapi.rat_core.ProblemDefinition): - """Gets updated parameter values from problem definition. + """Get updated parameter values from problem definition. Parameters ---------- @@ -184,7 +184,7 @@ def get_parameter_values(self, problem: ratapi.rat_core.ProblemDefinition): return values def set_parameter_values(self, values: dict): - """Updates the parameter values of the project in the main window model. + """Update the parameter values of the project in the main window model. Parameters ---------- @@ -207,7 +207,7 @@ def update_calculation_outputs( results: ratapi.outputs.Results | ratapi.outputs.BayesResults, log: str, ): - """Updates the project, results and log in the main window model. + """Update the project, results and log in the main window model. Parameters ---------- diff --git a/rascal2/core/worker.py b/rascal2/core/worker.py index cb863a5e..23dd61a4 100644 --- a/rascal2/core/worker.py +++ b/rascal2/core/worker.py @@ -39,7 +39,7 @@ def stop(self): @classmethod def call(cls, func, args, on_success=None, on_failure=None, on_complete=None): - """Calls the given function from a new worker thread object. + """Call the given function from a new worker thread object. Parameters ---------- diff --git a/rascal2/dialogs/settings_dialog.py b/rascal2/dialogs/settings_dialog.py index 16f4a89b..0ed71d19 100644 --- a/rascal2/dialogs/settings_dialog.py +++ b/rascal2/dialogs/settings_dialog.py @@ -112,9 +112,9 @@ def __init__(self, parent: SettingsDialog, group: SettingsGroups): self.setLayout(tab_layout) def modify_setting(self, setting: str): - """A slot that updates the given setting in the dialog's copy of the Settings object. + """Update the given setting in the dialog's copy of the Settings object. - Connect this (via a lambda) to the "edited_signal" of the corresponding widget. + Connect this slot (via a lambda) to the "edited_signal" of the corresponding widget. Parameters ---------- diff --git a/rascal2/dialogs/startup_dialog.py b/rascal2/dialogs/startup_dialog.py index 51f503c5..41580676 100644 --- a/rascal2/dialogs/startup_dialog.py +++ b/rascal2/dialogs/startup_dialog.py @@ -66,7 +66,7 @@ def compose_layout(self): self.setLayout(main_layout) def create_loading_bar(self): - """Creates non-deterministic progress bar.""" + """Create a non-deterministic progress bar.""" self.loading_bar = QtWidgets.QProgressBar() self.loading_bar.setMinimum(0) self.loading_bar.setMaximum(0) @@ -279,7 +279,7 @@ def compose_layout(self): self.setLayout(main_layout) def create_load_tab(self): - """Creates the load project widget.""" + """Create the load project widget.""" layout = QtWidgets.QVBoxLayout() layout.setSpacing(20) @@ -327,7 +327,7 @@ def create_list_widget_tab(self, tab_name: str): return list_widget def create_example_tab(self): - """Creates the example widget.""" + """Create the example widget.""" self.example_list_widget = self.create_list_widget_tab("Examples") for name, desc in EXAMPLES.items(): @@ -340,7 +340,7 @@ def create_example_tab(self): item.setSizeHint(item_widget.sizeHint()) def create_recent_tab(self): - """Creates the recent project widget.""" + """Create the recent project widget.""" recent_projects = update_recent_projects() recent_projects = recent_projects[:6] self.recent_list_widget = self.create_list_widget_tab("Recent Projects") diff --git a/rascal2/main.py b/rascal2/main.py index 79f37ecc..a6b9155e 100644 --- a/rascal2/main.py +++ b/rascal2/main.py @@ -10,7 +10,7 @@ def ui_execute(): - """Creates main window and executes GUI event loop. + """Create main window and executes GUI event loop. Returns ------- diff --git a/rascal2/ui/model.py b/rascal2/ui/model.py index 1efd7521..e4295cd1 100644 --- a/rascal2/ui/model.py +++ b/rascal2/ui/model.py @@ -35,7 +35,7 @@ def __init__(self): self.save_path = "" def create_project(self, name: str, save_path: str): - """Creates a new RAT project and controls object. + """Create a new RAT project and controls object. Parameters ---------- @@ -70,7 +70,7 @@ def update_results(self, results: ratapi.outputs.Results | ratapi.outputs.BayesR self.results_updated.emit() def update_project(self, new_values: dict) -> None: - """Replaces the project with a new project. + """Replace the project with a new project. Parameters ---------- diff --git a/rascal2/ui/presenter.py b/rascal2/ui/presenter.py index cee9ade0..6b2d0c4b 100644 --- a/rascal2/ui/presenter.py +++ b/rascal2/ui/presenter.py @@ -31,7 +31,7 @@ def __init__(self, view): self.worker = None def create_project(self, name: str, save_path: str): - """Creates a new RAT project and controls object then initialise UI. + """Create a new RAT project and controls object then initialise UI. Parameters ---------- @@ -167,7 +167,7 @@ def export_fits(self): self.view.logging.error(f"Failed to save fits to {save_file}.\n", exc_info=err) def interrupt_terminal(self): - """Sends an interrupt signal to the RAT runner.""" + """Send an interrupt signal to the RAT runner.""" self.runner.interrupt() def quick_run(self, project=None): diff --git a/rascal2/ui/view.py b/rascal2/ui/view.py index 5f9a5726..c4c1190f 100644 --- a/rascal2/ui/view.py +++ b/rascal2/ui/view.py @@ -64,7 +64,7 @@ def closeEvent(self, event): event.ignore() def show_project_dialog(self, dialog: StartupDialog): - """Shows a startup dialog of a given type. + """Show a startup dialog of a given type. Parameters ---------- @@ -79,7 +79,7 @@ def show_project_dialog(self, dialog: StartupDialog): project_dlg.show() def show_settings_dialog(self, tab_name=""): - """Shows the settings dialog and makes tab with given name active. + """Show the settings dialog and makes tab with given name active. Parameters ---------- @@ -95,7 +95,7 @@ def show_settings_dialog(self, tab_name=""): settings_dlg.show() def create_actions(self): - """Creates the menu and toolbar actions.""" + """Create the menu and toolbar actions.""" self.new_project_action = QtGui.QAction("&New Project", self) self.new_project_action.setStatusTip("Create a new project") self.new_project_action.setIcon(QtGui.QIcon(path_for("new-project.png"))) @@ -251,7 +251,7 @@ def create_menus(self): help_menu.addAction(self.open_help_action) def toggle_sliders(self): - """Toggles sliders for the fitted parameters in project class view.""" + """Toggle sliders for the fitted parameters in project class view.""" show_text = self.toggle_slider_action.property("show_text") if self.toggle_slider_action.text() == show_text: hide_text = self.toggle_slider_action.property("hide_text") @@ -262,7 +262,7 @@ def toggle_sliders(self): self.project_widget.show_project_view() def open_about_info(self): - """Opens about dialog containing information about RASCAL.""" + """Open about dialog containing information about RASCAL.""" self.about_dialog.update_rascal_info(self) self.about_dialog.show() @@ -272,12 +272,12 @@ def show_undo_view(self): self.undo_view.raise_() def open_docs(self): - """Opens the documentation.""" + """Open the documentation.""" url = QtCore.QUrl("https://rascalsoftware.github.io/RAT-Docs/dev/index.html") QtGui.QDesktopServices.openUrl(url) def create_toolbar(self): - """Creates the toolbar.""" + """Create the toolbar.""" self.toolbar = self.addToolBar("ToolBar") self.toolbar.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.PreventContextMenu) self.toolbar.setMovable(False) @@ -291,12 +291,12 @@ def create_toolbar(self): self.toolbar.addAction(self.open_help_action) def create_status_bar(self): - """Creates the status bar.""" + """Create the status bar.""" sb = QtWidgets.QStatusBar() self.setStatusBar(sb) def setup_mdi(self): - """Creates the multi-document interface.""" + """Create the multi-document interface.""" # if windows are already created, don't set them up again, # just refresh the widget data if len(self.mdi.subWindowList()) == 4: @@ -322,7 +322,7 @@ def setup_mdi(self): self.setCentralWidget(self.mdi) def setup_mdi_widgets(self): - """Performs initialization of MDI widgets that rely on the Project being defined.""" + """Perform initialization of MDI widgets that rely on the Project being defined.""" self.controls_widget.setup_controls() self.project_widget.show_project_view() self.plot_widget.clear() diff --git a/rascal2/widgets/controls.py b/rascal2/widgets/controls.py index c515c9ce..7fb4ffef 100644 --- a/rascal2/widgets/controls.py +++ b/rascal2/widgets/controls.py @@ -83,7 +83,7 @@ def __init__(self, parent): self.setLayout(widget_layout) def setup_controls(self): - """Setup the parts of the widget which depend on the Controls object.""" + """Set up the parts of the widget which depend on the Controls object.""" # clear any chi-squared from previous controls self.chi_squared.setText("") @@ -104,7 +104,7 @@ def setup_controls(self): self.procedure_dropdown.setCurrentIndex(init_procedure) def update_ui(self): - """Updates UI without firing signals to avoid recursion.""" + """Update UI without firing signals to avoid recursion.""" init_procedure = [p.value for p in Procedures].index(self.presenter.model.controls.procedure) self.procedure_dropdown.blockSignals(True) self.procedure_dropdown.setCurrentIndex(init_procedure) diff --git a/rascal2/widgets/inputs.py b/rascal2/widgets/inputs.py index c326071f..4058cf1a 100644 --- a/rascal2/widgets/inputs.py +++ b/rascal2/widgets/inputs.py @@ -255,7 +255,7 @@ def valueFromText(self, text: str) -> float: return float(text) def setValue(self, value: float): - """Hook into setValue that sets the decimals when the value is manually set. + """Hook into setValue to set the decimals when the value is manually set. Parameters ---------- @@ -629,7 +629,7 @@ def default_text(self, text): self.setText(text) def show_progress(self): - """Shows busy indicator.""" + """Show busy indicator.""" self.setEnabled(False) self.setText(f"{self.progress_text} ...") diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index f4335120..7c4aa7a0 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -411,7 +411,7 @@ def timerEvent(self, event): self.resize_timer = 0 def plot(self, project: ratapi.Project, results: ratapi.outputs.Results | ratapi.outputs.BayesResults): - """Plots the reflectivity and SLD profiles. + """Plot the reflectivity and SLD profiles. Parameters ---------- @@ -438,7 +438,7 @@ def plot(self, project: ratapi.Project, results: ratapi.outputs.Results | ratapi self.plot_event(data) def plot_event(self, data: ratapi.events.PlotEventData | None = None): - """Updates the ref and SLD plots from a provided or cached plot event. + """Update the ref and SLD plots from a provided or cached plot event. Parameters ---------- @@ -472,7 +472,7 @@ def plot_event(self, data: ratapi.events.PlotEventData | None = None): self.canvas.draw() def plot_with_blit(self, data: ratapi.events.PlotEventData | None = None): - """Updates the ref and SLD plots with blitting. + """Update the ref and SLD plots with blitting. Parameters ---------- @@ -538,7 +538,7 @@ def plot(self, project, results: ratapi.outputs.BayesResults): self.draw_plot() def draw_plot(self): - """Plots the shaded reflectivity and SLD profiles.""" + """Plot the shaded reflectivity and SLD profiles.""" self.clear() ratapi.plotting.plot_ref_sld( diff --git a/rascal2/widgets/project/project.py b/rascal2/widgets/project/project.py index e9ceda61..56839857 100644 --- a/rascal2/widgets/project/project.py +++ b/rascal2/widgets/project/project.py @@ -78,7 +78,7 @@ def __init__(self, parent): self.setLayout(layout) def create_project_view(self) -> QtWidgets.QWidget: - """Creates the project (non-edit) view.""" + """Create the project (non-edit) view.""" project_widget = QtWidgets.QWidget() main_layout = QtWidgets.QVBoxLayout() main_layout.setSpacing(20) @@ -146,7 +146,7 @@ def create_project_view(self) -> QtWidgets.QWidget: return project_widget def create_edit_view(self) -> QtWidgets.QWidget: - """Creates the project edit view.""" + """Create the project edit view.""" edit_project_widget = QtWidgets.QWidget() main_layout = QtWidgets.QVBoxLayout() main_layout.setSpacing(20) @@ -264,7 +264,7 @@ def update_slider_view(self): widget.initialize() def update_project_view(self, update_tab_index=None) -> None: - """Updates the project view.""" + """Update the project view.""" if update_tab_index is None: update_tab_index = self.stacked_widget.currentIndex() tab_to_update = self.view_tabs if update_tab_index == 0 else self.edit_tabs @@ -302,7 +302,7 @@ def update_project_view(self, update_tab_index=None) -> None: ) def update_draft_project(self, new_values: dict) -> None: - """Updates the draft project. + """Update the draft project. Parameters ---------- @@ -313,7 +313,7 @@ def update_draft_project(self, new_values: dict) -> None: self.draft_project.update(new_values) def handle_tabs(self) -> None: - """Displays or hides tabs as relevant.""" + """Display or hide tabs as relevant.""" # the domains tab should only be visible if calculating domains domain_tab_index = list(self.view_tabs).index("Domains") is_domains = self.calculation_combobox.currentText() == Calculations.Domains diff --git a/rascal2/widgets/project/tables.py b/rascal2/widgets/project/tables.py index c2e1d61f..74d85364 100644 --- a/rascal2/widgets/project/tables.py +++ b/rascal2/widgets/project/tables.py @@ -42,7 +42,7 @@ def __init__(self, classlist: ratapi.ClassList, parent: QtWidgets.QWidget): self.col_offset = 1 def setup_classlist(self, classlist: ratapi.ClassList): - """Setup the ClassList, type and headers for the model.""" + """Set up the ClassList, type and headers for the model.""" self.classlist = classlist self.item_type = classlist._class_handle if not issubclass(self.item_type, pydantic.BaseModel): diff --git a/rascal2/widgets/terminal.py b/rascal2/widgets/terminal.py index ae37e373..dc8843c3 100644 --- a/rascal2/widgets/terminal.py +++ b/rascal2/widgets/terminal.py @@ -104,4 +104,4 @@ def update_progress(self, event): self.progress_bar.setValue(int(event.percent * 100)) def flush(self): - """Added to make TerminalWidget an IO stream.""" + """Make TerminalWidget an IO stream.""" diff --git a/tests/core/test_runner.py b/tests/core/test_runner.py index be225ba4..339f43d3 100644 --- a/tests/core/test_runner.py +++ b/tests/core/test_runner.py @@ -142,7 +142,7 @@ def test_run_error(): """If RATMain produces an error, it should be added to the queue.""" def erroring_ratmain(*args): - """A RATMain mock that raises an error.""" + """RATMain mock that raises an error.""" raise ValueError("RAT Main Error!") queue = Queue() diff --git a/tests/widgets/project/test_models.py b/tests/widgets/project/test_models.py index 2b2925da..828ae058 100644 --- a/tests/widgets/project/test_models.py +++ b/tests/widgets/project/test_models.py @@ -33,7 +33,7 @@ def __init__(self): class DataModel(pydantic.BaseModel, validate_assignment=True): - """A test Pydantic model.""" + """Test Pydantic model.""" name: str = "Test Model" value: int = 15 @@ -41,7 +41,7 @@ class DataModel(pydantic.BaseModel, validate_assignment=True): @pytest.fixture def classlist(): - """A test ClassList.""" + """Test ClassList.""" return ratapi.ClassList( [ DataModel(name="A", value=1), @@ -53,7 +53,7 @@ def classlist(): @pytest.fixture def table_model(classlist): - """A test ClassListTableModel.""" + """Test ClassListTableModel.""" return ClassListTableModel(classlist, parent) diff --git a/tests/widgets/project/test_project.py b/tests/widgets/project/test_project.py index b38d5496..645b2bbb 100644 --- a/tests/widgets/project/test_project.py +++ b/tests/widgets/project/test_project.py @@ -41,7 +41,7 @@ def __init__(self): class DataModel(pydantic.BaseModel, validate_assignment=True): - """A test Pydantic model.""" + """Test Pydantic model.""" name: str = "Test Model" value: int = 15 @@ -52,13 +52,13 @@ class DataModel(pydantic.BaseModel, validate_assignment=True): @pytest.fixture def classlist(): - """A test ClassList.""" + """Test ClassList.""" return ratapi.ClassList([DataModel(name="A", value=1), DataModel(name="B", value=6), DataModel(name="C", value=18)]) @pytest.fixture def table_model(classlist): - """A test ClassListTableModel.""" + """Test ClassListTableModel.""" return ClassListTableModel(classlist, parent) diff --git a/tests/widgets/test_plot.py b/tests/widgets/test_plot.py index 6a663f00..ef52ca7a 100644 --- a/tests/widgets/test_plot.py +++ b/tests/widgets/test_plot.py @@ -51,7 +51,7 @@ def shaded_plot_widget(): @pytest.fixture def mock_bayes_results(): - """A mock of Bayes results with given fit parameter names.""" + """Mock of Bayes results with given fit parameter names.""" def _mock_bayes(fitnames): bayes_results = MagicMock(spec=ratapi.outputs.BayesResults)