Release 2.7 Alpha 2 (#2198)

This commit is contained in:
Veronica Berglyd Olsen
2025-01-20 22:22:07 +01:00
committed by GitHub
6 changed files with 59 additions and 50 deletions
+37 -27
View File
@@ -42,14 +42,14 @@ if TYPE_CHECKING: # pragma: no cover
# ============ # ============
__package__ = "novelwriter" __package__ = "novelwriter"
__copyright__ = "Copyright 20182024, Veronica Berglyd Olsen" __copyright__ = "Copyright 2018-2025 Veronica Berglyd Olsen"
__license__ = "GPLv3" __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen" __author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen" __maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net" __email__ = "code@vkbo.net"
__version__ = "2.7a1" __version__ = "2.7a2"
__hexversion__ = "0x020700a1" __hexversion__ = "0x020700a2"
__date__ = "2025-01-15" __date__ = "2025-01-20"
__status__ = "Stable" __status__ = "Stable"
__domain__ = "novelwriter.io" __domain__ = "novelwriter.io"
@@ -65,20 +65,20 @@ CONFIG = Config()
SHARED = SharedData() SHARED = SharedData()
# ANSI Colours # ANSI Colours
C_RED = "\033[91m" RED = "\033[91m"
C_GREEN = "\033[92m" GREEN = "\033[92m"
C_YELLOW = "\033[93m" YELLOW = "\033[93m"
C_BLUE = "\033[94m" BLUE = "\033[94m"
C_WHITE = "\033[97m" WHITE = "\033[97m"
C_END = "\033[0m" END = "\033[0m"
# Log Formats # Log Format Components
L_TIME = "[{asctime:}]" TIME = "[{asctime:}]"
L_FILE = "{filename:>18}" FILE = "{filename:>18}"
L_LINE = "{lineno:<4d}" LINE = "{lineno:<4d}"
L_LVLP = "{levelname:8}" LVLP = "{levelname:8}"
L_LVLC = "{levelname:17}" LVLC = "{levelname:17}"
L_TEXT = "{message:}" TEXT = "{message:}"
def main(sysArgs: list | None = None) -> GuiMain | None: def main(sysArgs: list | None = None) -> GuiMain | None:
@@ -104,11 +104,19 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
f"novelWriter {__version__} ({__date__})\n" f"novelWriter {__version__} ({__date__})\n"
f"{__copyright__}\n" f"{__copyright__}\n"
"\n" "\n"
"This program is free software: you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation, either version 3 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n" "This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public Licence for more details.\n" "GNU General Public Licence for more details.\n"
"\n" "\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program. If not, see <https://www.gnu.org/licenses/>.\n"
"\n"
"Usage:\n" "Usage:\n"
" -h, --help Print this message.\n" " -h, --help Print this message.\n"
" -v, --version Print program version and exit.\n" " -v, --version Print program version and exit.\n"
@@ -167,21 +175,21 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
if fmtFlags & 0b01: if fmtFlags & 0b01:
# This will overwrite the default level names, and also ensure that # This will overwrite the default level names, and also ensure that
# they can be converted back to integer levels # they can be converted back to integer levels
logging.addLevelName(logging.DEBUG, f"{C_BLUE}DEBUG{C_END}") logging.addLevelName(logging.DEBUG, f"{BLUE}DEBUG{END}")
logging.addLevelName(logging.INFO, f"{C_GREEN}INFO{C_END}") logging.addLevelName(logging.INFO, f"{GREEN}INFO{END}")
logging.addLevelName(logging.WARNING, f"{C_YELLOW}WARNING{C_END}") logging.addLevelName(logging.WARNING, f"{YELLOW}WARNING{END}")
logging.addLevelName(logging.ERROR, f"{C_RED}ERROR{C_END}") logging.addLevelName(logging.ERROR, f"{RED}ERROR{END}")
logging.addLevelName(logging.CRITICAL, f"{C_RED}CRITICAL{C_END}") logging.addLevelName(logging.CRITICAL, f"{RED}CRITICAL{END}")
# Determine Log Format # Determine Log Format
if fmtFlags == 0b00: if fmtFlags == 0b00:
logFmt = f"{L_LVLP} {L_TEXT}" logFmt = f"{LVLP} {TEXT}"
elif fmtFlags == 0b01: elif fmtFlags == 0b01:
logFmt = f"{L_LVLC} {L_TEXT}" logFmt = f"{LVLC} {TEXT}"
elif fmtFlags == 0b10: elif fmtFlags == 0b10:
logFmt = f"{L_TIME} {L_FILE}:{L_LINE} {L_LVLP} {L_TEXT}" logFmt = f"{TIME} {FILE}:{LINE} {LVLP} {TEXT}"
elif fmtFlags == 0b11: elif fmtFlags == 0b11:
logFmt = f"{L_TIME} {C_BLUE}{L_FILE}{C_END}:{C_WHITE}{L_LINE}{C_END} {L_LVLC} {L_TEXT}" logFmt = f"{TIME} {BLUE}{FILE}{END}:{WHITE}{LINE}{END} {LVLC} {TEXT}"
# Setup Logging # Setup Logging
pkgLogger = logging.getLogger(__package__) pkgLogger = logging.getLogger(__package__)
@@ -272,7 +280,9 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
def _createApp(style: str) -> QApplication: def _createApp(style: str) -> QApplication:
"""Create the app.""" """Create the app. This is done in a function to make it easier to
block app creation during testing.
"""
app = QApplication([CONFIG.appName, (f"-style={style}")]) app = QApplication([CONFIG.appName, (f"-style={style}")])
app.setApplicationName(CONFIG.appName) app.setApplicationName(CONFIG.appName)
app.setApplicationVersion(__version__) app.setApplicationVersion(__version__)
+2 -2
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.7a1" hexVersion="0x020700a1" fileVersion="1.5" fileRevision="4" timeStamp="2025-01-15 23:35:34"> <novelWriterXML appVersion="2.7a2" hexVersion="0x020700a2" fileVersion="1.5" fileRevision="4" timeStamp="2025-01-18 15:16:45">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2152" autoCount="281" editTime="95820"> <project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2153" autoCount="281" editTime="95823">
<name>Sample Project</name> <name>Sample Project</name>
<author>Jane Smith</author> <author>Jane Smith</author>
</project> </project>
+6 -6
View File
@@ -1,7 +1,7 @@
IDI_ICON1 ICON DISCARDABLE "novelwriter.ico" IDI_ICON1 ICON DISCARDABLE "novelWriter.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 1,0,0,0 FILEVERSION 1,1,0,0
PRODUCTVERSION 1,0,0,0 PRODUCTVERSION 1,1,0,0
FILEOS 0x4 FILEOS 0x4
FILETYPE 0x1 FILETYPE 0x1
{ {
@@ -9,11 +9,11 @@ FILETYPE 0x1
BLOCK "040904b0" { BLOCK "040904b0" {
VALUE "CompanyName", "Veronica Berglyd Olsen\0" VALUE "CompanyName", "Veronica Berglyd Olsen\0"
VALUE "FileDescription", "novelWriter Launcher\0" VALUE "FileDescription", "novelWriter Launcher\0"
VALUE "FileVersion", "1.0.0.0\0" VALUE "FileVersion", "1.1.0.0\0"
VALUE "LegalCopyright", "© 2025 Veronica Berglyd Olsen\0" VALUE "LegalCopyright", "(c) 2025 Veronica Berglyd Olsen\0"
VALUE "OriginalFilename", "novelWriter.exe\0" VALUE "OriginalFilename", "novelWriter.exe\0"
VALUE "ProductName", "novelWriter\0" VALUE "ProductName", "novelWriter\0"
VALUE "ProductVersion", "1.0.0.0\0" VALUE "ProductVersion", "1.1.0.0\0"
} }
} }
BLOCK "VarFileInfo" { BLOCK "VarFileInfo" {
+8 -7
View File
@@ -24,7 +24,7 @@
#include <tchar.h> #include <tchar.h>
#include <iostream> #include <iostream>
void _tmain( int argc, TCHAR *argv[] ) { void _tmain(int argc, TCHAR *argv[]) {
STARTUPINFO si; STARTUPINFO si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
@@ -32,19 +32,20 @@ void _tmain( int argc, TCHAR *argv[] ) {
si.cb = sizeof(si); si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&pi, sizeof(pi));
TCHAR fileName[MAX_PATH]; TCHAR path[MAX_PATH];
auto pathlen = GetModuleFileName(NULL, fileName, MAX_PATH); auto pathlen = GetModuleFileName(NULL, path, MAX_PATH);
fileName[pathlen - 15] = 0; path[pathlen - 15] = 0;
SetCurrentDirectory(fileName); SetCurrentDirectory(path);
std::cout << "WorkDir: " << fileName << std::endl; std::cout << "WorkDir: " << path << std::endl;
TCHAR cmd[MAX_PATH] = "pythonw.exe novelWriter.pyw"; TCHAR cmd[MAX_PATH] = TEXT("pythonw.exe novelWriter.pyw");
if (argc > 1) { if (argc > 1) {
_tcscat_s(cmd, TEXT(" ")); _tcscat_s(cmd, TEXT(" "));
_tcscat_s(cmd, argv[1]); _tcscat_s(cmd, argv[1]);
} }
std::cout << "Command: " << cmd << std::endl; std::cout << "Command: " << cmd << std::endl;
std::cout << "Launching novelWriter GUI" << std::endl;
CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
return; return;
Binary file not shown.
+6 -8
View File
@@ -30,8 +30,8 @@ import pytest
from PyQt6.QtWidgets import QApplication from PyQt6.QtWidgets import QApplication
from novelwriter import ( from novelwriter import (
C_BLUE, C_END, C_WHITE, CONFIG, L_FILE, L_LINE, L_LVLC, L_LVLP, L_TEXT, BLUE, CONFIG, END, FILE, LINE, LVLC, LVLP, TEXT, TIME, WHITE, _createApp,
L_TIME, _createApp, logger, main logger, main
) )
from tests.tools import clearLogHandlers from tests.tools import clearLogHandlers
@@ -115,16 +115,14 @@ def testBaseInit_Options(monkeypatch, fncPath):
main(["--info", "--color", f"--config={fncPath}", f"--data={fncPath}"]) main(["--info", "--color", f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0 assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.INFO assert logger.getEffectiveLevel() == logging.INFO
assert getFormat() == f"{L_LVLC} {L_TEXT}" assert getFormat() == f"{LVLC} {TEXT}"
clearLogHandlers() clearLogHandlers()
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
main(["--debug", "--color", f"--config={fncPath}", f"--data={fncPath}"]) main(["--debug", "--color", f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0 assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.DEBUG assert logger.getEffectiveLevel() == logging.DEBUG
assert getFormat() == ( assert getFormat() == f"{TIME} {BLUE}{FILE}{END}:{WHITE}{LINE}{END} {LVLC} {TEXT}"
f"{L_TIME} {C_BLUE}{L_FILE}{C_END}:{C_WHITE}{L_LINE}{C_END} {L_LVLC} {L_TEXT}"
)
# Log Levels wo/Color # Log Levels wo/Color
clearLogHandlers() clearLogHandlers()
@@ -132,14 +130,14 @@ def testBaseInit_Options(monkeypatch, fncPath):
main(["--info", f"--config={fncPath}", f"--data={fncPath}"]) main(["--info", f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0 assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.INFO assert logger.getEffectiveLevel() == logging.INFO
assert getFormat() == f"{L_LVLP} {L_TEXT}" assert getFormat() == f"{LVLP} {TEXT}"
clearLogHandlers() clearLogHandlers()
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
main(["--debug", f"--config={fncPath}", f"--data={fncPath}"]) main(["--debug", f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0 assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.DEBUG assert logger.getEffectiveLevel() == logging.DEBUG
assert getFormat() == f"{L_TIME} {L_FILE}:{L_LINE} {L_LVLP} {L_TEXT}" assert getFormat() == f"{TIME} {FILE}:{LINE} {LVLP} {TEXT}"
# Help and Version # Help and Version
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex: