Change dataPath to a Path object

This commit is contained in:
Veronica Berglyd Olsen
2022-11-09 00:25:50 +01:00
parent 6f5539de90
commit 6792c11a71
5 changed files with 44 additions and 59 deletions
+1 -3
View File
@@ -27,8 +27,6 @@ import sys
import getopt import getopt
import logging import logging
from pathlib import Path
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QErrorMessage from PyQt5.QtWidgets import QApplication, QErrorMessage
@@ -158,7 +156,7 @@ def main(sysArgs=None):
elif inOpt == "--style": elif inOpt == "--style":
qtStyle = inArg qtStyle = inArg
elif inOpt == "--config": elif inOpt == "--config":
confPath = Path(inArg) confPath = inArg
elif inOpt == "--data": elif inOpt == "--data":
dataPath = inArg dataPath = inArg
elif inOpt == "--testmode": elif inOpt == "--testmode":
+27 -34
View File
@@ -38,7 +38,7 @@ from PyQt5.QtCore import (
) )
from novelwriter.error import logException, formatException from novelwriter.error import logException, formatException
from novelwriter.common import ensureFolder, splitVersionNumber, formatTimeStamp, NWConfigParser from novelwriter.common import splitVersionNumber, formatTimeStamp, NWConfigParser
from novelwriter.constants import nwFiles, nwUnicode from novelwriter.constants import nwFiles, nwUnicode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -55,12 +55,14 @@ class Config:
self.appName = "novelWriter" self.appName = "novelWriter"
self.appHandle = "novelwriter" self.appHandle = "novelwriter"
confRoot = Path(QStandardPaths.writableLocation(QStandardPaths.ConfigLocation))
self._confPath = confRoot.absolute() / self.appHandle # The user config location
# Set Paths # Set Paths
confRoot = Path(QStandardPaths.writableLocation(QStandardPaths.ConfigLocation))
dataRoot = Path(QStandardPaths.writableLocation(QStandardPaths.AppDataLocation))
self._confPath = confRoot.absolute() / self.appHandle # The user config location
self._dataPath = dataRoot.absolute() / self.appHandle # The user data location
self.cmdOpen = None # Path from command line for project to be opened on launch self.cmdOpen = None # Path from command line for project to be opened on launch
self.dataPath = None # Folder where app data is stored
self.lastPath = None # The last user-selected folder (browse dialogs) self.lastPath = None # The last user-selected folder (browse dialogs)
self.appPath = None # The full path to the novelwriter package folder self.appPath = None # The full path to the novelwriter package folder
self.appRoot = None # The full path to the novelwriter root folder self.appRoot = None # The full path to the novelwriter root folder
@@ -245,6 +247,13 @@ class Config:
""" """
return int(theSize/self.guiScale) return int(theSize/self.guiScale)
def getDataPath(self, target=None):
"""Return a path in the data folder.
"""
if isinstance(target, str):
return self._dataPath / target
return self._dataPath
## ##
# Config Actions # Config Actions
## ##
@@ -254,19 +263,16 @@ class Config:
and dataPath is mainly intended for the test suite. and dataPath is mainly intended for the test suite.
""" """
logger.debug("Initialising Config ...") logger.debug("Initialising Config ...")
if isinstance(confPath, Path): if isinstance(confPath, (str, Path)):
logger.info("Setting config from alternative path: %s", confPath) logger.info("Setting config from alternative path: %s", confPath)
self._confPath = confPath self._confPath = Path(confPath)
if dataPath is None: if isinstance(dataPath, (str, Path)):
dataRoot = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)
self.dataPath = os.path.join(os.path.abspath(dataRoot), self.appHandle)
else:
logger.info("Setting data path from alternative path: %s", dataPath) logger.info("Setting data path from alternative path: %s", dataPath)
self.dataPath = dataPath self._dataPath = Path(dataPath)
logger.debug("Config path: %s", self._confPath) logger.debug("Config path: %s", self._confPath)
logger.debug("Data path: %s", self.dataPath) logger.debug("Data path: %s", self._dataPath)
self.lastPath = os.path.expanduser("~") self.lastPath = os.path.expanduser("~")
self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__))) self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__)))
@@ -293,15 +299,12 @@ class Config:
# If the config and data folders don't not exist, create them # If the config and data folders don't not exist, create them
# This assumes that the os config and data folders exist # This assumes that the os config and data folders exist
self._confPath.mkdir(exist_ok=True) self._confPath.mkdir(exist_ok=True)
self._dataPath.mkdir(exist_ok=True)
if not ensureFolder(self.dataPath, errLog=self.errData):
self.hasError = True
self.dataPath = None
# We don't error on these failing since they are not essential # We don't error on these failing since they are not essential
if self.dataPath is not None: if self._dataPath.is_dir():
ensureFolder("syntax", parent=self.dataPath) (self._dataPath / "syntax").mkdir(exist_ok=True)
ensureFolder("themes", parent=self.dataPath) (self._dataPath / "themes").mkdir(exist_ok=True)
# Check if config file exists # Check if config file exists
if (self._confPath / nwFiles.CONF_FILE).is_file(): if (self._confPath / nwFiles.CONF_FILE).is_file():
@@ -618,12 +621,9 @@ class Config:
def loadRecentCache(self): def loadRecentCache(self):
"""Load the cache file for recent projects. """Load the cache file for recent projects.
""" """
if self.dataPath is None:
return False
self.recentProj = {} self.recentProj = {}
cacheFile = os.path.join(self.dataPath, nwFiles.RECENT_FILE) cacheFile = self._dataPath / nwFiles.RECENT_FILE
if not os.path.isfile(cacheFile): if not os.path.isfile(cacheFile):
return True return True
@@ -649,25 +649,18 @@ class Config:
def saveRecentCache(self): def saveRecentCache(self):
"""Save the cache dictionary of recent projects. """Save the cache dictionary of recent projects.
""" """
if self.dataPath is None: cacheFile = self._dataPath / nwFiles.RECENT_FILE
return False cacheTemp = cacheFile.with_suffix(".tmp")
cacheFile = os.path.join(self.dataPath, nwFiles.RECENT_FILE)
cacheTemp = os.path.join(self.dataPath, nwFiles.RECENT_FILE+"~")
try: try:
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile: with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
json.dump(self.recentProj, outFile, indent=2) json.dump(self.recentProj, outFile, indent=2)
cacheTemp.replace(cacheFile)
except Exception as exc: except Exception as exc:
self.hasError = True self.hasError = True
self.errData.append("Could not save recent project cache") self.errData.append("Could not save recent project cache")
self.errData.append(formatException(exc)) self.errData.append(formatException(exc))
return False return False
if os.path.isfile(cacheFile):
os.unlink(cacheFile)
os.rename(cacheTemp, cacheFile)
return True return True
def updateRecentCache(self, projPath, projTitle, wordCount, saveTime): def updateRecentCache(self, projPath, projTitle, wordCount, saveTime):
+8 -8
View File
@@ -29,6 +29,7 @@ import logging
import novelwriter import novelwriter
from math import ceil from math import ceil
from pathlib import Path
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import qApp from PyQt5.QtWidgets import qApp
@@ -122,9 +123,8 @@ class GuiTheme:
self._listConf(self._availSyntax, os.path.join(self.mainConf.assetPath, "syntax")) self._listConf(self._availSyntax, os.path.join(self.mainConf.assetPath, "syntax"))
self._listConf(self._availThemes, os.path.join(self.mainConf.assetPath, "themes")) self._listConf(self._availThemes, os.path.join(self.mainConf.assetPath, "themes"))
if self.mainConf.dataPath: # Not guaranteed to be set self._listConf(self._availSyntax, self.mainConf.getDataPath("syntax"))
self._listConf(self._availSyntax, os.path.join(self.mainConf.dataPath, "syntax")) self._listConf(self._availThemes, self.mainConf.getDataPath("themes"))
self._listConf(self._availThemes, os.path.join(self.mainConf.dataPath, "themes"))
self.loadTheme() self.loadTheme()
self.loadSyntax() self.loadSyntax()
@@ -380,13 +380,13 @@ class GuiTheme:
def _listConf(self, targetDict, checkDir): def _listConf(self, targetDict, checkDir):
"""Scan for theme config files and populate the dictionary. """Scan for theme config files and populate the dictionary.
""" """
if not os.path.isdir(checkDir): checkDir = Path(checkDir)
if not checkDir.is_dir():
return False return False
for checkFile in os.listdir(checkDir): for checkFile in checkDir.iterdir():
confPath = os.path.join(checkDir, checkFile) if checkFile.is_file() and checkFile.name.endswith(".conf"):
if os.path.isfile(confPath) and confPath.endswith(".conf"): targetDict[checkFile.name[:-5]] = checkFile
targetDict[checkFile[:-5]] = confPath
return True return True
+2 -2
View File
@@ -165,7 +165,7 @@ def tmpConf(tmpPath):
if confFile.is_file(): if confFile.is_file():
confFile.unlink() confFile.unlink()
theConf = Config() theConf = Config()
theConf.initConfig(tmpPath, str(tmpPath)) theConf.initConfig(tmpPath, tmpPath)
theConf.setLastPath("") theConf.setLastPath("")
theConf.guiLang = "en_GB" theConf.guiLang = "en_GB"
return theConf return theConf
@@ -179,7 +179,7 @@ def fncConf(fncPath):
if confFile.is_file(): if confFile.is_file():
confFile.unlink() confFile.unlink()
theConf = Config() theConf = Config()
theConf.initConfig(fncPath, str(fncPath)) theConf.initConfig(fncPath, fncPath)
theConf.setLastPath("") theConf.setLastPath("")
theConf.guiLang = "en_GB" theConf.guiLang = "en_GB"
return theConf return theConf
+6 -12
View File
@@ -99,7 +99,7 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *a: fncDir) mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *a: fncDir)
tstConf.initConfig() tstConf.initConfig()
assert tstConf._confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf._confPath == os.path.join(fncDir, tstConf.appHandle)
assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf._dataPath == os.path.join(fncDir, tstConf.appHandle)
assert not os.path.isfile(confFile) assert not os.path.isfile(confFile)
# Fail to make folders # Fail to make folders
@@ -109,13 +109,13 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
tstConfDir = os.path.join(fncDir, "test_conf") tstConfDir = os.path.join(fncDir, "test_conf")
tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir) tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir)
assert tstConf._confPath is None assert tstConf._confPath is None
assert tstConf.dataPath == tmpDir assert tstConf._dataPath == tmpDir
assert not os.path.isfile(confFile) assert not os.path.isfile(confFile)
tstDataDir = os.path.join(fncDir, "test_data") tstDataDir = os.path.join(fncDir, "test_data")
tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir) tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir)
assert tstConf._confPath == tmpDir assert tstConf._confPath == tmpDir
assert tstConf.dataPath is None assert tstConf._dataPath is None
assert os.path.isfile(confFile) assert os.path.isfile(confFile)
os.unlink(confFile) os.unlink(confFile)
@@ -130,7 +130,7 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
mp.setattr("os.path.expanduser", lambda *a: "") mp.setattr("os.path.expanduser", lambda *a: "")
tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
assert tstConf._confPath == tmpDir assert tstConf._confPath == tmpDir
assert tstConf.dataPath == tmpDir assert tstConf._dataPath == tmpDir
assert os.path.isfile(confFile) assert os.path.isfile(confFile)
copyfile(confFile, testFile) copyfile(confFile, testFile)
@@ -158,13 +158,13 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
assert tstConf._confPath == tmpDir assert tstConf._confPath == tmpDir
assert tstConf.dataPath == tmpDir assert tstConf._dataPath == tmpDir
appRoot = tstConf.appRoot appRoot = tstConf.appRoot
mp.setattr("os.path.isfile", lambda *a: True) mp.setattr("os.path.isfile", lambda *a: True)
tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
assert tstConf._confPath == tmpDir assert tstConf._confPath == tmpDir
assert tstConf.dataPath == tmpDir assert tstConf._dataPath == tmpDir
assert tstConf.appRoot == os.path.dirname(appRoot) assert tstConf.appRoot == os.path.dirname(appRoot)
assert tstConf.appPath == os.path.dirname(appRoot) assert tstConf.appPath == os.path.dirname(appRoot)
@@ -233,12 +233,6 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
def testBaseConfig_RecentCache(monkeypatch, tmpConf, tmpDir, fncDir): def testBaseConfig_RecentCache(monkeypatch, tmpConf, tmpDir, fncDir):
"""Test recent cache file. """Test recent cache file.
""" """
# Check failing
tmpConf.dataPath = None
assert not tmpConf.loadRecentCache()
assert not tmpConf.saveRecentCache()
tmpConf.dataPath = tmpDir
# Add a couple of values # Add a couple of values
pathOne = os.path.join(fncDir, "projPathOne", nwFiles.PROJ_FILE) pathOne = os.path.join(fncDir, "projPathOne", nwFiles.PROJ_FILE)
pathTwo = os.path.join(fncDir, "projPathTwo", nwFiles.PROJ_FILE) pathTwo = os.path.join(fncDir, "projPathTwo", nwFiles.PROJ_FILE)