Remember last used path for each tool individually (#1934)
This commit is contained in:
+67
-15
@@ -5,6 +5,7 @@ novelWriter – Config Class
|
|||||||
File History:
|
File History:
|
||||||
Created: 2018-09-22 [0.0.1] Config
|
Created: 2018-09-22 [0.0.1] Config
|
||||||
Created: 2022-11-09 [2.0rc2] RecentProjects
|
Created: 2022-11-09 [2.0rc2] RecentProjects
|
||||||
|
Created: 2024-06-16 [2.5rc1] RecentPaths
|
||||||
|
|
||||||
This file is a part of novelWriter
|
This file is a part of novelWriter
|
||||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||||
@@ -103,7 +104,8 @@ class Config:
|
|||||||
# User Settings
|
# User Settings
|
||||||
# =============
|
# =============
|
||||||
|
|
||||||
self._recentObj = RecentProjects(self)
|
self._recentProjects = RecentProjects(self)
|
||||||
|
self._recentPaths = RecentPaths(self)
|
||||||
|
|
||||||
# General GUI Settings
|
# General GUI Settings
|
||||||
self.guiLocale = self._qLocale.name()
|
self.guiLocale = self._qLocale.name()
|
||||||
@@ -180,7 +182,6 @@ class Config:
|
|||||||
self.fmtPadThin = False
|
self.fmtPadThin = False
|
||||||
|
|
||||||
# User Paths
|
# User Paths
|
||||||
self._lastPath = self._homePath # The user's last used path
|
|
||||||
self._backupPath = self._backPath # Backup path to use, can be none
|
self._backupPath = self._backPath # Backup path to use, can be none
|
||||||
|
|
||||||
# Spell Checking Settings
|
# Spell Checking Settings
|
||||||
@@ -253,7 +254,7 @@ class Config:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def recentProjects(self) -> RecentProjects:
|
def recentProjects(self) -> RecentProjects:
|
||||||
return self._recentObj
|
return self._recentProjects
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mainWinSize(self) -> list[int]:
|
def mainWinSize(self) -> list[int]:
|
||||||
@@ -343,7 +344,7 @@ class Config:
|
|||||||
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
||||||
return
|
return
|
||||||
|
|
||||||
def setLastPath(self, path: str | Path) -> None:
|
def setLastPath(self, key: str, path: str | Path) -> None:
|
||||||
"""Set the last used path. Only the folder is saved, so if the
|
"""Set the last used path. Only the folder is saved, so if the
|
||||||
path is not a folder, the parent of the path is used instead.
|
path is not a folder, the parent of the path is used instead.
|
||||||
"""
|
"""
|
||||||
@@ -352,8 +353,7 @@ class Config:
|
|||||||
if not path.is_dir():
|
if not path.is_dir():
|
||||||
path = path.parent
|
path = path.parent
|
||||||
if path.is_dir():
|
if path.is_dir():
|
||||||
self._lastPath = path
|
self._recentPaths.setPath(key, path)
|
||||||
logger.debug("Last path updated: %s" % self._lastPath)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def setBackupPath(self, path: Path | str) -> None:
|
def setBackupPath(self, path: Path | str) -> None:
|
||||||
@@ -438,11 +438,12 @@ class Config:
|
|||||||
return self._appPath / "assets" / target
|
return self._appPath / "assets" / target
|
||||||
return self._appPath / "assets"
|
return self._appPath / "assets"
|
||||||
|
|
||||||
def lastPath(self) -> Path:
|
def lastPath(self, key: str) -> Path:
|
||||||
"""Return the last path used by the user, if it exists."""
|
"""Return the last path used by the user, if it exists."""
|
||||||
if isinstance(self._lastPath, Path):
|
if path := self._recentPaths.getPath(key):
|
||||||
if self._lastPath.is_dir():
|
asPath = Path(path)
|
||||||
return self._lastPath
|
if asPath.is_dir():
|
||||||
|
return asPath
|
||||||
return self._homePath
|
return self._homePath
|
||||||
|
|
||||||
def backupPath(self) -> Path:
|
def backupPath(self) -> Path:
|
||||||
@@ -516,7 +517,6 @@ class Config:
|
|||||||
logger.debug("Data Path: %s", self._dataPath)
|
logger.debug("Data Path: %s", self._dataPath)
|
||||||
logger.debug("App Root: %s", self._appRoot)
|
logger.debug("App Root: %s", self._appRoot)
|
||||||
logger.debug("App Path: %s", self._appPath)
|
logger.debug("App Path: %s", self._appPath)
|
||||||
logger.debug("Last Path: %s", self._lastPath)
|
|
||||||
logger.debug("PDF Manual: %s", self.pdfDocs)
|
logger.debug("PDF Manual: %s", self.pdfDocs)
|
||||||
|
|
||||||
# If the config and data folders don't exist, create them
|
# If the config and data folders don't exist, create them
|
||||||
@@ -531,7 +531,8 @@ class Config:
|
|||||||
(self._dataPath / "syntax").mkdir(exist_ok=True)
|
(self._dataPath / "syntax").mkdir(exist_ok=True)
|
||||||
(self._dataPath / "themes").mkdir(exist_ok=True)
|
(self._dataPath / "themes").mkdir(exist_ok=True)
|
||||||
|
|
||||||
self._recentObj.loadCache()
|
self._recentPaths.loadCache()
|
||||||
|
self._recentProjects.loadCache()
|
||||||
self._checkOptionalPackages()
|
self._checkOptionalPackages()
|
||||||
|
|
||||||
logger.debug("Config instance initialised")
|
logger.debug("Config instance initialised")
|
||||||
@@ -600,7 +601,6 @@ class Config:
|
|||||||
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
||||||
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
||||||
self.nativeFont = conf.rdBool(sec, "nativefont", self.nativeFont)
|
self.nativeFont = conf.rdBool(sec, "nativefont", self.nativeFont)
|
||||||
self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
|
|
||||||
|
|
||||||
# Sizes
|
# Sizes
|
||||||
sec = "Sizes"
|
sec = "Sizes"
|
||||||
@@ -710,7 +710,6 @@ class Config:
|
|||||||
"hidehscroll": str(self.hideHScroll),
|
"hidehscroll": str(self.hideHScroll),
|
||||||
"lastnotes": str(self.lastNotes),
|
"lastnotes": str(self.lastNotes),
|
||||||
"nativefont": str(self.nativeFont),
|
"nativefont": str(self.nativeFont),
|
||||||
"lastpath": str(self._lastPath),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conf["Sizes"] = {
|
conf["Sizes"] = {
|
||||||
@@ -811,7 +810,7 @@ class Config:
|
|||||||
"""Pack a list of items into a comma-separated string for saving
|
"""Pack a list of items into a comma-separated string for saving
|
||||||
to the config file.
|
to the config file.
|
||||||
"""
|
"""
|
||||||
return ", ".join([str(inVal) for inVal in data])
|
return ", ".join(str(inVal) for inVal in data)
|
||||||
|
|
||||||
def _checkOptionalPackages(self) -> None:
|
def _checkOptionalPackages(self) -> None:
|
||||||
"""Check optional packages used by some features."""
|
"""Check optional packages used by some features."""
|
||||||
@@ -893,3 +892,56 @@ class RecentProjects:
|
|||||||
logger.debug("Removed recent: %s", path)
|
logger.debug("Removed recent: %s", path)
|
||||||
self.saveCache()
|
self.saveCache()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RecentPaths:
|
||||||
|
|
||||||
|
KEYS = ["default", "project", "import", "outline", "stats"]
|
||||||
|
|
||||||
|
def __init__(self, config: Config) -> None:
|
||||||
|
self._conf = config
|
||||||
|
self._data = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
def setPath(self, key: str, path: Path | str) -> None:
|
||||||
|
"""Set a path for a given key, and save the cache."""
|
||||||
|
if key in self.KEYS:
|
||||||
|
self._data[key] = str(path)
|
||||||
|
self.saveCache()
|
||||||
|
return
|
||||||
|
|
||||||
|
def getPath(self, key: str) -> str | None:
|
||||||
|
"""Get a path for a given key, or return None."""
|
||||||
|
return self._data.get(key)
|
||||||
|
|
||||||
|
def loadCache(self) -> bool:
|
||||||
|
"""Load the cache file for recent paths."""
|
||||||
|
self._data = {}
|
||||||
|
cacheFile = self._conf.dataPath(nwFiles.RECENT_PATH)
|
||||||
|
if cacheFile.is_file():
|
||||||
|
try:
|
||||||
|
with open(cacheFile, mode="r", encoding="utf-8") as inFile:
|
||||||
|
data = json.load(inFile)
|
||||||
|
if isinstance(data, dict):
|
||||||
|
for key, path in data.items():
|
||||||
|
if key in self.KEYS and isinstance(path, str):
|
||||||
|
self._data[key] = path
|
||||||
|
except Exception:
|
||||||
|
logger.error("Could not load recent paths cache")
|
||||||
|
logException()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def saveCache(self) -> bool:
|
||||||
|
"""Save the cache dictionary of recent paths."""
|
||||||
|
cacheFile = self._conf.dataPath(nwFiles.RECENT_PATH)
|
||||||
|
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||||
|
try:
|
||||||
|
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
||||||
|
json.dump(self._data, outFile, indent=2)
|
||||||
|
cacheTemp.replace(cacheFile)
|
||||||
|
except Exception:
|
||||||
|
logger.error("Could not save recent paths cache")
|
||||||
|
logException()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ class nwFiles:
|
|||||||
# Config Files
|
# Config Files
|
||||||
CONF_FILE = "novelwriter.conf"
|
CONF_FILE = "novelwriter.conf"
|
||||||
RECENT_FILE = "recentProjects.json"
|
RECENT_FILE = "recentProjects.json"
|
||||||
|
RECENT_PATH = "recentPaths.json"
|
||||||
|
|
||||||
# Project Root Files
|
# Project Root Files
|
||||||
PROJ_FILE = "nwProject.nwx"
|
PROJ_FILE = "nwProject.nwx"
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ class BuildSettings:
|
|||||||
return self._order
|
return self._order
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lastPath(self) -> Path:
|
def lastBuildPath(self) -> Path:
|
||||||
"""The last used build path."""
|
"""The last used build path."""
|
||||||
if self._path.is_dir():
|
if self._path.is_dir():
|
||||||
return self._path
|
return self._path
|
||||||
@@ -293,7 +293,7 @@ class BuildSettings:
|
|||||||
self._order = value
|
self._order = value
|
||||||
return
|
return
|
||||||
|
|
||||||
def setLastPath(self, path: Path | str | None) -> None:
|
def setLastBuildPath(self, path: Path | str | None) -> None:
|
||||||
"""Set the last used build path."""
|
"""Set the last used build path."""
|
||||||
if isinstance(path, str):
|
if isinstance(path, str):
|
||||||
path = Path(path)
|
path = Path(path)
|
||||||
@@ -461,7 +461,7 @@ class BuildSettings:
|
|||||||
self.setName(data.get("name", ""))
|
self.setName(data.get("name", ""))
|
||||||
self.setBuildID(data.get("uuid", ""))
|
self.setBuildID(data.get("uuid", ""))
|
||||||
self.setOrder(data.get("order", 0))
|
self.setOrder(data.get("order", 0))
|
||||||
self.setLastPath(data.get("path", None))
|
self.setLastBuildPath(data.get("path", None))
|
||||||
self.setLastBuildName(data.get("build", ""))
|
self.setLastBuildName(data.get("build", ""))
|
||||||
|
|
||||||
buildFmt = str(data.get("format", ""))
|
buildFmt = str(data.get("format", ""))
|
||||||
|
|||||||
@@ -523,12 +523,12 @@ class GuiOutlineTree(QTreeWidget):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def exportOutline(self) -> None:
|
def exportOutline(self) -> None:
|
||||||
"""Export the outline as a CSV file."""
|
"""Export the outline as a CSV file."""
|
||||||
path = CONFIG.lastPath() / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
path = CONFIG.lastPath("outline") / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
||||||
path, _ = QFileDialog.getSaveFileName(
|
path, _ = QFileDialog.getSaveFileName(
|
||||||
self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
|
self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
CONFIG.setLastPath(path)
|
CONFIG.setLastPath("outline", path)
|
||||||
logger.info("Writing CSV file: %s", path)
|
logger.info("Writing CSV file: %s", path)
|
||||||
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
||||||
order = [self._colIdx[col] for col in cols]
|
order = [self._colIdx[col] for col in cols]
|
||||||
|
|||||||
@@ -652,7 +652,7 @@ class GuiMain(QMainWindow):
|
|||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
lastPath = CONFIG.lastPath()
|
lastPath = CONFIG.lastPath("import")
|
||||||
ffilter = formatFileFilter(["*.txt", "*.md", "*.nwd", "*"])
|
ffilter = formatFileFilter(["*.txt", "*.md", "*.nwd", "*"])
|
||||||
loadFile, _ = QFileDialog.getOpenFileName(
|
loadFile, _ = QFileDialog.getOpenFileName(
|
||||||
self, self.tr("Import File"), str(lastPath), filter=ffilter
|
self, self.tr("Import File"), str(lastPath), filter=ffilter
|
||||||
@@ -667,7 +667,7 @@ class GuiMain(QMainWindow):
|
|||||||
try:
|
try:
|
||||||
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
|
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
|
||||||
text = inFile.read()
|
text = inFile.read()
|
||||||
CONFIG.setLastPath(loadFile)
|
CONFIG.setLastPath("import", loadFile)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
SHARED.error(self.tr(
|
SHARED.error(self.tr(
|
||||||
"Could not read file. The file must be an existing text file."
|
"Could not read file. The file must be an existing text file."
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ class GuiManuscriptBuild(NDialog):
|
|||||||
|
|
||||||
self.btnBuild.setFocus()
|
self.btnBuild.setFocus()
|
||||||
self._populateContentList()
|
self._populateContentList()
|
||||||
self.buildPath.setText(str(self._build.lastPath))
|
self.buildPath.setText(str(self._build.lastBuildPath))
|
||||||
if self._build.lastBuildName:
|
if self._build.lastBuildName:
|
||||||
self.buildName.setText(self._build.lastBuildName)
|
self.buildName.setText(self._build.lastBuildName)
|
||||||
else:
|
else:
|
||||||
@@ -274,7 +274,7 @@ class GuiManuscriptBuild(NDialog):
|
|||||||
def _doSelectPath(self) -> None:
|
def _doSelectPath(self) -> None:
|
||||||
"""Select a folder for output."""
|
"""Select a folder for output."""
|
||||||
bPath = Path(self.buildPath.text())
|
bPath = Path(self.buildPath.text())
|
||||||
bPath = bPath if bPath.is_dir() else self._build.lastPath
|
bPath = bPath if bPath.is_dir() else self._build.lastBuildPath
|
||||||
savePath = QFileDialog.getExistingDirectory(
|
savePath = QFileDialog.getExistingDirectory(
|
||||||
self, self.tr("Select Folder"), str(bPath)
|
self, self.tr("Select Folder"), str(bPath)
|
||||||
)
|
)
|
||||||
@@ -336,7 +336,7 @@ class GuiManuscriptBuild(NDialog):
|
|||||||
for i, _ in docBuild.iterBuild(buildPath, bFormat):
|
for i, _ in docBuild.iterBuild(buildPath, bFormat):
|
||||||
self.buildProgress.setValue(i+1)
|
self.buildProgress.setValue(i+1)
|
||||||
|
|
||||||
self._build.setLastPath(bPath)
|
self._build.setLastBuildPath(bPath)
|
||||||
self._build.setLastBuildName(bName)
|
self._build.setLastBuildName(bName)
|
||||||
self._build.setLastFormat(bFormat)
|
self._build.setLastFormat(bFormat)
|
||||||
|
|
||||||
|
|||||||
@@ -220,8 +220,7 @@ class GuiWelcome(NDialog):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _browseForProject(self) -> None:
|
def _browseForProject(self) -> None:
|
||||||
"""Browse for a project to open."""
|
"""Browse for a project to open."""
|
||||||
if path := SHARED.getProjectPath(self, path=CONFIG.lastPath(), allowZip=False):
|
if path := SHARED.getProjectPath(self, path=CONFIG.homePath(), allowZip=False):
|
||||||
CONFIG.setLastPath(path)
|
|
||||||
self._openProjectPath(path)
|
self._openProjectPath(path)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -550,7 +549,7 @@ class _NewProjectForm(QWidget):
|
|||||||
def __init__(self, parent: QWidget) -> None:
|
def __init__(self, parent: QWidget) -> None:
|
||||||
super().__init__(parent=parent)
|
super().__init__(parent=parent)
|
||||||
|
|
||||||
self._basePath = CONFIG.homePath()
|
self._basePath = CONFIG.lastPath("project")
|
||||||
self._fillMode = self.FILL_BLANK
|
self._fillMode = self.FILL_BLANK
|
||||||
self._copyPath = None
|
self._copyPath = None
|
||||||
|
|
||||||
@@ -726,12 +725,13 @@ class _NewProjectForm(QWidget):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _doBrowse(self) -> None:
|
def _doBrowse(self) -> None:
|
||||||
"""Select a project folder."""
|
"""Select a project folder."""
|
||||||
if projDir := QFileDialog.getExistingDirectory(
|
if path := QFileDialog.getExistingDirectory(
|
||||||
self, self.tr("Select Project Folder"),
|
self, self.tr("Select Project Folder"),
|
||||||
str(self._basePath), options=QFileDialog.Option.ShowDirsOnly
|
str(self._basePath), options=QFileDialog.Option.ShowDirsOnly
|
||||||
):
|
):
|
||||||
self._basePath = Path(projDir)
|
self._basePath = Path(path)
|
||||||
self._updateProjPath()
|
self._updateProjPath()
|
||||||
|
CONFIG.setLastPath("project", path)
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
|||||||
@@ -384,14 +384,14 @@ class GuiWritingStats(NToolDialog):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Generate the file name
|
# Generate the file name
|
||||||
savePath = CONFIG.lastPath() / f"sessionStats.{fileExt}"
|
savePath = CONFIG.lastPath("stats") / f"sessionStats.{fileExt}"
|
||||||
savePath, _ = QFileDialog.getSaveFileName(
|
savePath, _ = QFileDialog.getSaveFileName(
|
||||||
self, self.tr("Save Data As"), str(savePath), f"{textFmt} (*.{fileExt})"
|
self, self.tr("Save Data As"), str(savePath), f"{textFmt} (*.{fileExt})"
|
||||||
)
|
)
|
||||||
if not savePath:
|
if not savePath:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
CONFIG.setLastPath(savePath)
|
CONFIG.setLastPath("stats", savePath)
|
||||||
|
|
||||||
# Do the actual writing
|
# Do the actual writing
|
||||||
wSuccess = False
|
wSuccess = False
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ def resetConfigVars():
|
|||||||
"""Reset the CONFIG object and set various values for testing to
|
"""Reset the CONFIG object and set various values for testing to
|
||||||
prevent interfering with local OS.
|
prevent interfering with local OS.
|
||||||
"""
|
"""
|
||||||
CONFIG.setLastPath(_TMP_ROOT)
|
|
||||||
CONFIG.setBackupPath(_TMP_ROOT)
|
CONFIG.setBackupPath(_TMP_ROOT)
|
||||||
CONFIG.setGuiFont(None)
|
CONFIG.setGuiFont(None)
|
||||||
CONFIG.setTextFont(None)
|
CONFIG.setTextFont(None)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[Meta]
|
[Meta]
|
||||||
timestamp = 2024-05-20 16:48:20
|
timestamp = 2024-06-16 00:36:27
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
font =
|
font =
|
||||||
@@ -10,7 +10,6 @@ hidevscroll = False
|
|||||||
hidehscroll = False
|
hidehscroll = False
|
||||||
lastnotes = 0x0
|
lastnotes = 0x0
|
||||||
nativefont = True
|
nativefont = True
|
||||||
lastpath =
|
|
||||||
|
|
||||||
[Sizes]
|
[Sizes]
|
||||||
mainwindow = 1200, 650
|
mainwindow = 1200, 650
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -28,7 +29,7 @@ from shutil import copyfile
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from novelwriter import CONFIG
|
from novelwriter import CONFIG
|
||||||
from novelwriter.config import Config, RecentProjects
|
from novelwriter.config import Config, RecentPaths, RecentProjects
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
|
|
||||||
from tests.mocked import MockApp, causeOSError
|
from tests.mocked import MockApp, causeOSError
|
||||||
@@ -213,21 +214,21 @@ def testBaseConfig_Methods(fncPath):
|
|||||||
assert tstConf.assetPath("stuff") == appPath / "assets" / "stuff"
|
assert tstConf.assetPath("stuff") == appPath / "assets" / "stuff"
|
||||||
|
|
||||||
# Last Path
|
# Last Path
|
||||||
assert tstConf.lastPath() == Path.home().absolute()
|
assert tstConf.lastPath("project") == Path.home().absolute()
|
||||||
|
|
||||||
tmpStuff = fncPath / "stuff"
|
tmpStuff = fncPath / "stuff"
|
||||||
tmpStuff.mkdir()
|
tmpStuff.mkdir()
|
||||||
tstConf.setLastPath(tmpStuff)
|
tstConf.setLastPath("project", tmpStuff)
|
||||||
assert tstConf.lastPath() == tmpStuff
|
assert tstConf.lastPath("project") == tmpStuff
|
||||||
|
|
||||||
fileStuff = tmpStuff / "more_stuff.txt"
|
fileStuff = tmpStuff / "more_stuff.txt"
|
||||||
fileStuff.write_text("Stuff")
|
fileStuff.write_text("Stuff")
|
||||||
tstConf.setLastPath(fileStuff)
|
tstConf.setLastPath("project", fileStuff)
|
||||||
assert tstConf.lastPath() == tmpStuff
|
assert tstConf.lastPath("project") == tmpStuff
|
||||||
|
|
||||||
fileStuff.unlink()
|
fileStuff.unlink()
|
||||||
tmpStuff.rmdir()
|
tmpStuff.rmdir()
|
||||||
assert tstConf.lastPath() == Path.home().absolute()
|
assert tstConf.lastPath("project") == Path.home().absolute()
|
||||||
|
|
||||||
# Backup Path
|
# Backup Path
|
||||||
assert tstConf.backupPath() == tstConf._backPath
|
assert tstConf.backupPath() == tstConf._backPath
|
||||||
@@ -440,3 +441,58 @@ def testBaseConfig_RecentCache(monkeypatch, tstPaths):
|
|||||||
assert recent.listEntries() == [
|
assert recent.listEntries() == [
|
||||||
(str(pathOne), "Proj One", 100, 1600002000),
|
(str(pathOne), "Proj One", 100, 1600002000),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseConfig_RecentPaths(monkeypatch, tstPaths):
|
||||||
|
"""Test recent paths file."""
|
||||||
|
cacheFile = tstPaths.cnfDir / nwFiles.RECENT_PATH
|
||||||
|
recent = RecentPaths(CONFIG)
|
||||||
|
|
||||||
|
# Load when there is no file should pass, but load nothing
|
||||||
|
assert not cacheFile.exists()
|
||||||
|
assert recent.loadCache() is True
|
||||||
|
assert recent._data == {}
|
||||||
|
|
||||||
|
# Set valid paths
|
||||||
|
recent.setPath("default", tstPaths.cnfDir / "default")
|
||||||
|
recent.setPath("project", tstPaths.cnfDir / "project")
|
||||||
|
recent.setPath("import", tstPaths.cnfDir / "import")
|
||||||
|
recent.setPath("outline", tstPaths.cnfDir / "outline")
|
||||||
|
recent.setPath("stats", tstPaths.cnfDir / "stats")
|
||||||
|
|
||||||
|
# Set invalid path
|
||||||
|
recent.setPath("foobar", tstPaths.cnfDir / "foobar")
|
||||||
|
|
||||||
|
# Check valid paths
|
||||||
|
assert recent.getPath("default") == str(tstPaths.cnfDir / "default")
|
||||||
|
assert recent.getPath("project") == str(tstPaths.cnfDir / "project")
|
||||||
|
assert recent.getPath("import") == str(tstPaths.cnfDir / "import")
|
||||||
|
assert recent.getPath("outline") == str(tstPaths.cnfDir / "outline")
|
||||||
|
assert recent.getPath("stats") == str(tstPaths.cnfDir / "stats")
|
||||||
|
|
||||||
|
# Check invalid path
|
||||||
|
assert recent.getPath("foobar") is None
|
||||||
|
|
||||||
|
# Check file
|
||||||
|
expected = {
|
||||||
|
"default": str(tstPaths.cnfDir / "default"),
|
||||||
|
"project": str(tstPaths.cnfDir / "project"),
|
||||||
|
"import": str(tstPaths.cnfDir / "import"),
|
||||||
|
"outline": str(tstPaths.cnfDir / "outline"),
|
||||||
|
"stats": str(tstPaths.cnfDir / "stats"),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert cacheFile.exists()
|
||||||
|
assert json.loads(cacheFile.read_text()) == expected
|
||||||
|
|
||||||
|
# Clear and reload
|
||||||
|
recent._data = {}
|
||||||
|
recent.loadCache()
|
||||||
|
assert recent._data == expected
|
||||||
|
|
||||||
|
# Check error handling
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("builtins.open", causeOSError)
|
||||||
|
assert recent.saveCache() is False
|
||||||
|
assert recent.loadCache() is False
|
||||||
|
|||||||
@@ -73,29 +73,29 @@ def testCoreBuildSettings_ClassAttributes(fncPath: Path):
|
|||||||
assert isUUID(build.buildID)
|
assert isUUID(build.buildID)
|
||||||
|
|
||||||
# Last path must be valid, if not it defaults to $HOME
|
# Last path must be valid, if not it defaults to $HOME
|
||||||
build.setLastPath("/path/to/nowhere")
|
build.setLastBuildPath("/path/to/nowhere")
|
||||||
assert build.lastPath == CONFIG.homePath()
|
assert build.lastBuildPath == CONFIG.homePath()
|
||||||
|
|
||||||
build.setLastPath(None)
|
build.setLastBuildPath(None)
|
||||||
assert build.lastPath == CONFIG.homePath()
|
assert build.lastBuildPath == CONFIG.homePath()
|
||||||
|
|
||||||
(fncPath / "test.txt").write_text("foobar")
|
(fncPath / "test.txt").write_text("foobar")
|
||||||
build.setLastPath(fncPath / "test.txt") # Can't be a file
|
build.setLastBuildPath(fncPath / "test.txt") # Can't be a file
|
||||||
assert build.lastPath == CONFIG.homePath()
|
assert build.lastBuildPath == CONFIG.homePath()
|
||||||
|
|
||||||
build.setLastPath(fncPath)
|
build.setLastBuildPath(fncPath)
|
||||||
assert build.lastPath == fncPath
|
assert build.lastBuildPath == fncPath
|
||||||
|
|
||||||
build.setLastPath(str(fncPath)) # String paths are also ok
|
build.setLastBuildPath(str(fncPath)) # String paths are also ok
|
||||||
assert build.lastPath == fncPath
|
assert build.lastBuildPath == fncPath
|
||||||
|
|
||||||
# Last path no longer exists -> fallback to $HOME
|
# Last path no longer exists -> fallback to $HOME
|
||||||
testDir = fncPath / "test_dir"
|
testDir = fncPath / "test_dir"
|
||||||
testDir.mkdir()
|
testDir.mkdir()
|
||||||
build.setLastPath(testDir)
|
build.setLastBuildPath(testDir)
|
||||||
assert build.lastPath == testDir
|
assert build.lastBuildPath == testDir
|
||||||
testDir.rmdir()
|
testDir.rmdir()
|
||||||
assert build.lastPath == CONFIG.homePath()
|
assert build.lastBuildPath == CONFIG.homePath()
|
||||||
|
|
||||||
# Last build name
|
# Last build name
|
||||||
build.setLastBuildName(None) # type: ignore
|
build.setLastBuildName(None) # type: ignore
|
||||||
@@ -119,7 +119,7 @@ def testCoreBuildSettings_ClassAttributes(fncPath: Path):
|
|||||||
# Set some sensible values
|
# Set some sensible values
|
||||||
build.setName("Test Build")
|
build.setName("Test Build")
|
||||||
build.setBuildID("5cf45d24-f496-42c9-8733-529a9e52a62b")
|
build.setBuildID("5cf45d24-f496-42c9-8733-529a9e52a62b")
|
||||||
build.setLastPath(fncPath)
|
build.setLastBuildPath(fncPath)
|
||||||
build.setLastBuildName("Build Name")
|
build.setLastBuildName("Build Name")
|
||||||
build.setLastFormat(nwBuildFmt.HTML)
|
build.setLastFormat(nwBuildFmt.HTML)
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def testToolManuscriptBuild_Main(
|
|||||||
buildTestProject(nwGUI, projPath)
|
buildTestProject(nwGUI, projPath)
|
||||||
nwGUI.openProject(projPath)
|
nwGUI.openProject(projPath)
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
build.setLastPath(fncPath)
|
build.setLastBuildPath(fncPath)
|
||||||
|
|
||||||
manus = GuiManuscriptBuild(nwGUI, build)
|
manus = GuiManuscriptBuild(nwGUI, build)
|
||||||
manus.show()
|
manus.show()
|
||||||
@@ -100,7 +100,7 @@ def testToolManuscriptBuild_Main(
|
|||||||
|
|
||||||
assert build.lastBuildName == "TestBuild"
|
assert build.lastBuildName == "TestBuild"
|
||||||
assert build.lastFormat == lastFmt
|
assert build.lastFormat == lastFmt
|
||||||
assert build.lastPath == fncPath
|
assert build.lastBuildPath == fncPath
|
||||||
|
|
||||||
# Error Handling
|
# Error Handling
|
||||||
# ==============
|
# ==============
|
||||||
|
|||||||
Reference in New Issue
Block a user