Add creating new project from zipped existing project (#1684)

This commit is contained in:
Veronica Berglyd Olsen
2024-02-03 15:40:06 +01:00
committed by GitHub
14 changed files with 156 additions and 72 deletions
+23 -13
View File
@@ -32,6 +32,7 @@ import logging
from typing import Iterable from typing import Iterable
from pathlib import Path from pathlib import Path
from functools import partial from functools import partial
from zipfile import ZipFile, is_zipfile
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
@@ -459,7 +460,7 @@ class ProjectBuilder:
""" """
source = data.get("template") source = data.get("template")
if not (isinstance(source, Path) and source.is_file() 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) logger.error("Could not access source project: %s", source)
return False return False
@@ -476,12 +477,24 @@ class ProjectBuilder:
dstPath = path.resolve() dstPath = path.resolve()
srcCont = srcPath / "content" srcCont = srcPath / "content"
dstCont = dstPath / "content" dstCont = dstPath / "content"
dstPath.mkdir(exist_ok=True) try:
dstCont.mkdir(exist_ok=True) dstPath.mkdir(exist_ok=True)
shutil.copy2(srcPath / nwFiles.PROJ_FILE, dstPath) dstCont.mkdir(exist_ok=True)
for contFile in srcCont.iterdir(): if is_zipfile(source):
if contFile.is_file() and contFile.suffix == ".nwd" and isHandle(contFile.stem): with ZipFile(source) as zipObj:
shutil.copy2(contFile, dstCont) 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 # Open the copied project and update settings
project = NWProject() project = NWProject()
@@ -505,14 +518,11 @@ class ProjectBuilder:
"""Make a copy of the sample project by extracting the """Make a copy of the sample project by extracting the
sample.zip file to the new path. sample.zip file to the new path.
""" """
pkgSample = CONFIG.assetPath("sample.zip") if (sample := CONFIG.assetPath("sample.zip")).is_file():
if pkgSample.is_file():
try: try:
shutil.unpack_archive(pkgSample, path) shutil.unpack_archive(sample, path)
except Exception as exc: except Exception as exc:
SHARED.error(self.tr( SHARED.error(self.tr("Failed to create a new example project."), exc=exc)
"Failed to create a new example project."
), exc=exc)
return False return False
else: else:
SHARED.error(self.tr( SHARED.error(self.tr(
+8 -9
View File
@@ -221,16 +221,15 @@ class SharedData(QObject):
def getProjectPath(self, parent: QWidget, path: str | Path | None = None, def getProjectPath(self, parent: QWidget, path: str | Path | None = None,
allowZip: bool = False) -> Path | None: allowZip: bool = False) -> Path | None:
"""Open the file dialog and select a novelWriter project file.""" """Open the file dialog and select a novelWriter project file."""
ext = [ label = (self.tr("novelWriter Project File or Zip")
self.tr("novelWriter Project File ({0})").format(nwFiles.PROJ_FILE), if allowZip else self.tr("novelWriter Project File"))
self.tr("All files ({0})").format("*"), ext = f"{nwFiles.PROJ_FILE} *.zip" if allowZip else nwFiles.PROJ_FILE
] selected, _ = QFileDialog.getOpenFileName(
if allowZip: parent, self.tr("Open Project"), str(path or ""), filter=";;".join(
ext.insert(1, self.tr("Zip Archives ({0})").format("*.zip")) [f"{label} ({ext})", "{0} (*)".format(self.tr("All Files"))]
projFile, _ = QFileDialog.getOpenFileName( )
parent, self.tr("Open Project"), str(path or ""), filter=";;".join(ext)
) )
return Path(projFile) if projFile else None return Path(selected) if selected else None
def findTopLevelWidget(self, kind: type[NWWidget]) -> NWWidget | None: def findTopLevelWidget(self, kind: type[NWWidget]) -> NWWidget | None:
"""Find a top level widget.""" """Find a top level widget."""
+89 -2
View File
@@ -22,6 +22,7 @@ from __future__ import annotations
import uuid import uuid
import pytest import pytest
import shutil
from shutil import copyfile from shutil import copyfile
from pathlib import Path from pathlib import Path
@@ -501,7 +502,7 @@ def testCoreTools_ProjectBuilderB(monkeypatch, fncPath, tstPaths, mockRnd):
@pytest.mark.core @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.""" """Create a new project copied from existing project."""
srcPath = prjLipsum / nwFiles.PROJ_FILE srcPath = prjLipsum / nwFiles.PROJ_FILE
dstPath = fncPath / "lipsum" dstPath = fncPath / "lipsum"
@@ -524,6 +525,14 @@ def testCoreTools_ProjectBuilderTemplate(monkeypatch, mockGUI, prjLipsum, fncPat
# Cannot copy to existing folder # Cannot copy to existing folder
assert builder.buildProject({"path": fncPath, "template": srcPath}) is False 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 # Copy project properly
assert builder.buildProject(data) is True 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.autoCount < 5
assert dstProject.data.editTime < 10 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 @pytest.mark.core
+3 -4
View File
@@ -24,10 +24,9 @@ import pytest
from pathlib import Path from pathlib import Path
from tools import getGuiItem
from PyQt5.QtWidgets import QAction, QMessageBox from PyQt5.QtWidgets import QAction, QMessageBox
from novelwriter import SHARED
from novelwriter.dialogs.about import GuiAbout from novelwriter.dialogs.about import GuiAbout
@@ -37,8 +36,8 @@ def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
# NW About # NW About
nwGUI.showAboutNWDialog(showNotes=True) nwGUI.showAboutNWDialog(showNotes=True)
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiAbout) is not None, timeout=1000)
msgAbout = getGuiItem("GuiAbout") msgAbout = SHARED.findTopLevelWidget(GuiAbout)
assert isinstance(msgAbout, GuiAbout) assert isinstance(msgAbout, GuiAbout)
assert msgAbout.pageAbout.document().characterCount() > 100 assert msgAbout.pageAbout.document().characterCount() > 100
+2 -4
View File
@@ -22,8 +22,6 @@ from __future__ import annotations
import pytest import pytest
from tools import getGuiItem
from PyQt5.QtGui import QFontDatabase, QKeyEvent from PyQt5.QtGui import QFontDatabase, QKeyEvent
from PyQt5.QtCore import QEvent, Qt from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog
@@ -44,8 +42,8 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
# Load GUI with standard values # Load GUI with standard values
nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger) nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger)
qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiPreferences) is not None, timeout=1000)
prefs = getGuiItem("GuiPreferences") prefs = SHARED.findTopLevelWidget(GuiPreferences)
assert isinstance(prefs, GuiPreferences) assert isinstance(prefs, GuiPreferences)
prefs.show() prefs.show()
@@ -22,7 +22,7 @@ from __future__ import annotations
import pytest import pytest
from tools import C, getGuiItem, buildTestProject from tools import C, buildTestProject
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt 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 # Check that we cannot open when there is no project
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
assert getGuiItem("GuiProjectSettings") is None assert SHARED.findTopLevelWidget(GuiProjectSettings) is None
# Pretend we have a project # Pretend we have a project
SHARED.project._valid = True SHARED.project._valid = True
@@ -55,9 +55,11 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
# Get the dialog object # Get the dialog object
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) 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) assert isinstance(projSettings, GuiProjectSettings)
projSettings.show() projSettings.show()
qtbot.addWidget(projSettings) qtbot.addWidget(projSettings)
+3 -3
View File
@@ -25,7 +25,7 @@ import pytest
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QAction from PyQt5.QtWidgets import QDialog, QAction
from tools import buildTestProject, getGuiItem from tools import buildTestProject
from novelwriter import SHARED from novelwriter import SHARED
from novelwriter.core.spellcheck import UserDictionary from novelwriter.core.spellcheck import UserDictionary
@@ -47,9 +47,9 @@ def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, projPath):
# Load the dialog # Load the dialog
nwGUI.mainMenu.aEditWordList.activate(QAction.Trigger) 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) assert isinstance(wList, GuiWordList)
wList.show() wList.show()
+5 -5
View File
@@ -26,7 +26,7 @@ import pytest
from shutil import copyfile from shutil import copyfile
from tools import ( from tools import (
C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE, getGuiItem C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE
) )
from PyQt5.QtGui import QPalette from PyQt5.QtGui import QPalette
@@ -93,16 +93,16 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath):
nwGUI.closeProject() nwGUI.closeProject()
# Check that release notes opened # Check that release notes opened
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiAbout) is not None, timeout=1000)
msgAbout = getGuiItem("GuiAbout") msgAbout = SHARED.findTopLevelWidget(GuiAbout)
assert isinstance(msgAbout, GuiAbout) assert isinstance(msgAbout, GuiAbout)
assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes
msgAbout.accept() msgAbout.accept()
# Check that project open dialog launches # Check that project open dialog launches
nwGUI.postLaunchTasks(None) nwGUI.postLaunchTasks(None)
qtbot.waitUntil(lambda: getGuiItem("GuiWelcome") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiWelcome) is not None, timeout=1000)
assert isinstance(welcome := getGuiItem("GuiWelcome"), GuiWelcome) assert isinstance(welcome := SHARED.findTopLevelWidget(GuiWelcome), GuiWelcome)
welcome.show() welcome.show()
welcome.close() welcome.close()
+2 -3
View File
@@ -25,7 +25,6 @@ import enchant
from zipfile import ZipFile from zipfile import ZipFile
from tools import getGuiItem
from mocked import causeException from mocked import causeException
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
@@ -48,9 +47,9 @@ def testToolDictionaries_Main(qtbot, monkeypatch, nwGUI, fncPath):
# Open the tool # Open the tool
nwGUI.showDictionariesDialog() 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 isinstance(nwDicts, GuiDictionaries)
assert nwDicts.isVisible() assert nwDicts.isVisible()
assert nwDicts.inPath.text() == str(fncPath) assert nwDicts.inPath.text() == str(fncPath)
+3 -2
View File
@@ -22,10 +22,11 @@ from __future__ import annotations
import pytest import pytest
from tools import C, getGuiItem, buildTestProject from tools import C, buildTestProject
from PyQt5.QtWidgets import QAction from PyQt5.QtWidgets import QAction
from novelwriter import SHARED
from novelwriter.tools.lipsum import GuiLipsum from novelwriter.tools.lipsum import GuiLipsum
@@ -34,7 +35,7 @@ def testToolLipsum_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
"""Test the Lorem Ipsum tool.""" """Test the Lorem Ipsum tool."""
# Check that we cannot open when there is no project # Check that we cannot open when there is no project
nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger) nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger)
assert getGuiItem("GuiLipsum") is None assert SHARED.findTopLevelWidget(GuiLipsum) is None
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
nwLipsum = GuiLipsum(nwGUI) nwLipsum = GuiLipsum(nwGUI)
+5 -5
View File
@@ -26,7 +26,7 @@ import pytest
from pathlib import Path from pathlib import Path
from pytestqt.qtbot import QtBot from pytestqt.qtbot import QtBot
from tools import C, buildTestProject, getGuiItem from tools import C, buildTestProject
from mocked import causeOSError from mocked import causeOSError
from PyQt5.QtCore import Qt, pyqtSlot 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* * *" allText = "New Novel\nBy Jane Doe\nA Chapter\n\t\tHi\n* * *"
nwGUI.mainMenu.aBuildManuscript.activate(QAction.Trigger) nwGUI.mainMenu.aBuildManuscript.activate(QAction.Trigger)
qtbot.waitUntil(lambda: getGuiItem("GuiManuscript") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiManuscript) is not None, timeout=1000)
manus = getGuiItem("GuiManuscript") manus = SHARED.findTopLevelWidget(GuiManuscript)
assert isinstance(manus, GuiManuscript) assert isinstance(manus, GuiManuscript)
manus.show() manus.show()
assert manus.docPreview.toPlainText().strip() == "" assert manus.docPreview.toPlainText().strip() == ""
@@ -104,7 +104,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path):
# Create a new build # Create a new build
manus.tbAdd.click() manus.tbAdd.click()
bSettings = getGuiItem("GuiBuildSettings") bSettings = SHARED.findTopLevelWidget(GuiBuildSettings)
assert isinstance(bSettings, GuiBuildSettings) assert isinstance(bSettings, GuiBuildSettings)
bSettings.editBuildName.setText("Test Build") bSettings.editBuildName.setText("Test Build")
build = None build = None
@@ -127,7 +127,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path):
manus.buildList.setCurrentRow(0) manus.buildList.setCurrentRow(0)
manus.tbEdit.click() manus.tbEdit.click()
bSettings = getGuiItem("GuiBuildSettings") bSettings = SHARED.findTopLevelWidget(GuiBuildSettings)
assert isinstance(bSettings, GuiBuildSettings) assert isinstance(bSettings, GuiBuildSettings)
build = None build = None
+2 -4
View File
@@ -22,8 +22,6 @@ from __future__ import annotations
import pytest import pytest
from tools import getGuiItem
from PyQt5.QtWidgets import QAction from PyQt5.QtWidgets import QAction
from novelwriter import SHARED from novelwriter import SHARED
@@ -49,8 +47,8 @@ def testToolNovelDetails_Main(qtbot, nwGUI, prjLipsum, ipsumText):
# Create the dialog # Create the dialog
nwGUI.mainMenu.aNovelDetails.activate(QAction.ActionEvent.Trigger) nwGUI.mainMenu.aNovelDetails.activate(QAction.ActionEvent.Trigger)
qtbot.waitUntil(lambda: getGuiItem("GuiNovelDetails") is not None, timeout=1000) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiNovelDetails) is not None, timeout=1000)
details = getGuiItem("GuiNovelDetails") details = SHARED.findTopLevelWidget(GuiNovelDetails)
assert isinstance(details, GuiNovelDetails) assert isinstance(details, GuiNovelDetails)
# Overview Page # Overview Page
+4 -5
View File
@@ -25,7 +25,7 @@ import pytest
from pathlib import Path from pathlib import Path
from tools import getGuiItem, buildTestProject from tools import buildTestProject
from mocked import causeOSError from mocked import causeOSError
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@@ -38,8 +38,7 @@ from novelwriter.tools.writingstats import GuiWritingStats
@pytest.mark.gui @pytest.mark.gui
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): 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 # Create a project to work on
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
project = SHARED.project project = SHARED.project
@@ -50,9 +49,9 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
# Open the Writing Stats dialog # Open the Writing Stats dialog
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger) 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) assert isinstance(sessLog, GuiWritingStats)
# Test Loading # Test Loading
+1 -9
View File
@@ -25,7 +25,7 @@ import shutil
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget, qApp from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget
XML_IGNORE = ("<novelWriterXML", "<project") XML_IGNORE = ("<novelWriterXML", "<project")
ODT_IGNORE = ("<meta:generator", "<meta:creation-date", "<dc:date", "<meta:editing") ODT_IGNORE = ("<meta:generator", "<meta:creation-date", "<dc:date", "<meta:editing")
@@ -114,14 +114,6 @@ def cmpFiles(
return not diffFound return not diffFound
def getGuiItem(name: str):
"""Returns a QtWidget based on its objectName."""
for qWidget in qApp.topLevelWidgets():
if qWidget.objectName() == name:
return qWidget
return None
def readFile(fileName: str | Path): def readFile(fileName: str | Path):
"""Returns the content of a file as a string.""" """Returns the content of a file as a string."""
with open(fileName, mode="r", encoding="utf-8") as inFile: with open(fileName, mode="r", encoding="utf-8") as inFile: