diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py
index 1ff73d2e..f617817d 100644
--- a/novelwriter/core/coretools.py
+++ b/novelwriter/core/coretools.py
@@ -305,11 +305,10 @@ class ProjectBuilder:
return False
project = NWProject(self.mainGui)
- if not project.setProjectPath(projPath, newProject=True):
+ if not project.storage.openProjectInPlace(projPath, newProject=True):
return False
- if not project.storage.openProjectInPlace(projPath):
- return False
+ project.projPath = projPath
lblNewProject = self.tr("New Project")
lblNewChapter = self.tr("New Chapter")
diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py
index ce1a1278..e7c50671 100644
--- a/novelwriter/core/index.py
+++ b/novelwriter/core/index.py
@@ -26,11 +26,11 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import json
import logging
from time import time
+from pathlib import Path
from novelwriter.enum import nwItemType, nwItemLayout
from novelwriter.error import logException
@@ -141,12 +141,15 @@ class NWIndex:
def loadIndex(self):
"""Load index from last session from the project meta folder.
"""
+ indexFile = self.theProject.storage.getMetaFile(nwFiles.INDEX_FILE)
+ if not isinstance(indexFile, Path):
+ return False
+
theData = {}
- indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
tStart = time()
self._indexBroken = False
- if os.path.isfile(indexFile):
+ if indexFile.exists():
logger.debug("Loading index file")
try:
with open(indexFile, mode="r", encoding="utf-8") as inFile:
@@ -184,8 +187,11 @@ class NWIndex:
"""Save the current index as a json file in the project meta
data folder.
"""
+ indexFile = self.theProject.storage.getMetaFile(nwFiles.INDEX_FILE)
+ if not isinstance(indexFile, Path):
+ return False
+
logger.debug("Saving index file")
- indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
tStart = time()
try:
diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py
index 9d840e0f..cbf3fe14 100644
--- a/novelwriter/core/options.py
+++ b/novelwriter/core/options.py
@@ -24,11 +24,11 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import json
import logging
from enum import Enum
+from pathlib import Path
from novelwriter.error import logException
from novelwriter.common import checkBool, checkFloat, checkInt, checkString
@@ -77,13 +77,12 @@ class OptionState:
def loadSettings(self):
"""Load the options dictionary from the project settings file.
"""
- if self.theProject.projMeta is None:
+ stateFile = self.theProject.storage.getMetaFile(nwFiles.OPTS_FILE)
+ if not isinstance(stateFile, Path):
return False
- stateFile = os.path.join(self.theProject.projMeta, nwFiles.OPTS_FILE)
theState = {}
-
- if os.path.isfile(stateFile):
+ if stateFile.exists():
logger.debug("Loading GUI options file")
try:
with open(stateFile, mode="r", encoding="utf-8") as inFile:
@@ -106,12 +105,11 @@ class OptionState:
def saveSettings(self):
"""Save the options dictionary to the project settings file.
"""
- if self.theProject.projMeta is None:
+ stateFile = self.theProject.storage.getMetaFile(nwFiles.OPTS_FILE)
+ if not isinstance(stateFile, Path):
return False
- stateFile = os.path.join(self.theProject.projMeta, nwFiles.OPTS_FILE)
logger.debug("Saving GUI options file")
-
try:
with open(stateFile, mode="w+", encoding="utf-8") as outFile:
json.dump(self._theState, outFile, indent=2)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index 9d0c78ca..891d8dde 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -27,6 +27,7 @@ from __future__ import annotations
import os
import json
+from pathlib import Path
import shutil
import logging
import novelwriter
@@ -84,7 +85,6 @@ class NWProject(QObject):
# Class Settings
self.projPath = None # The full path to where the currently open project is saved
- self.projMeta = None # The full path to the project's meta data folder
self.projCache = None # The full path to the project's cache folder
self.projContent = None # The full path to the project's content folder
self.projDict = None # The spell check dictionary
@@ -254,7 +254,6 @@ class NWProject(QObject):
# Project Settings
self.projPath = None
- self.projMeta = None
self.projCache = None
self.projContent = None
self.projDict = None
@@ -276,11 +275,10 @@ class NWProject(QObject):
self.projPath = str(self._storage.runtimePath)
self.projContent = str(self._storage.contentPath)
self.projCache = str(self._storage.cachePath)
- self.projMeta = str(self._storage.metaPath)
logger.info("Opening project: %s", self.projPath)
- self.projDict = os.path.join(self.projMeta, nwFiles.PROJ_DICT)
+ self.projDict = str(self._storage.getMetaFile(nwFiles.PROJ_DICT))
# Project Lock
# ============
@@ -421,8 +419,6 @@ class NWProject(QObject):
return False
saveTime = time()
- if not self.ensureFolderStructure():
- return False
logger.info("Saving project: %s", self.projPath)
@@ -482,7 +478,6 @@ class NWProject(QObject):
if self.projPath is None or self.projPath == "":
return False
- self.projMeta = os.path.join(self.projPath, "meta")
self.projCache = os.path.join(self.projPath, "cache")
self.projContent = os.path.join(self.projPath, "content")
@@ -490,8 +485,6 @@ class NWProject(QObject):
# Don't make a mess in the user's home folder
return False
- if not self._checkFolder(self.projMeta):
- return False
if not self._checkFolder(self.projCache):
return False
if not self._checkFolder(self.projContent):
@@ -589,41 +582,6 @@ class NWProject(QObject):
# Setters
##
- def setProjectPath(self, projPath, newProject=False):
- """Set the project storage path, and also expand ~ to the user
- directory using the path library.
- """
- if projPath is None or projPath == "":
- self.projPath = None
- else:
- if projPath.startswith("~"):
- projPath = os.path.expanduser(projPath)
- self.projPath = os.path.abspath(projPath)
-
- if newProject:
- if not os.path.isdir(projPath):
- try:
- os.mkdir(projPath)
- logger.debug("Created folder: %s", projPath)
- except Exception as exc:
- self.mainGui.makeAlert(self.tr(
- "Could not create new project folder."
- ), nwAlert.ERROR, exception=exc)
- return False
-
- if os.path.isdir(projPath):
- if os.listdir(self.projPath):
- self.mainGui.makeAlert(self.tr(
- "New project folder is not empty. "
- "Each project requires a dedicated project folder."
- ), nwAlert.ERROR)
- return False
-
- self.ensureFolderStructure()
- self.setProjectChanged(True)
-
- return True
-
def setProjectLang(self, theLang):
"""Set the project-specific language.
"""
@@ -934,12 +892,10 @@ class NWProject(QObject):
def _appendSessionStats(self, idleTime):
"""Append session statistics to the sessions log file.
"""
- if not self.ensureFolderStructure():
+ sessionFile = self._storage.getMetaFile(nwFiles.SESS_STATS)
+ if not isinstance(sessionFile, Path):
return False
- sessionFile = os.path.join(self.projMeta, nwFiles.SESS_STATS)
- isFile = os.path.isfile(sessionFile)
-
nowTime = time()
iNovel, iNotes = self._data.initCounts
cNovel, cNotes = self._data.currCounts
@@ -953,6 +909,7 @@ class NWProject(QObject):
return False
try:
+ isFile = sessionFile.exists() # We must save the state before we open
with open(sessionFile, mode="a+", encoding="utf-8") as outFile:
if not isFile:
# It's a new file, so add a header
diff --git a/novelwriter/core/storage.py b/novelwriter/core/storage.py
index 0813f7cc..485af8f0 100644
--- a/novelwriter/core/storage.py
+++ b/novelwriter/core/storage.py
@@ -97,7 +97,7 @@ class NWStorage:
"""
return self._runtimePath is not None
- def openProjectInPlace(self, path):
+ def openProjectInPlace(self, path, newProject=False):
"""Open a novelWriter project in-place. That is, it is opened
directly from a project folder.
"""
@@ -112,7 +112,7 @@ class NWStorage:
self._lockFilePath = inPath / nwFiles.PROJ_LOCK
self._openMode = self.MODE_INPLACE
- if self._prepareStorage(checkLegacy=True) is False:
+ if not self._prepareStorage(checkLegacy=True, newProject=newProject):
self.clear()
return False
@@ -142,7 +142,7 @@ class NWStorage:
##
def getXmlReader(self):
- """
+ """Return a properly configured ProjectXMLReader instance.
"""
if self._runtimePath is None:
return None
@@ -153,7 +153,7 @@ class NWStorage:
return xmlReader
def getXmlWriter(self):
- """
+ """Return a properly configured ProjectXMLWriter instance.
"""
if self._runtimePath is None:
return None
@@ -165,8 +165,12 @@ class NWStorage:
def getDocument(self, tHandle):
pass
- def getMetaFile(self, kind):
- pass
+ def getMetaFile(self, fileName):
+ """Return the path to a file in the project meta folder.
+ """
+ if self._runtimePath is not None:
+ return self._runtimePath / "meta" / fileName
+ return None
def readLockFile(self):
"""Read the project lock file.
@@ -234,7 +238,7 @@ class NWStorage:
def _writeLockFile(self):
pass
- def _prepareStorage(self, checkLegacy=True):
+ def _prepareStorage(self, checkLegacy=True, newProject=False):
"""Prepare the storage area for the project.
"""
path = self._runtimePath
@@ -248,6 +252,15 @@ class NWStorage:
self.clear()
return False
+ if newProject:
+ # If it's a new project, we check that there is no existing
+ # project in the selected path.
+ projFile = path / nwFiles.PROJ_FILE
+ if projFile.exists():
+ logger.error("A project already exists in this path")
+ self.clear()
+ return False
+
# The folder is not required to exist, as it could be a new
# project, so we make sure it does. Then we add subfolders.
try:
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index 01a8afff..baabccdb 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -23,10 +23,11 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import logging
import novelwriter
+from pathlib import Path
+
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QListWidget,
@@ -150,9 +151,11 @@ class GuiWordList(QDialog):
"""
self._saveGuiSettings()
- dctFile = os.path.join(self.theProject.projMeta, nwFiles.PROJ_DICT)
- tmpFile = dctFile + "~"
+ dctFile = self.theProject.storage.getMetaFile(nwFiles.PROJ_DICT)
+ if not isinstance(dctFile, Path):
+ return False
+ tmpFile = dctFile.with_suffix(".tmp")
try:
with open(tmpFile, mode="w", encoding="utf-8") as outFile:
for i in range(self.listBox.count()):
@@ -160,15 +163,16 @@ class GuiWordList(QDialog):
if item is not None:
outFile.write(item.text() + "\n")
+ if dctFile.exists():
+ dctFile.unlink()
+ tmpFile.rename(dctFile)
+
except Exception:
logger.error("Could not save new word list")
logException()
self.reject()
return False
- if os.path.isfile(dctFile):
- os.unlink(dctFile)
- os.rename(tmpFile, dctFile)
self.accept()
return True
@@ -187,10 +191,12 @@ class GuiWordList(QDialog):
def _loadWordList(self):
"""Load the project's word list, if it exists.
"""
- self.listBox.clear()
+ wordList = self.theProject.storage.getMetaFile(nwFiles.PROJ_DICT)
+ if not isinstance(wordList, Path):
+ return False
- wordList = os.path.join(self.theProject.projMeta, nwFiles.PROJ_DICT)
- if not os.path.isfile(wordList):
+ self.listBox.clear()
+ if not wordList.exists():
logger.debug("No project dictionary file found")
return False
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index 2a579837..7015c992 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -28,6 +28,7 @@ import json
import logging
import novelwriter
+from pathlib import Path
from datetime import datetime
from PyQt5.QtGui import QPixmap, QCursor
@@ -439,8 +440,8 @@ class GuiWritingStats(QDialog):
ttTime = 0
ttIdle = 0
- logFile = os.path.join(self.theProject.projMeta, nwFiles.SESS_STATS)
- if not os.path.isfile(logFile):
+ logFile = self.theProject.storage.getMetaFile(nwFiles.SESS_STATS)
+ if not isinstance(logFile, Path) or not logFile.exists():
logger.info("This project has no writing stats logfile")
return False
diff --git a/tests/test_core/test_core_options.py b/tests/test_core/test_core_options.py
index 0535ca71..8d1b74fb 100644
--- a/tests/test_core/test_core_options.py
+++ b/tests/test_core/test_core_options.py
@@ -19,28 +19,30 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import json
import pytest
from mock import causeOSError
-from tools import writeFile
+from novelwriter.constants import nwFiles
from novelwriter.core.options import OptionState
from novelwriter.core.project import NWProject
-from novelwriter.constants import nwFiles
+from novelwriter.gui.noveltree import NovelTreeColumn
@pytest.mark.core
-def testCoreOptions_LoadSave(monkeypatch, mockGUI, tmpDir):
+def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
"""Test loading and saving from the OptionState class.
"""
theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
+ metaDir = fncPath / "meta"
+ metaDir.mkdir()
+
# Write a test file
- optFile = os.path.join(tmpDir, nwFiles.OPTS_FILE)
- writeFile(optFile, json.dumps({
+ optFile = metaDir / nwFiles.OPTS_FILE
+ optFile.write_text(json.dumps({
"GuiBuildNovel": {
"winWidth": 1000,
"winHeight": 700,
@@ -52,22 +54,22 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, tmpDir):
"MockGroup": {
"mockItem": None,
},
- }))
+ }), encoding="utf-8")
# Load and save with no path set
- theProject.projMeta = None
- assert not theOpts.loadSettings()
- assert not theOpts.saveSettings()
+ theProject.storage._runtimePath = None
+ assert theOpts.loadSettings() is False
+ assert theOpts.saveSettings() is False
# Set path
- theProject.projMeta = tmpDir
- assert theProject.projMeta == tmpDir
+ theProject.storage._runtimePath = fncPath
+ assert theProject.storage.getMetaFile(nwFiles.OPTS_FILE) == optFile
# Cause open() to fail
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
- assert not theOpts.loadSettings()
- assert not theOpts.saveSettings()
+ assert theOpts.loadSettings() is False
+ assert theOpts.saveSettings() is False
# Load proper
assert theOpts.loadSettings()
@@ -108,9 +110,11 @@ def testCoreOptions_SetGet(mockGUI):
theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
+ nwColHidden = NovelTreeColumn.HIDDEN
+
# Set invalid values
- assert not theOpts.setValue("MockGroup", "mockItem", None)
- assert not theOpts.setValue("GuiBuildNovel", "mockItem", None)
+ assert theOpts.setValue("MockGroup", "mockItem", None) is False
+ assert theOpts.setValue("GuiBuildNovel", "mockItem", None) is False
# Set valid value
assert theOpts.setValue("GuiBuildNovel", "winWidth", 100)
@@ -120,6 +124,7 @@ def testCoreOptions_SetGet(mockGUI):
assert theOpts.setValue("GuiBuildNovel", "winHeight", 12.34)
assert theOpts.setValue("GuiBuildNovel", "addNovel", True)
assert theOpts.setValue("GuiBuildNovel", "textFont", "Cantarell")
+ assert theOpts.setValue("GuiNovelView", "lastCol", nwColHidden)
# Generic get, doesn't check type
assert theOpts.getValue("GuiBuildNovel", "winWidth", None) == 100
@@ -139,5 +144,14 @@ def testCoreOptions_SetGet(mockGUI):
assert theOpts.getFloat("GuiBuildNovel", "mockItem", None) is None
assert theOpts.getBool("GuiBuildNovel", "addNovel", None) is True
assert theOpts.getBool("GuiBuildNovel", "mockItem", None) is None
+ assert theOpts.getEnum("GuiNovelView", "lastCol", NovelTreeColumn, None) == nwColHidden
+
+ # Get from non-existent groups
+ assert theOpts.getValue("SomeGroup", "mockItem", None) is None
+ assert theOpts.getString("SomeGroup", "mockItem", None) is None
+ assert theOpts.getInt("SomeGroup", "mockItem", None) is None
+ assert theOpts.getFloat("SomeGroup", "mockItem", None) is None
+ assert theOpts.getBool("SomeGroup", "mockItem", None) is None
+ assert theOpts.getEnum("SomeGroup", "mockItem", NovelTreeColumn, None) is None
# END Test testCoreOptions_SetGet
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 752e216b..4404fdc3 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -23,11 +23,13 @@ import os
import shutil
import pytest
+from time import time
from shutil import copyfile
+from pathlib import Path
from zipfile import ZipFile
from mock import causeOSError
-from tools import C, cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE
+from tools import C, cmpFiles, writeFile, buildTestProject, XML_IGNORE
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.common import formatTimeStamp
@@ -52,11 +54,6 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI, mockRnd):
mockRnd.reset()
buildTestProject(theProject, fncDir)
- assert theProject.setProjectPath(fncDir) is True
- assert theProject.saveProject() is True
- assert theProject.closeProject() is True
- assert theProject.openProject(projFile) is True
-
assert theProject.newRoot(nwItemClass.NOVEL) == "0000000000010"
assert theProject.newRoot(nwItemClass.PLOT) == "0000000000011"
assert theProject.newRoot(nwItemClass.CHARACTER) == "0000000000012"
@@ -108,11 +105,6 @@ def testCoreProject_NewFileFolder(monkeypatch, fncDir, outDir, refDir, mockGUI,
mockRnd.reset()
buildTestProject(theProject, fncDir)
- assert theProject.setProjectPath(fncDir) is True
- assert theProject.saveProject() is True
- assert theProject.closeProject() is True
- assert theProject.openProject(projFile) is True
-
# Invalid call
assert theProject.newFolder("New Folder", "1234567890abc") is None
assert theProject.newFile("New File", "1234567890abc") is None
@@ -195,7 +187,6 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
assert theProject.openProject(fncDir) is False
# Fail on lock file
- theProject.setProjectPath(fncDir)
assert theProject._storage.writeLockFile()
assert theProject.openProject(fncDir) is False
@@ -208,7 +199,6 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
assert theProject.closeProject()
# Force open with lockfile
- theProject.setProjectPath(fncDir)
assert theProject._storage.writeLockFile()
assert theProject.openProject(fncDir, overrideLock=True) is True
assert theProject.closeProject()
@@ -267,12 +257,6 @@ def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncDir, refDir):
mockRnd.reset()
buildTestProject(theProject, fncDir)
- # Fail on folder structure check
- with monkeypatch.context() as mp:
- mp.setattr("os.mkdir", causeOSError)
- shutil.rmtree(os.path.join(fncDir, "meta"))
- assert theProject.saveProject() is False
-
# Fail writing
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLWriter, "write", lambda *a: False)
@@ -303,12 +287,6 @@ def testCoreProject_Helpers(monkeypatch, fncDir, mockGUI):
mp.setattr("os.path.expanduser", lambda *a, **k: fncDir)
assert theProject.ensureFolderStructure() is False
- # Create a file to block meta folder
- metaDir = os.path.join(fncDir, "meta")
- writeFile(metaDir, "stuff")
- assert theProject.ensureFolderStructure() is False
- os.unlink(metaDir)
-
# Create a file to block cache folder
cacheDir = os.path.join(fncDir, "cache")
writeFile(cacheDir, "stuff")
@@ -323,7 +301,7 @@ def testCoreProject_Helpers(monkeypatch, fncDir, mockGUI):
# Now, do it right
assert theProject.ensureFolderStructure() is True
- assert os.path.isdir(metaDir)
+ # assert os.path.isdir(metaDir)
assert os.path.isdir(cacheDir)
assert os.path.isdir(contentDir)
@@ -506,32 +484,12 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
@pytest.mark.core
-def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd):
+def testCoreProject_Methods(monkeypatch, mockGUI, fncDir, mockRnd):
"""Test other project class methods and functions.
"""
theProject = NWProject(mockGUI)
buildTestProject(theProject, fncDir)
- # Setting project path
- assert theProject.setProjectPath(None)
- assert theProject.projPath is None
- assert theProject.setProjectPath("")
- assert theProject.projPath is None
- assert theProject.setProjectPath("~")
- assert theProject.projPath == os.path.expanduser("~")
-
- # Create a new folder and populate it
- projPath = os.path.join(fncDir, "mock1")
- assert theProject.setProjectPath(projPath, newProject=True)
-
- # Make os.mkdir fail
- monkeypatch.setattr("os.mkdir", causeOSError)
- projPath = os.path.join(fncDir, "mock2")
- assert not theProject.setProjectPath(projPath, newProject=True)
-
- # Set back
- assert theProject.setProjectPath(fncDir)
-
# Project Name
theProject.data.setName(" A Name ")
assert theProject.data.name == "A Name"
@@ -639,29 +597,39 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd):
assert theProject.tree.handles() == oldOrder
# Session stats
- theProject._data._initCounts = [50, 50]
- theProject._data._currCounts = [100, 100]
+ theProject.data.setInitCounts(50, 50)
+ theProject.data.setCurrCounts(100, 100)
+
+ # No path for writing
with monkeypatch.context() as mp:
- mp.setattr("os.path.isdir", lambda *a, **k: False)
- assert not theProject._appendSessionStats(idleTime=0)
+ mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None)
+ assert theProject._appendSessionStats(idleTime=0) is False
# Block open
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
- assert not theProject._appendSessionStats(idleTime=0)
+ assert theProject._appendSessionStats(idleTime=0) is False
+
+ # Session too short
+ theProject._projOpened = time()
+ theProject.data.setInitCounts(50, 50)
+ theProject.data.setCurrCounts(50, 50)
+ assert theProject._appendSessionStats(idleTime=0) is False
# Write entry
- assert theProject.projMeta == os.path.join(fncDir, "meta")
- statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS)
+ statsFile = theProject.storage.getMetaFile(nwFiles.SESS_STATS)
+ assert isinstance(statsFile, Path)
+ statsFile.unlink(missing_ok=True)
theProject._projOpened = 1600002000
- theProject._data._currCounts = [200, 100]
+ theProject.data._initCounts = [50, 50]
+ theProject.data._currCounts = [200, 100]
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.project.time", lambda: 1600005600)
assert theProject._appendSessionStats(idleTime=99)
- assert readFile(statsFile) == (
+ assert statsFile.read_text(encoding="utf-8") == (
"# Offset 100\n"
"# Start Time End Time Novel Notes Idle\n"
"%s %s 200 100 99\n"
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 28582695..4ec1ed5e 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -170,8 +170,6 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
assert len(nwGUI.theProject.tree._treeOrder) == 0
assert len(nwGUI.theProject.tree._treeRoots) == 0
assert nwGUI.theProject.tree.trashRoot() is None
- assert nwGUI.theProject.projPath is None
- assert nwGUI.theProject.projMeta is None
assert nwGUI.theProject.data.name == ""
assert nwGUI.theProject.data.title == ""
assert nwGUI.theProject.data.authors == []
@@ -192,8 +190,6 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
assert len(nwGUI.theProject.tree._treeOrder) == 8
assert len(nwGUI.theProject.tree._treeRoots) == 4
assert nwGUI.theProject.tree.trashRoot() is None
- assert nwGUI.theProject.projPath == fncProj
- assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta")
assert nwGUI.theProject.data.name == "New Project"
assert nwGUI.theProject.data.title == "New Novel"
assert nwGUI.theProject.data.authors == ["Jane Doe"]
diff --git a/tests/tools.py b/tests/tools.py
index e101bcbb..99f0d258 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -166,8 +166,8 @@ def buildTestProject(theObject, projPath):
theProject = theObject.theProject
theProject.clearProject()
- theProject.setProjectPath(projPath, newProject=True)
- theProject.storage.openProjectInPlace(theProject.projPath)
+ theProject.projPath = projPath
+ theProject.storage.openProjectInPlace(projPath)
theProject.setDefaultStatusImport()
theProject.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")