Change dataPath to a Path object
This commit is contained in:
@@ -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
@@ -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):
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user