Change lastPath to a Path object

This commit is contained in:
Veronica Berglyd Olsen
2022-11-09 18:21:40 +01:00
parent 9d3291aba6
commit 47b57172eb
13 changed files with 45 additions and 71 deletions
+25 -24
View File
@@ -64,26 +64,20 @@ class Config:
self._confPath = confRoot.absolute() / self.appHandle # The user config location self._confPath = confRoot.absolute() / self.appHandle # The user config location
self._dataPath = dataRoot.absolute() / self.appHandle # The user data location self._dataPath = dataRoot.absolute() / self.appHandle # The user data location
self._lastPath = Path.home().absolute() # The user's last used path
if hasattr(sys, "_MEIPASS"): self._appPath = Path(__file__).parent.absolute()
self._appPath = Path(sys._MEIPASS).absolute()
else:
self._appPath = Path(__file__).parent.absolute()
self._appRoot = self._appPath.parent self._appRoot = self._appPath.parent
if self._appRoot.is_file(): if self._appRoot.is_file():
# novelWriter is packaged as a single file # novelWriter is packaged as a single file
self._appRoot = self._appRoot.parent self._appRoot = self._appRoot.parent
self._appPath = self._appRoot self._appPath = self._appRoot
self.cmdOpen = None # Path from command line for project to be opened on launch
self.lastPath = None # The last user-selected folder (browse dialogs)
self.pdfDocs = None # The location of the PDF manual, if it exists
# Runtime Settings and Variables # Runtime Settings and Variables
self.hasError = False # True if the config class encountered an error self.hasError = False # True if the config class encountered an error
self.errData = [] # List of error messages self.errData = [] # List of error messages
self.confChanged = False # True whenever the config has chenged, false after save self.confChanged = False # True whenever the config has chenged, false after save
self.cmdOpen = None # Path from command line for project to be opened on launch
# Localisation Info # Localisation Info
self._qLocal = QLocale.system() self._qLocal = QLocale.system()
@@ -91,6 +85,10 @@ class Config:
self._qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath) self._qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
self._nwLangPath = str(self._appPath / "assets" / "i18n") self._nwLangPath = str(self._appPath / "assets" / "i18n")
# PDF Manual
pdfDocs = self._appPath / "assets" / "manual.pdf"
self.pdfDocs = pdfDocs if pdfDocs.is_file() else None
# User Settings # User Settings
# ============= # =============
@@ -277,6 +275,13 @@ class Config:
return self._appPath / "assets" / target return self._appPath / "assets" / target
return self._appPath / "assets" return self._appPath / "assets"
def getLastPath(self):
"""Return the last path used by the user, but ensure it exists.
"""
if self._lastPath.is_dir():
return self._lastPath
return Path.home().absolute()
## ##
# Config Actions # Config Actions
## ##
@@ -298,9 +303,8 @@ 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)
self.lastPath = os.path.expanduser("~") logger.debug("PDF Manual: %s", self.pdfDocs)
logger.debug("Last path: %s", self.lastPath)
# 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
@@ -329,12 +333,6 @@ class Config:
if not self.spellLanguage: if not self.spellLanguage:
self.spellLanguage = "en" self.spellLanguage = "en"
# Look for a PDF version of the manual
pdfDocs = self._appPath / "assets" / "manual.pdf"
if pdfDocs.is_file():
logger.debug("Found PDF manual: %s", pdfDocs)
self.pdfDocs = pdfDocs
logger.debug("Config initialisation complete") logger.debug("Config initialisation complete")
return True return True
@@ -495,7 +493,7 @@ class Config:
# Path # Path
cnfSec = "Path" cnfSec = "Path"
self.lastPath = theConf.rdStr(cnfSec, "lastpath", self.lastPath) self._lastPath = Path(theConf.rdStr(cnfSec, "lastpath", self._lastPath))
# Check Certain Values for None # Check Certain Values for None
self.spellLanguage = self._checkNone(self.spellLanguage) self.spellLanguage = self._checkNone(self.spellLanguage)
@@ -605,7 +603,7 @@ class Config:
} }
theConf["Path"] = { theConf["Path"] = {
"lastpath": str(self.lastPath), "lastpath": str(self._lastPath),
} }
# Write config file # Write config file
@@ -698,10 +696,13 @@ class Config:
def setLastPath(self, lastPath): def setLastPath(self, lastPath):
"""Set the last used path (by the user). """Set the last used path (by the user).
""" """
if lastPath is None or lastPath == "": if isinstance(lastPath, str):
self.lastPath = "" lastPath = Path(lastPath)
else: if isinstance(lastPath, Path):
self.lastPath = os.path.dirname(lastPath) if lastPath.is_file():
self._lastPath = lastPath.parent
elif lastPath.is_dir():
self._lastPath = lastPath
return True return True
def setWinSize(self, newWidth, newHeight): def setWinSize(self, newWidth, newHeight):
+2 -2
View File
@@ -698,7 +698,7 @@ class GuiMain(QMainWindow):
logger.error("No project open") logger.error("No project open")
return False return False
lastPath = self.mainConf.lastPath lastPath = self.mainConf.getLastPath()
extFilter = [ extFilter = [
self.tr("Text files ({0})").format("*.txt"), self.tr("Text files ({0})").format("*.txt"),
self.tr("Markdown files ({0})").format("*.md"), self.tr("Markdown files ({0})").format("*.md"),
@@ -706,7 +706,7 @@ class GuiMain(QMainWindow):
self.tr("All files ({0})").format("*"), self.tr("All files ({0})").format("*"),
] ]
loadFile, _ = QFileDialog.getOpenFileName( loadFile, _ = QFileDialog.getOpenFileName(
self, self.tr("Import File"), lastPath, filter=";;".join(extFilter) self, self.tr("Import File"), str(lastPath), filter=";;".join(extFilter)
) )
if not loadFile: if not loadFile:
return False return False
+2 -7
View File
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
import os
import json import json
import logging import logging
import novelwriter import novelwriter
@@ -891,13 +890,9 @@ class GuiBuildNovel(QDialog):
cleanName = makeFileNameSafe(self.theProject.data.name) cleanName = makeFileNameSafe(self.theProject.data.name)
fileName = "%s.%s" % (cleanName, fileExt) fileName = "%s.%s" % (cleanName, fileExt)
saveDir = self.mainConf.lastPath savePath = self.mainConf.getLastPath() / fileName
if not os.path.isdir(saveDir):
saveDir = os.path.expanduser("~")
savePath = os.path.join(saveDir, fileName)
savePath, _ = QFileDialog.getSaveFileName( savePath, _ = QFileDialog.getSaveFileName(
self, self.tr("Save Document As"), savePath self, self.tr("Save Document As"), str(savePath)
) )
if not savePath: if not savePath:
return False return False
+2 -5
View File
@@ -236,12 +236,9 @@ class ProjWizardFolderPage(QWizardPage):
def _doBrowse(self): def _doBrowse(self):
"""Select a project folder. """Select a project folder.
""" """
lastPath = self.mainConf.lastPath lastPath = self.mainConf.getLastPath()
if not os.path.isdir(lastPath):
lastPath = ""
projDir = QFileDialog.getExistingDirectory( projDir = QFileDialog.getExistingDirectory(
self, self.tr("Select Project Folder"), lastPath, options=QFileDialog.ShowDirsOnly self, self.tr("Select Project Folder"), str(lastPath), options=QFileDialog.ShowDirsOnly
) )
if projDir: if projDir:
projName = self.field("projName") projName = self.field("projName")
+2 -9
View File
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
import os
import json import json
import logging import logging
import novelwriter import novelwriter
@@ -363,15 +362,9 @@ class GuiWritingStats(QDialog):
return False return False
# Generate the file name # Generate the file name
saveDir = self.mainConf.lastPath savePath = self.mainConf.getLastPath() / f"sessionStats.{fileExt}"
if not os.path.isdir(saveDir):
saveDir = os.path.expanduser("~")
fileName = "sessionStats.%s" % fileExt
savePath = os.path.join(saveDir, fileName)
savePath, _ = QFileDialog.getSaveFileName( savePath, _ = QFileDialog.getSaveFileName(
self, self.tr("Save Data As"), savePath, "%s (*.%s)" % (textFmt, fileExt) self, self.tr("Save Data As"), str(savePath), "%s (*.%s)" % (textFmt, fileExt)
) )
if not savePath: if not savePath:
return False return False
+5 -5
View File
@@ -166,7 +166,7 @@ def tmpConf(tmpPath):
confFile.unlink() confFile.unlink()
theConf = Config() theConf = Config()
theConf.initConfig(tmpPath, tmpPath) theConf.initConfig(tmpPath, tmpPath)
theConf.setLastPath("") theConf.setLastPath(tmpPath)
theConf.guiLang = "en_GB" theConf.guiLang = "en_GB"
return theConf return theConf
@@ -180,7 +180,7 @@ def fncConf(fncPath):
confFile.unlink() confFile.unlink()
theConf = Config() theConf = Config()
theConf.initConfig(fncPath, fncPath) theConf.initConfig(fncPath, fncPath)
theConf.setLastPath("") theConf.setLastPath(fncPath)
theConf.guiLang = "en_GB" theConf.guiLang = "en_GB"
return theConf return theConf
@@ -196,7 +196,7 @@ def mockGUI(monkeypatch, tmpConf):
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def nwGUI(qtbot, monkeypatch, fncDir, fncConf): def nwGUI(qtbot, monkeypatch, fncPath, fncConf):
"""Create an instance of the novelWriter GUI. """Create an instance of the novelWriter GUI.
""" """
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok) monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok)
@@ -205,12 +205,12 @@ def nwGUI(qtbot, monkeypatch, fncDir, fncConf):
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr("novelwriter.CONFIG", fncConf) monkeypatch.setattr("novelwriter.CONFIG", fncConf)
nwGUI = novelwriter.main(["--testmode", "--config=%s" % fncDir, "--data=%s" % fncDir]) nwGUI = novelwriter.main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
qtbot.addWidget(nwGUI) qtbot.addWidget(nwGUI)
nwGUI.show() nwGUI.show()
qtbot.wait(20) qtbot.wait(20)
nwGUI.mainConf.lastPath = fncDir nwGUI.mainConf.setLastPath(fncPath)
yield nwGUI yield nwGUI
+2 -1
View File
@@ -444,7 +444,8 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
assert tmpConf.confChanged is False assert tmpConf.confChanged is False
copyfile(confFile, testFile) copyfile(confFile, testFile)
assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang")) ignore = ("timestamp", "lastnotes", "guilang", "lastpath")
assert cmpFiles(testFile, compFile, ignoreStart=ignore)
# END Test testBaseConfig_SettersGetters # END Test testBaseConfig_SettersGetters
+2 -2
View File
@@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import pytest import pytest
from shutil import copyfile from shutil import copyfile
from tools import cmpFiles, getGuiItem from tools import cmpFiles, getGuiItem
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@@ -215,7 +216,6 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
nwPrefs._doClose() nwPrefs._doClose()
assert theConf.confChanged assert theConf.confChanged
theConf.lastPath = ""
assert nwGUI.mainConf.saveConfig() assert nwGUI.mainConf.saveConfig()
projFile = fncPath / "novelwriter.conf" projFile = fncPath / "novelwriter.conf"
@@ -225,7 +225,7 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
ignTuple = ( ignTuple = (
"timestamp", "guifont", "lastnotes", "guilang", "geometry", "timestamp", "guifont", "lastnotes", "guilang", "geometry",
"preferences", "projcols", "mainpane", "docpane", "viewpane", "preferences", "projcols", "mainpane", "docpane", "viewpane",
"outlinepane", "textfont", "textsize" "outlinepane", "textfont", "textsize", "lastpath"
) )
assert cmpFiles(testFile, compFile, ignoreStart=ignTuple) assert cmpFiles(testFile, compFile, ignoreStart=ignTuple)
@@ -38,7 +38,6 @@ def testDlgProjDetails_Dialog(qtbot, nwGUI, nwLipsum):
qtbot.wait(100) qtbot.wait(100)
# Open the Writing Stats dialog # Open the Writing Stats dialog
nwGUI.mainConf.lastPath = ""
nwGUI.mainMenu.aProjectDetails.activate(QAction.Trigger) nwGUI.mainMenu.aProjectDetails.activate(QAction.Trigger)
qtbot.waitUntil(lambda: getGuiItem("GuiProjectDetails") is not None, timeout=1000) qtbot.waitUntil(lambda: getGuiItem("GuiProjectDetails") is not None, timeout=1000)
-1
View File
@@ -156,7 +156,6 @@ def testGuiOutline_Content(qtbot, nwGUI, nwLipsum):
"""Test the outline view. """Test the outline view.
""" """
assert nwGUI.openProject(nwLipsum) assert nwGUI.openProject(nwLipsum)
nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex() nwGUI.rebuildIndex()
nwGUI._changeView(nwView.OUTLINE) nwGUI._changeView(nwView.OUTLINE)
+3 -9
View File
@@ -23,6 +23,8 @@ import pytest
import os import os
from shutil import copyfile from shutil import copyfile
from pathlib import Path
from tools import cmpFiles, getGuiItem from tools import cmpFiles, getGuiItem
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@@ -61,21 +63,13 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
# Invalid file format # Invalid file format
assert not nwBuild._saveDocument(-1) assert not nwBuild._saveDocument(-1)
# Non-existent path
with monkeypatch.context() as mp:
mp.setattr("os.path.expanduser", lambda *a, **k: nwLipsum)
assert nwGUI.mainConf.lastPath != nwLipsum
nwGUI.mainConf.lastPath = "no_such_path"
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
assert nwGUI.mainConf.lastPath == nwLipsum
# No path selected # No path selected
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getSaveFileName", lambda *a, **k: ("", "")) mp.setattr(QFileDialog, "getSaveFileName", lambda *a, **k: ("", ""))
assert not nwBuild._saveDocument(nwBuild.FMT_NWD) assert not nwBuild._saveDocument(nwBuild.FMT_NWD)
# Default Settings # Default Settings
nwGUI.mainConf.lastPath = nwLipsum nwGUI.mainConf._lastPath = Path(nwLipsum)
qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
assert nwBuild._saveDocument(nwBuild.FMT_NWD) assert nwBuild._saveDocument(nwBuild.FMT_NWD)
@@ -67,7 +67,6 @@ def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, fncProj):
# Test the Wizard Launching # Test the Wizard Launching
# ========================= # =========================
nwGUI.mainConf.lastPath = " "
monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None) monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None)
result = nwGUI.showNewProjectDialog() result = nwGUI.showNewProjectDialog()
@@ -102,7 +101,6 @@ def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncDir, prjType):
""" """
monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None) monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None)
nwGUI.mainConf.lastPath = " "
nwWiz = GuiProjectWizard(nwGUI) nwWiz = GuiProjectWizard(nwGUI)
nwWiz.show() nwWiz.show()
qtbot.addWidget(nwWiz) qtbot.addWidget(nwWiz)
@@ -44,7 +44,6 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
sessFile = os.path.join(fncProj, "meta", nwFiles.SESS_STATS) sessFile = os.path.join(fncProj, "meta", nwFiles.SESS_STATS)
# Open the Writing Stats dialog # Open the Writing Stats dialog
nwGUI.mainConf.lastPath = ""
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger) nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger)
qtbot.waitUntil(lambda: getGuiItem("GuiWritingStats") is not None, timeout=1000) qtbot.waitUntil(lambda: getGuiItem("GuiWritingStats") is not None, timeout=1000)
@@ -135,8 +134,6 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
assert sessLog._saveData(sessLog.FMT_JSON) assert sessLog._saveData(sessLog.FMT_JSON)
qtbot.wait(100) qtbot.wait(100)
assert nwGUI.mainConf.lastPath == fncDir
# Check the exported files # Check the exported files
jsonStats = os.path.join(fncDir, "sessionStats.json") jsonStats = os.path.join(fncDir, "sessionStats.json")
with open(jsonStats, mode="r", encoding="utf-8") as inFile: with open(jsonStats, mode="r", encoding="utf-8") as inFile: