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