From a11657c1455bffc03e865d1c410e5406d03c11c8 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:54:01 +0100 Subject: [PATCH 1/3] Allow creating new project from zip archive --- novelwriter/core/coretools.py | 32 +++++++++++++++++++++----------- novelwriter/shared.py | 18 ++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py index 0eb4197b..b493d1b0 100644 --- a/novelwriter/core/coretools.py +++ b/novelwriter/core/coretools.py @@ -32,6 +32,7 @@ import logging from typing import Iterable from pathlib import Path from functools import partial +from zipfile import ZipFile, is_zipfile from PyQt5.QtCore import QCoreApplication @@ -459,7 +460,7 @@ class ProjectBuilder: """ source = data.get("template") if not (isinstance(source, Path) and source.is_file() - and source.name == nwFiles.PROJ_FILE): + and (source.name == nwFiles.PROJ_FILE or is_zipfile(source))): logger.error("Could not access source project: %s", source) return False @@ -478,10 +479,22 @@ class ProjectBuilder: dstCont = dstPath / "content" dstPath.mkdir(exist_ok=True) dstCont.mkdir(exist_ok=True) - shutil.copy2(srcPath / nwFiles.PROJ_FILE, dstPath) - for contFile in srcCont.iterdir(): - if contFile.is_file() and contFile.suffix == ".nwd" and isHandle(contFile.stem): - shutil.copy2(contFile, dstCont) + try: + if is_zipfile(source): + with ZipFile(source) as zipObj: + for member in zipObj.namelist(): + if member == nwFiles.PROJ_FILE: + zipObj.extract(member, dstPath) + elif member.startswith("content") and member.endswith(".nwd"): + zipObj.extract(member, dstPath) + else: + shutil.copy2(srcPath / nwFiles.PROJ_FILE, dstPath) + for item in srcCont.iterdir(): + if item.is_file() and item.suffix == ".nwd" and isHandle(item.stem): + shutil.copy2(item, dstCont) + except Exception as exc: + SHARED.error(self.tr("Could not copy project files."), exc=exc) + return False # Open the copied project and update settings project = NWProject() @@ -505,14 +518,11 @@ class ProjectBuilder: """Make a copy of the sample project by extracting the sample.zip file to the new path. """ - pkgSample = CONFIG.assetPath("sample.zip") - if pkgSample.is_file(): + if (sample := CONFIG.assetPath("sample.zip")).is_file(): try: - shutil.unpack_archive(pkgSample, path) + shutil.unpack_archive(sample, path) except Exception as exc: - SHARED.error(self.tr( - "Failed to create a new example project." - ), exc=exc) + SHARED.error(self.tr("Failed to create a new example project."), exc=exc) return False else: SHARED.error(self.tr( diff --git a/novelwriter/shared.py b/novelwriter/shared.py index c2c342f8..28d1cf74 100644 --- a/novelwriter/shared.py +++ b/novelwriter/shared.py @@ -221,16 +221,18 @@ class SharedData(QObject): def getProjectPath(self, parent: QWidget, path: str | Path | None = None, allowZip: bool = False) -> Path | None: """Open the file dialog and select a novelWriter project file.""" - ext = [ - self.tr("novelWriter Project File ({0})").format(nwFiles.PROJ_FILE), - self.tr("All files ({0})").format("*"), - ] if allowZip: - ext.insert(1, self.tr("Zip Archives ({0})").format("*.zip")) - projFile, _ = QFileDialog.getOpenFileName( - parent, self.tr("Open Project"), str(path or ""), filter=";;".join(ext) + label = self.tr("novelWriter Project File or Zip") + ext = f"{nwFiles.PROJ_FILE} *.zip" + else: + label = self.tr("novelWriter Project File") + ext = nwFiles.PROJ_FILE + selected, _ = QFileDialog.getOpenFileName( + parent, self.tr("Open Project"), str(path or ""), filter=";;".join( + [f"{label} ({ext})", "{0} (*)".format(self.tr("All Files"))] + ) ) - return Path(projFile) if projFile else None + return Path(selected) if selected else None def findTopLevelWidget(self, kind: type[NWWidget]) -> NWWidget | None: """Find a top level widget.""" From d5064a8333d07dfeed607c27ab208727679c7cb1 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 3 Feb 2024 15:34:08 +0100 Subject: [PATCH 2/3] Add test for new project creation path --- novelwriter/core/coretools.py | 4 +- novelwriter/shared.py | 9 +-- tests/test_core/test_core_coretools.py | 91 +++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 10 deletions(-) diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py index b493d1b0..bba2ca64 100644 --- a/novelwriter/core/coretools.py +++ b/novelwriter/core/coretools.py @@ -477,9 +477,9 @@ class ProjectBuilder: dstPath = path.resolve() srcCont = srcPath / "content" dstCont = dstPath / "content" - dstPath.mkdir(exist_ok=True) - dstCont.mkdir(exist_ok=True) try: + dstPath.mkdir(exist_ok=True) + dstCont.mkdir(exist_ok=True) if is_zipfile(source): with ZipFile(source) as zipObj: for member in zipObj.namelist(): diff --git a/novelwriter/shared.py b/novelwriter/shared.py index 28d1cf74..1c003687 100644 --- a/novelwriter/shared.py +++ b/novelwriter/shared.py @@ -221,12 +221,9 @@ class SharedData(QObject): def getProjectPath(self, parent: QWidget, path: str | Path | None = None, allowZip: bool = False) -> Path | None: """Open the file dialog and select a novelWriter project file.""" - if allowZip: - label = self.tr("novelWriter Project File or Zip") - ext = f"{nwFiles.PROJ_FILE} *.zip" - else: - label = self.tr("novelWriter Project File") - ext = nwFiles.PROJ_FILE + label = (self.tr("novelWriter Project File or Zip") + if allowZip else self.tr("novelWriter Project File")) + ext = f"{nwFiles.PROJ_FILE} *.zip" if allowZip else nwFiles.PROJ_FILE selected, _ = QFileDialog.getOpenFileName( parent, self.tr("Open Project"), str(path or ""), filter=";;".join( [f"{label} ({ext})", "{0} (*)".format(self.tr("All Files"))] diff --git a/tests/test_core/test_core_coretools.py b/tests/test_core/test_core_coretools.py index d8dec316..3c03e048 100644 --- a/tests/test_core/test_core_coretools.py +++ b/tests/test_core/test_core_coretools.py @@ -22,6 +22,7 @@ from __future__ import annotations import uuid import pytest +import shutil from shutil import copyfile from pathlib import Path @@ -501,7 +502,7 @@ def testCoreTools_ProjectBuilderB(monkeypatch, fncPath, tstPaths, mockRnd): @pytest.mark.core -def testCoreTools_ProjectBuilderTemplate(monkeypatch, mockGUI, prjLipsum, fncPath): +def testCoreTools_ProjectBuilderCopyPlain(monkeypatch, caplog, mockGUI, prjLipsum, fncPath): """Create a new project copied from existing project.""" srcPath = prjLipsum / nwFiles.PROJ_FILE dstPath = fncPath / "lipsum" @@ -524,6 +525,14 @@ def testCoreTools_ProjectBuilderTemplate(monkeypatch, mockGUI, prjLipsum, fncPat # Cannot copy to existing folder assert builder.buildProject({"path": fncPath, "template": srcPath}) is False + # Valid data, but copy fails + caplog.clear() + with monkeypatch.context() as mp: + mp.setattr("pathlib.Path.mkdir", lambda *a, **k: causeOSError) + assert builder.buildProject(data) is False + assert "Could not copy project files." in caplog.text + dstPath.unlink(missing_ok=True) # The failed mkdir leaves an empty file + # Copy project properly assert builder.buildProject(data) is True @@ -556,7 +565,85 @@ def testCoreTools_ProjectBuilderTemplate(monkeypatch, mockGUI, prjLipsum, fncPat assert dstProject.data.autoCount < 5 assert dstProject.data.editTime < 10 -# END Test testCoreTools_ProjectBuilderTemplate +# END Test testCoreTools_ProjectBuilderCopyPlain + + +@pytest.mark.core +def testCoreTools_ProjectBuilderCopyZipped(monkeypatch, caplog, mockGUI, fncPath, mockRnd): + """Create a new project copied from existing zipped project.""" + + # Create a project + origPath = fncPath / "original" + srcProject = NWProject() + buildTestProject(srcProject, origPath) + + # Zip it + shutil.make_archive(str(fncPath / "original"), "zip", origPath) + + # Make fake zip file + fakeZip = fncPath / "broken.zip" + fakeZip.write_bytes(b"stuff") + + # Set up the builder + srcPath = fncPath / "original.zip" + dstPath = fncPath / "copy" + data = { + "name": "Test Project", + "author": "Jane Doe", + "language": "en_US", + "path": dstPath, + "template": srcPath, + } + + builder = ProjectBuilder() + + # No path set + assert builder.buildProject({"template": srcPath}) is False + + # No project at path + assert builder.buildProject({"path": fncPath, "template": fncPath}) is False + + # Cannot copy to existing folder + assert builder.buildProject({"path": fncPath, "template": srcPath}) is False + + # Cannot copy to existing folder + caplog.clear() + with monkeypatch.context() as mp: + mp.setattr("novelwriter.core.coretools.is_zipfile", lambda *a: True) + assert builder.buildProject({"path": dstPath, "template": fakeZip}) is False + assert "Could not copy project files." in caplog.text + shutil.rmtree(dstPath, ignore_errors=True) + + # Copy project properly + assert builder.buildProject(data) is True + + # Check Copy + # ========== + + dstProject = NWProject() + dstProject.openProject(dstPath) + + # UUID should be different + assert srcProject.data.uuid != dstProject.data.uuid + + # Name should be different + assert srcProject.data.name == "New Project" + assert dstProject.data.name == "Test Project" + + # Author should be different + assert srcProject.data.author == "Jane Doe" + assert dstProject.data.author == "Jane Doe" + + # Language should be different + assert srcProject.data.language is None + assert dstProject.data.language == "en_US" + + # Counts should be more or less zeroed + assert dstProject.data.saveCount < 5 + assert dstProject.data.autoCount < 5 + assert dstProject.data.editTime < 10 + +# END Test testCoreTools_ProjectBuilderCopyZipped @pytest.mark.core From 4d016c3b755d202804b4d5b20727fc6f339ad72a Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 3 Feb 2024 15:34:33 +0100 Subject: [PATCH 3/3] Clean up top level window access and add coverage to shared data class --- tests/test_dialogs/test_dlg_about.py | 7 +++---- tests/test_dialogs/test_dlg_preferences.py | 6 ++---- tests/test_dialogs/test_dlg_projectsettings.py | 10 ++++++---- tests/test_dialogs/test_dlg_wordlist.py | 6 +++--- tests/test_gui/test_gui_guimain.py | 10 +++++----- tests/test_tools/test_tools_dictionaries.py | 5 ++--- tests/test_tools/test_tools_lipsum.py | 5 +++-- tests/test_tools/test_tools_manuscript.py | 10 +++++----- tests/test_tools/test_tools_noveldetails.py | 6 ++---- tests/test_tools/test_tools_writingstats.py | 9 ++++----- tests/tools.py | 10 +--------- 11 files changed, 36 insertions(+), 48 deletions(-) diff --git a/tests/test_dialogs/test_dlg_about.py b/tests/test_dialogs/test_dlg_about.py index aaf94942..ab60cfd7 100644 --- a/tests/test_dialogs/test_dlg_about.py +++ b/tests/test_dialogs/test_dlg_about.py @@ -24,10 +24,9 @@ import pytest from pathlib import Path -from tools import getGuiItem - from PyQt5.QtWidgets import QAction, QMessageBox +from novelwriter import SHARED from novelwriter.dialogs.about import GuiAbout @@ -37,8 +36,8 @@ def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI): # NW About nwGUI.showAboutNWDialog(showNotes=True) - qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000) - msgAbout = getGuiItem("GuiAbout") + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiAbout) is not None, timeout=1000) + msgAbout = SHARED.findTopLevelWidget(GuiAbout) assert isinstance(msgAbout, GuiAbout) assert msgAbout.pageAbout.document().characterCount() > 100 diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index 408865c7..95d2eb59 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -22,8 +22,6 @@ from __future__ import annotations import pytest -from tools import getGuiItem - from PyQt5.QtGui import QFontDatabase, QKeyEvent from PyQt5.QtCore import QEvent, Qt from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog @@ -44,8 +42,8 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths): # Load GUI with standard values nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000) - prefs = getGuiItem("GuiPreferences") + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiPreferences) is not None, timeout=1000) + prefs = SHARED.findTopLevelWidget(GuiPreferences) assert isinstance(prefs, GuiPreferences) prefs.show() diff --git a/tests/test_dialogs/test_dlg_projectsettings.py b/tests/test_dialogs/test_dlg_projectsettings.py index 5b4d5499..74cfd24a 100644 --- a/tests/test_dialogs/test_dlg_projectsettings.py +++ b/tests/test_dialogs/test_dlg_projectsettings.py @@ -22,7 +22,7 @@ from __future__ import annotations import pytest -from tools import C, getGuiItem, buildTestProject +from tools import C, buildTestProject from PyQt5.QtGui import QColor from PyQt5.QtCore import Qt @@ -47,7 +47,7 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI): # Check that we cannot open when there is no project nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) - assert getGuiItem("GuiProjectSettings") is None + assert SHARED.findTopLevelWidget(GuiProjectSettings) is None # Pretend we have a project SHARED.project._valid = True @@ -55,9 +55,11 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI): # Get the dialog object nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None, timeout=1000) + qtbot.waitUntil( + lambda: SHARED.findTopLevelWidget(GuiProjectSettings) is not None, timeout=1000 + ) - projSettings = getGuiItem("GuiProjectSettings") + projSettings = SHARED.findTopLevelWidget(GuiProjectSettings) assert isinstance(projSettings, GuiProjectSettings) projSettings.show() qtbot.addWidget(projSettings) diff --git a/tests/test_dialogs/test_dlg_wordlist.py b/tests/test_dialogs/test_dlg_wordlist.py index 6af38902..e1b7d0ec 100644 --- a/tests/test_dialogs/test_dlg_wordlist.py +++ b/tests/test_dialogs/test_dlg_wordlist.py @@ -25,7 +25,7 @@ import pytest from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QDialog, QAction -from tools import buildTestProject, getGuiItem +from tools import buildTestProject from novelwriter import SHARED from novelwriter.core.spellcheck import UserDictionary @@ -47,9 +47,9 @@ def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, projPath): # Load the dialog nwGUI.mainMenu.aEditWordList.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiWordList") is not None, timeout=1000) + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiWordList) is not None, timeout=1000) - wList = getGuiItem("GuiWordList") + wList = SHARED.findTopLevelWidget(GuiWordList) assert isinstance(wList, GuiWordList) wList.show() diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py index 5c15ed4a..6bfb7f0d 100644 --- a/tests/test_gui/test_gui_guimain.py +++ b/tests/test_gui/test_gui_guimain.py @@ -26,7 +26,7 @@ import pytest from shutil import copyfile from tools import ( - C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE, getGuiItem + C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE ) from PyQt5.QtGui import QPalette @@ -93,16 +93,16 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath): nwGUI.closeProject() # Check that release notes opened - qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000) - msgAbout = getGuiItem("GuiAbout") + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiAbout) is not None, timeout=1000) + msgAbout = SHARED.findTopLevelWidget(GuiAbout) assert isinstance(msgAbout, GuiAbout) assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes msgAbout.accept() # Check that project open dialog launches nwGUI.postLaunchTasks(None) - qtbot.waitUntil(lambda: getGuiItem("GuiWelcome") is not None, timeout=1000) - assert isinstance(welcome := getGuiItem("GuiWelcome"), GuiWelcome) + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiWelcome) is not None, timeout=1000) + assert isinstance(welcome := SHARED.findTopLevelWidget(GuiWelcome), GuiWelcome) welcome.show() welcome.close() diff --git a/tests/test_tools/test_tools_dictionaries.py b/tests/test_tools/test_tools_dictionaries.py index 1e2b0f4e..9f11d51c 100644 --- a/tests/test_tools/test_tools_dictionaries.py +++ b/tests/test_tools/test_tools_dictionaries.py @@ -25,7 +25,6 @@ import enchant from zipfile import ZipFile -from tools import getGuiItem from mocked import causeException from PyQt5.QtGui import QDesktopServices @@ -48,9 +47,9 @@ def testToolDictionaries_Main(qtbot, monkeypatch, nwGUI, fncPath): # Open the tool nwGUI.showDictionariesDialog() - qtbot.waitUntil(lambda: getGuiItem("GuiDictionaries") is not None, timeout=1000) + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiDictionaries) is not None, timeout=1000) - nwDicts = getGuiItem("GuiDictionaries") + nwDicts = SHARED.findTopLevelWidget(GuiDictionaries) assert isinstance(nwDicts, GuiDictionaries) assert nwDicts.isVisible() assert nwDicts.inPath.text() == str(fncPath) diff --git a/tests/test_tools/test_tools_lipsum.py b/tests/test_tools/test_tools_lipsum.py index 2930ed9f..cc4f8b18 100644 --- a/tests/test_tools/test_tools_lipsum.py +++ b/tests/test_tools/test_tools_lipsum.py @@ -22,10 +22,11 @@ from __future__ import annotations import pytest -from tools import C, getGuiItem, buildTestProject +from tools import C, buildTestProject from PyQt5.QtWidgets import QAction +from novelwriter import SHARED from novelwriter.tools.lipsum import GuiLipsum @@ -34,7 +35,7 @@ def testToolLipsum_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd): """Test the Lorem Ipsum tool.""" # Check that we cannot open when there is no project nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger) - assert getGuiItem("GuiLipsum") is None + assert SHARED.findTopLevelWidget(GuiLipsum) is None buildTestProject(nwGUI, projPath) nwLipsum = GuiLipsum(nwGUI) diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index 0978ee05..e1615737 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -26,7 +26,7 @@ import pytest from pathlib import Path from pytestqt.qtbot import QtBot -from tools import C, buildTestProject, getGuiItem +from tools import C, buildTestProject from mocked import causeOSError from PyQt5.QtCore import Qt, pyqtSlot @@ -50,8 +50,8 @@ def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pat allText = "New Novel\nBy Jane Doe\nA Chapter\n\t\tHi\n* * *" nwGUI.mainMenu.aBuildManuscript.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiManuscript") is not None, timeout=1000) - manus = getGuiItem("GuiManuscript") + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiManuscript) is not None, timeout=1000) + manus = SHARED.findTopLevelWidget(GuiManuscript) assert isinstance(manus, GuiManuscript) manus.show() assert manus.docPreview.toPlainText().strip() == "" @@ -104,7 +104,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): # Create a new build manus.tbAdd.click() - bSettings = getGuiItem("GuiBuildSettings") + bSettings = SHARED.findTopLevelWidget(GuiBuildSettings) assert isinstance(bSettings, GuiBuildSettings) bSettings.editBuildName.setText("Test Build") build = None @@ -127,7 +127,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): manus.buildList.setCurrentRow(0) manus.tbEdit.click() - bSettings = getGuiItem("GuiBuildSettings") + bSettings = SHARED.findTopLevelWidget(GuiBuildSettings) assert isinstance(bSettings, GuiBuildSettings) build = None diff --git a/tests/test_tools/test_tools_noveldetails.py b/tests/test_tools/test_tools_noveldetails.py index c8925e53..b8b49a2c 100644 --- a/tests/test_tools/test_tools_noveldetails.py +++ b/tests/test_tools/test_tools_noveldetails.py @@ -22,8 +22,6 @@ from __future__ import annotations import pytest -from tools import getGuiItem - from PyQt5.QtWidgets import QAction from novelwriter import SHARED @@ -49,8 +47,8 @@ def testToolNovelDetails_Main(qtbot, nwGUI, prjLipsum, ipsumText): # Create the dialog nwGUI.mainMenu.aNovelDetails.activate(QAction.ActionEvent.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiNovelDetails") is not None, timeout=1000) - details = getGuiItem("GuiNovelDetails") + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiNovelDetails) is not None, timeout=1000) + details = SHARED.findTopLevelWidget(GuiNovelDetails) assert isinstance(details, GuiNovelDetails) # Overview Page diff --git a/tests/test_tools/test_tools_writingstats.py b/tests/test_tools/test_tools_writingstats.py index 1f8afabc..0524174a 100644 --- a/tests/test_tools/test_tools_writingstats.py +++ b/tests/test_tools/test_tools_writingstats.py @@ -25,7 +25,7 @@ import pytest from pathlib import Path -from tools import getGuiItem, buildTestProject +from tools import buildTestProject from mocked import causeOSError from PyQt5.QtCore import Qt @@ -38,8 +38,7 @@ from novelwriter.tools.writingstats import GuiWritingStats @pytest.mark.gui def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): - """Test the full writing stats tool. - """ + """Test the full writing stats tool.""" # Create a project to work on buildTestProject(nwGUI, projPath) project = SHARED.project @@ -50,9 +49,9 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): # Open the Writing Stats dialog nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiWritingStats") is not None, timeout=1000) + qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiWritingStats) is not None, timeout=1000) - sessLog = getGuiItem("GuiWritingStats") + sessLog = SHARED.findTopLevelWidget(GuiWritingStats) assert isinstance(sessLog, GuiWritingStats) # Test Loading diff --git a/tests/tools.py b/tests/tools.py index 7a00b4b6..6346432b 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -25,7 +25,7 @@ import shutil from pathlib import Path from datetime import datetime -from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget, qApp +from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget XML_IGNORE = ("