diff --git a/docs/source/conf.py b/docs/source/conf.py
index 8b507e58..4791c0e4 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -24,7 +24,7 @@ initFile = os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir,
"novelwriter", "__init__.py"
)
-with open(initFile) as inFile:
+with open(initFile, encoding="utf-8") as inFile:
for aLine in inFile:
if aLine.startswith("__version__"):
release = aLine.split('"')[1].strip()
diff --git a/tests/conftest.py b/tests/conftest.py
index 3dffc8c6..33baa870 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -33,10 +33,10 @@ from PyQt6.QtWidgets import QMessageBox
sys.path.insert(1, str(Path(__file__).parent.parent.absolute()))
-from novelwriter import CONFIG, SHARED # noqa: E402
+from novelwriter import CONFIG, SHARED
-from tests.mocked import MockGuiMain, MockTheme # noqa: E402
-from tests.tools import cleanProject # noqa: E402
+from tests.mocked import MockGuiMain, MockTheme
+from tests.tools import cleanProject
_TST_ROOT = Path(__file__).parent
_TMP_ROOT = _TST_ROOT / "temp"
@@ -89,7 +89,7 @@ def functionFixture(qtbot):
shutil.rmtree(_TMP_CONF)
_TMP_CONF.mkdir()
- CONFIG.__init__()
+ CONFIG.__init__() # noqa: PLC2801
CONFIG.initConfig(confPath=_TMP_CONF, dataPath=_TMP_CONF)
resetConfigVars()
logging.getLogger("novelwriter").setLevel(logging.INFO)
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 7314a844..39f96e3c 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,4 +1,5 @@
-pytest>=6.0.0
-pytest-timeout
+coverage>=7.2.0
pytest-cov
pytest-qt
+pytest-timeout
+pytest>=6.0.0
diff --git a/tests/test_base/test_base_common.py b/tests/test_base/test_base_common.py
index 7e03b895..bfd2b55c 100644
--- a/tests/test_base/test_base_common.py
+++ b/tests/test_base/test_base_common.py
@@ -556,7 +556,7 @@ def testBaseCommon_jsonEncode():
# Correct types
assert jsonEncode([1, 2]) == "[\n 1,\n 2\n]"
assert jsonEncode((1, 2)) == "[\n 1,\n 2\n]"
- assert jsonEncode({1: 2}) == "{\n \"1\": 2\n}"
+ assert jsonEncode({1: 2}) == '{\n "1": 2\n}'
tstDict = {
"null": None,
diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py
index b58c1fd2..74468629 100644
--- a/tests/test_base/test_base_config.py
+++ b/tests/test_base/test_base_config.py
@@ -141,8 +141,8 @@ def testBaseConfig_InitLoadSave(monkeypatch, fncPath, tstPaths):
assert newConf.guiSyntax == "bar"
# Test Correcting Quote Settings
- tstConf.fmtDQuoteOpen = "\""
- tstConf.fmtDQuoteClose = "\""
+ tstConf.fmtDQuoteOpen = '"'
+ tstConf.fmtDQuoteClose = '"'
tstConf.fmtSQuoteOpen = "'"
tstConf.fmtSQuoteClose = "'"
tstConf.doReplaceDQuote = True
diff --git a/tests/test_core/test_core_coretools.py b/tests/test_core/test_core_coretools.py
index 5b9f6c57..0bd4b24c 100644
--- a/tests/test_core/test_core_coretools.py
+++ b/tests/test_core/test_core_coretools.py
@@ -768,7 +768,7 @@ def testCoreTools_ProjectBuilderSample(monkeypatch, mockGUI, fncPath, tstPaths):
assert builder.buildProject(data) is False
# Create and open a defective zip file
- with open(dstSample, mode="w+") as outFile:
+ with open(dstSample, mode="w+", encoding="utf-8") as outFile:
outFile.write("foo")
assert builder.buildProject(data) is False
diff --git a/tests/test_core/test_core_projectxml.py b/tests/test_core/test_core_projectxml.py
index 39fa9297..acd5d19c 100644
--- a/tests/test_core/test_core_projectxml.py
+++ b/tests/test_core/test_core_projectxml.py
@@ -42,6 +42,8 @@ from tests.tools import cmpFiles, writeFile
class MockProject:
"""Fake project object."""
+ data: NWProjectData
+
def setProjectChanged(self, *a):
"""Fake project method."""
pass
@@ -219,7 +221,7 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, mockGUI, tstPaths, fncPath):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
item.unpack(entry)
@@ -348,7 +350,7 @@ def testCoreProjectXML_ReadLegacy10(tstPaths, fncPath, mockGUI, mockRnd):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
status = {}
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
@@ -493,7 +495,7 @@ def testCoreProjectXML_ReadLegacy11(tstPaths, fncPath, mockGUI, mockRnd):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
status = {}
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
@@ -638,7 +640,7 @@ def testCoreProjectXML_ReadLegacy12(tstPaths, fncPath, mockGUI, mockRnd):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
status = {}
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
@@ -786,7 +788,7 @@ def testCoreProjectXML_ReadLegacy13(tstPaths, fncPath, mockGUI, mockRnd):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
status = {}
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
@@ -933,7 +935,7 @@ def testCoreProjectXML_ReadLegacy14(tstPaths, fncPath, mockGUI, mockRnd):
packedContent = []
mockProject = MockProject()
- mockProject.__setattr__("data", data)
+ mockProject.data = data
status = {}
for entry in content:
item = NWItem(mockProject, "0000000000000") # type: ignore
diff --git a/tests/test_formats/test_fmt_toodt.py b/tests/test_formats/test_fmt_toodt.py
index 4f72f9df..05fde0e5 100644
--- a/tests/test_formats/test_fmt_toodt.py
+++ b/tests/test_formats/test_fmt_toodt.py
@@ -982,7 +982,7 @@ def testFmtToOdt_SaveFull(mockGUI, fncPath, tstPaths, ipsumText):
def prettifyXml(inFile, outFile):
with open(outFile, mode="wb") as fStream:
xml = ET.parse(inFile)
- xmlIndent(xml)
+ xmlIndent(xml.getroot())
xml.write(fStream, encoding="utf-8", xml_declaration=True)
prettifyXml(maniOut, maniFile)
@@ -1082,10 +1082,6 @@ def testFmtToOdt_ODTParagraphStyle():
assert parStyle._pAttr["text-align"] == ["fo", "end"]
parStyle.setTextAlign("justify")
assert parStyle._pAttr["text-align"] == ["fo", "justify"]
- parStyle.setTextAlign("inside")
- assert parStyle._pAttr["text-align"] == ["fo", "inside"]
- parStyle.setTextAlign("outside")
- assert parStyle._pAttr["text-align"] == ["fo", "outside"]
parStyle.setTextAlign("left")
assert parStyle._pAttr["text-align"] == ["fo", "left"]
parStyle.setTextAlign("right")
@@ -1099,8 +1095,6 @@ def testFmtToOdt_ODTParagraphStyle():
assert parStyle._pAttr["break-before"] == ["fo", None]
parStyle.setBreakBefore("auto")
assert parStyle._pAttr["break-before"] == ["fo", "auto"]
- parStyle.setBreakBefore("column")
- assert parStyle._pAttr["break-before"] == ["fo", "column"]
parStyle.setBreakBefore("page")
assert parStyle._pAttr["break-before"] == ["fo", "page"]
parStyle.setBreakBefore("even-page")
@@ -1118,8 +1112,6 @@ def testFmtToOdt_ODTParagraphStyle():
assert parStyle._pAttr["break-after"] == ["fo", None]
parStyle.setBreakAfter("auto")
assert parStyle._pAttr["break-after"] == ["fo", "auto"]
- parStyle.setBreakAfter("column")
- assert parStyle._pAttr["break-after"] == ["fo", "column"]
parStyle.setBreakAfter("page")
assert parStyle._pAttr["break-after"] == ["fo", "page"]
parStyle.setBreakAfter("even-page")
@@ -1394,9 +1386,9 @@ def testFmtToOdt_XMLParagraph():
# Plain Text
xmlPar.appendText("Hello World")
assert xmlToText(xRoot) == (
- ''
- 'Hello World'
- ''
+ ""
+ "Hello World"
+ ""
)
# Text Span
@@ -1431,9 +1423,9 @@ def testFmtToOdt_XMLParagraph():
# Plain Text w/Line Break
xmlPar.appendText("Hello\nWorld\n!!")
assert xmlToText(xRoot) == (
- ''
- 'HelloWorld!!'
- ''
+ ""
+ "HelloWorld!!"
+ ""
)
# Text Span w/Line Break
@@ -1467,9 +1459,9 @@ def testFmtToOdt_XMLParagraph():
# Plain Text w/Line Break
xmlPar.appendText("Hello\tWorld\t!!")
assert xmlToText(xRoot) == (
- ''
- 'HelloWorld!!'
- ''
+ ""
+ "HelloWorld!!"
+ ""
)
# Text Span w/Line Break
diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py
index be76f526..312c88bb 100644
--- a/tests/test_gui/test_gui_doceditor.py
+++ b/tests/test_gui/test_gui_doceditor.py
@@ -763,7 +763,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
assert docEditor.getText() == text.replace("consectetur", "\u2018consectetur\u2019")
# Replace Double Quotes
- repText = text.replace("consectetur", "\"consectetur\"")
+ repText = text.replace("consectetur", '"consectetur"')
docEditor.replaceText(repText)
assert docEditor.docAction(nwDocAction.SEL_ALL) is True
assert docEditor.docAction(nwDocAction.REPL_DBL) is True
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index da2d3ba0..24694ffe 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -116,7 +116,8 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath):
# Check that project open dialog launches
nwGUI.postLaunchTasks(None)
qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiWelcome) is not None, timeout=1000)
- assert isinstance(welcome := SHARED.findTopLevelWidget(GuiWelcome), GuiWelcome)
+ welcome = SHARED.findTopLevelWidget(GuiWelcome)
+ assert isinstance(welcome, GuiWelcome)
welcome.show()
welcome.close()
@@ -454,7 +455,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
# Dialogue
# ========
- for c in "\"Full line double quoted text.\"":
+ for c in '"Full line double quoted text."':
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
@@ -469,7 +470,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
CONFIG.fmtPadAfter = "\u201c"
docEditor.initEditor()
- for c in "Some \"double quoted text with spaces padded\".":
+ for c in 'Some "double quoted text with spaces padded".':
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
@@ -533,17 +534,17 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
# ================
nwGUI._switchFocus(nwView.EDITOR)
- for c in "\t\"Tab-indented text\"":
+ for c in '\t"Tab-indented text"':
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
- for c in ">\"Paragraph-indented text\"":
+ for c in '>"Paragraph-indented text"':
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
- for c in ">>\"Right-aligned text\"":
+ for c in '>>"Right-aligned text"':
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py
index ec29a233..f63f588a 100644
--- a/tests/test_gui/test_gui_mainmenu.py
+++ b/tests/test_gui/test_gui_mainmenu.py
@@ -279,7 +279,7 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
docEditor.setPlainText(
"### New Text\n\n"
"Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ 'Also text with "double" quotes which are "less tricky".\n\n'
)
mainMenu.aSelectAll.activate(QAction.ActionEvent.Trigger)
@@ -287,7 +287,7 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
assert docEditor.getText() == (
"### New Text\n\n"
"Text with ‘single’ quotes and ‘tricky stuff’s’.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ 'Also text with "double" quotes which are "less tricky".\n\n'
)
mainMenu.aSelectAll.activate(QAction.ActionEvent.Trigger)
@@ -347,7 +347,7 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
"### New Text\n\n"
"@tag: Bod\n\n"
"Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ 'Also text with "double" quotes which are "less tricky".\n\n'
)
# Cannot Format Tag
@@ -363,7 +363,7 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
"### New Text\n\n"
"@tag: Bod\n\n"
"Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ 'Also text with "double" quotes which are "less tricky".\n\n'
)
# qtbot.stop()
diff --git a/tests/test_text/test_text_patterns.py b/tests/test_text/test_text_patterns.py
index ca459292..ee938e10 100644
--- a/tests/test_text/test_text_patterns.py
+++ b/tests/test_text/test_text_patterns.py
@@ -29,15 +29,12 @@ from novelwriter.constants import nwUnicode
from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser
-def allMatches(regEx: re.Pattern, text: str) -> list[list[str]]:
+def allMatches(regEx: re.Pattern, text: str) -> list[list[tuple[str, int, int]]]:
"""Get all matches for a regex."""
- result = []
- for res in regEx.finditer(text):
- result.append([
- (res.group(n), res.start(n), res.end(n))
- for n in range((res.lastindex or 0) + 1)
- ])
- return result
+ return [
+ [(res.group(n), res.start(n), res.end(n)) for n in range((res.lastindex or 0) + 1)]
+ for res in regEx.finditer(text)
+ ]
@pytest.mark.core
@@ -310,7 +307,7 @@ def testTextPatterns_DialogueStyle():
assert allMatches(regEx, "one 'two' three") == []
# Straight double quotes are ignored
- assert allMatches(regEx, "one \"two\" three") == []
+ assert allMatches(regEx, 'one "two" three') == []
# Check with no whitespace, single quote
assert allMatches(regEx, "one\u2018two\u2019three") == [
@@ -370,19 +367,19 @@ def testTextPatterns_DialoguePlain():
# ======
# One double quoted string
- assert allMatches(regEx, "one \"two\" three") == [
- [("\"two\"", 4, 9)]
+ assert allMatches(regEx, 'one "two" three') == [
+ [('"two"', 4, 9)]
]
# Two double quoted strings
- assert allMatches(regEx, "one \"two\" three \"four\" five") == [
- [("\"two\"", 4, 9)], [("\"four\"", 16, 22)],
+ assert allMatches(regEx, 'one "two" three "four" five') == [
+ [('"two"', 4, 9)], [('"four"', 16, 22)],
]
# No space
- assert allMatches(regEx, "one\"two\" three") == []
- assert allMatches(regEx, "one \"two\"three") == []
- assert allMatches(regEx, "one\"two\"three") == []
+ assert allMatches(regEx, 'one"two" three') == []
+ assert allMatches(regEx, 'one "two"three') == []
+ assert allMatches(regEx, 'one"two"three') == []
# Single
# ======
@@ -595,6 +592,6 @@ def testTextPatterns_DialogParserPolish():
]
assert parser(
- "And so on and so forth. However, \"text in quotation marks\" should not be "
+ 'And so on and so forth. However, "text in quotation marks" should not be '
"highlighted at all, and if so, it should be highlighted differently."
) == []
diff --git a/tests/test_tools/test_tools_manusbuild.py b/tests/test_tools/test_tools_manusbuild.py
index 9a86eff6..50d04391 100644
--- a/tests/test_tools/test_tools_manusbuild.py
+++ b/tests/test_tools/test_tools_manusbuild.py
@@ -83,8 +83,7 @@ def testToolManuscriptBuild_Main(
if item.data(manus.D_KEY) == fmt:
manus.listFormats.setCurrentItem(item)
return
- else:
- raise ValueError("No such key in format list")
+ raise ValueError("No such key in format list")
# Build documents
lastFmt = None