From 6d7ca2bb86d4ec3741a2ff0e023ab5eb6449a033 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 4 Jul 2021 17:57:54 +0200
Subject: [PATCH] Cleanup (#820)
* Update instructions and readmes
* Cleanup in base files
* Cleanup in core files
* Cleanup in gui files
* Cleanup in dialog files
* Cleanup in tools files
* Cleanup in test files
---
CONTRIBUTING.md | 6 +-
README.md | 3 +-
i18n/README.md | 12 +-
nw/__init__.py | 18 +--
nw/common.py | 2 +-
nw/config.py | 24 ++--
nw/core/document.py | 4 +-
nw/core/index.py | 30 ++---
nw/core/options.py | 6 +-
nw/core/project.py | 35 +++--
nw/core/spellcheck.py | 3 +-
nw/core/status.py | 22 ++--
nw/core/tohtml.py | 8 +-
nw/core/tokenizer.py | 38 +++---
nw/core/tomd.py | 22 ++--
nw/core/tree.py | 6 +-
nw/dialogs/about.py | 8 +-
nw/dialogs/itemeditor.py | 4 +-
nw/dialogs/preferences.py | 18 +--
nw/dialogs/projload.py | 8 +-
nw/dialogs/projsettings.py | 8 +-
nw/dialogs/wordlist.py | 6 +-
nw/enum.py | 10 +-
nw/gui/custom.py | 27 ++--
nw/gui/doceditor.py | 68 +++++-----
nw/gui/docviewer.py | 8 +-
nw/gui/mainmenu.py | 34 +++--
nw/gui/noveltree.py | 10 +-
nw/gui/outline.py | 174 +++++++++++++------------
nw/gui/outlinedetails.py | 6 +-
nw/gui/projdetails.py | 10 +-
nw/gui/projtree.py | 4 +-
nw/gui/statusbar.py | 8 +-
nw/gui/theme.py | 18 +--
nw/guimain.py | 53 ++++----
nw/tools/build.py | 50 ++++---
nw/tools/projwizard.py | 2 +-
nw/tools/writingstats.py | 18 +--
tests/conftest.py | 2 +-
tests/test_core/test_core_document.py | 45 +++----
tests/test_core/test_core_index.py | 36 ++---
tests/test_core/test_core_item.py | 20 +--
tests/test_core/test_core_options.py | 36 ++---
tests/test_core/test_core_project.py | 115 ++++++++--------
tests/test_core/test_core_tohtml.py | 20 +--
tests/test_core/test_core_tokenizer.py | 16 +--
tests/test_core/test_core_toodt.py | 6 +-
tests/test_core/test_core_tree.py | 61 ++++-----
tests/test_gui/test_gui_mainmenu.py | 5 +-
tests/test_gui/test_gui_outline.py | 2 +-
tests/tools.py | 8 +-
51 files changed, 583 insertions(+), 580 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9123e7ab..e8b618a8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,8 +22,12 @@ either `testing` or `dev` branch.
### What Branch to Use for Contributions
* If your contribution is a fix for the latest stable release, branch from the `main` branch.
-* If your contribution is a fix for the latest testing release, branch from the `testing` branch.
* If your contribution is a new feature, branch from the `dev` branch.
+* The `testing` branch is used infrequently. It is only used for pre-releases when new code is
+ being developed that is not a part of the current testing release.
+
+The current status of each branch is described in a pinned issue titled
+"[Development Flow & Status](https://github.com/vkbo/novelWriter/issues/707)".
Please do not make your changes on a branch with the same name as any of the above mentioned
branches. You should make a unique and descriptive branch name in your fork for your changes.
diff --git a/README.md b/README.md
index 55d74763..60c9de65 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@ In addition, novelWriter adds the following syntax used for its additional featu
be used to make simple tables and lists. Note that for HTML exports, most browsers will treat a
tab as a space, so it may not show up like expected. Open Document exports should produce the
expected result.
+* Paragraph alignment and indendtation is supported by a set of tags using `>` and `<` markers.
The core export formats of novelWriter are Open Document and HTML5. Open Document is an open
standard for office type documents that is supported by most office applications. See
@@ -105,7 +106,7 @@ four can be used internally in each scene to create separate sections.
Each novel file can be assigned a layout format, which shows up as a flag next to the item in the
project tree. These are mostly to help the user track what they contain, but they also have some
-impact on the format of the exported document. See the
+impact on the layout of the exported document. See the
[documentation](https://novelwriter.readthedocs.io) for further details.
### Project Notes
diff --git a/i18n/README.md b/i18n/README.md
index 9d206a5f..73d71932 100644
--- a/i18n/README.md
+++ b/i18n/README.md
@@ -3,14 +3,14 @@
The `i18n` folder contains the translation files for the Qt5 GUI. There are two types of files
involved: the `nw_XX.ts` and the `nw_XX.qm` files. The `nw_XX.ts` files are located in the `i18n`
folder at the root of the repository, and the `nw_XX.qm` together with the `project_XX.json` files
-are located in `nw/assets/i18n`. The latter are JSON files translation maps for the novelWriter
-projects, used by the Build Novel Project tool.
+are located in `nw/assets/i18n`. The latter are JSON translation maps for the novelWriter projects,
+used by the Build Novel Project tool.
**Note**
When making a new translation, or updating an existing one, only commit the `nw_XX.ts` you have
made changes to. The `qtlupdate` command mentioned below will likely modify all `nw_XX.ts`
-slightly, but please _don't_ commit those changes and add them to the pull request.
+slightly, but please _don't_ commit those changes to the pull request.
## Qt GUI Localisation
@@ -39,8 +39,8 @@ When you're done editing, you can build the `nw/assets/i18n/nw_XX.qm` file and t
novelWriter. The Preferences dialog should list the newly added language, and you can select it and
test it.
-Please do not submit the `.qm` files to the repository. Only the `.ts` files in the `i18n` folder
-are needed.
+Please do not submit the `.qm` files to the repository. Only the `.ts` file you just added in the
+`i18n` folder is needed.
**Note**
@@ -54,7 +54,7 @@ sudo apt install qttools5-dev-tools pyqt5-dev-tools
### Missing QtBase Translations
-The default Qt dialogs also have translations, for instance for standard buttons for "Yes", "No",
+The default Qt dialogs also have translations, for instance for standard buttons like "Yes", "No",
"Ok", "Cancel", etc. Generally, these translations files are installed with the Qt libraries on
your system, and novelWriter will collect those translations from there. However, these
translations are missing for many languages.
diff --git a/nw/__init__.py b/nw/__init__.py
index f6458ae9..8be259e5 100644
--- a/nw/__init__.py
+++ b/nw/__init__.py
@@ -39,9 +39,9 @@ from nw.config import Config
# Generally follows PEP 440
# Hex Version:
# - Digit 1,2 : Major Version (01-ff)
-# = Digit 3,4 : Minor Version (01-ff)
+# - Digit 3,4 : Minor Version (01-ff)
# - Digit 5,6 : Patch Version (01-ff)
-# = Digit 7 : Release Type (a: aplha, b: beta, c: candidate, f: final)
+# - Digit 7 : Release Type (a: aplha, b: beta, c: candidate, f: final)
# - Digit 8 : Release Number (0-f)
#
# Example : Full Short Description
@@ -111,7 +111,7 @@ CONFIG = Config()
def main(sysArgs=None):
- """Parses command line, sets up logging, and launches main GUI.
+ """Parse command line, set up logging, and launches main GUI.
"""
if sysArgs is None:
sysArgs = sys.argv[1:]
@@ -155,13 +155,13 @@ def main(sysArgs=None):
)
# Defaults
- logLevel = logging.WARN
+ logLevel = logging.WARN
logFormat = "{levelname:8} {message:}"
- confPath = None
- dataPath = None
- testMode = False
- qtStyle = "Fusion"
- cmdOpen = None
+ confPath = None
+ dataPath = None
+ testMode = False
+ qtStyle = "Fusion"
+ cmdOpen = None
# Parse Options
try:
diff --git a/nw/common.py b/nw/common.py
index 3def0edd..daa2b32d 100644
--- a/nw/common.py
+++ b/nw/common.py
@@ -208,7 +208,7 @@ def splitVersionNumber(vString):
vMajor = 0
vMinor = 0
vPatch = 0
- vInt = 0
+ vInt = 0
vBits = vString.split(".")
nBits = len(vBits)
diff --git a/nw/config.py b/nw/config.py
index b076860f..faabe6ae 100644
--- a/nw/config.py
+++ b/nw/config.py
@@ -23,12 +23,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+import os
+import sys
+import json
+import shutil
import logging
import configparser
-import shutil
-import json
-import sys
-import os
from time import time
@@ -433,9 +433,9 @@ class Config:
return False
cnfParse = configparser.ConfigParser()
- cnfPath = os.path.join(self.confPath, self.confFile)
+ cnfPath = os.path.join(self.confPath, self.confFile)
try:
- with open(cnfPath, mode="r", encoding="utf8") as inFile:
+ with open(cnfPath, mode="r", encoding="utf-8") as inFile:
cnfParse.read_file(inFile)
except Exception as e:
logger.error("Could not load config file")
@@ -807,7 +807,7 @@ class Config:
# Write config file
cnfPath = os.path.join(self.confPath, self.confFile)
try:
- with open(cnfPath, mode="w", encoding="utf8") as outFile:
+ with open(cnfPath, mode="w", encoding="utf-8") as outFile:
cnfParse.write(outFile)
self.confChanged = False
except Exception as e:
@@ -831,13 +831,13 @@ class Config:
if os.path.isfile(cacheFile):
try:
- with open(cacheFile, mode="r", encoding="utf8") as inFile:
+ with open(cacheFile, mode="r", encoding="utf-8") as inFile:
theData = json.load(inFile)
for projPath in theData.keys():
- theEntry = theData[projPath]
- theTitle = ""
- lastTime = 0
+ theEntry = theData[projPath]
+ theTitle = ""
+ lastTime = 0
wordCount = 0
if "title" in theEntry.keys():
theTitle = theEntry["title"]
@@ -869,7 +869,7 @@ class Config:
cacheTemp = os.path.join(self.dataPath, nwFiles.RECENT_FILE+"~")
try:
- with open(cacheTemp, mode="w+", encoding="utf8") as outFile:
+ with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
json.dump(self.recentProj, outFile, indent=2)
except Exception as e:
self.hasError = True
diff --git a/nw/core/document.py b/nw/core/document.py
index 8093bb75..7ec2d6c6 100644
--- a/nw/core/document.py
+++ b/nw/core/document.py
@@ -82,7 +82,7 @@ class NWDoc():
self._docMeta = {}
if os.path.isfile(docPath):
try:
- with open(docPath, mode="r", encoding="utf8") as inFile:
+ with open(docPath, mode="r", encoding="utf-8") as inFile:
# Check the first <= 10 lines for metadata
for i in range(10):
@@ -136,7 +136,7 @@ class NWDoc():
)
try:
- with open(docTemp, mode="w", encoding="utf8") as outFile:
+ with open(docTemp, mode="w", encoding="utf-8") as outFile:
outFile.write(docMeta)
outFile.write(docText)
except Exception as e:
diff --git a/nw/core/index.py b/nw/core/index.py
index c7d7a432..01bdb69d 100644
--- a/nw/core/index.py
+++ b/nw/core/index.py
@@ -144,13 +144,13 @@ class NWIndex():
def loadIndex(self):
"""Load index from last session from the project meta folder.
"""
- theData = {}
+ theData = {}
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
if os.path.isfile(indexFile):
logger.debug("Loading index file")
try:
- with open(indexFile, mode="r", encoding="utf8") as inFile:
+ with open(indexFile, mode="r", encoding="utf-8") as inFile:
theData = json.load(inFile)
except Exception:
logger.error("Failed to load index file")
@@ -158,10 +158,10 @@ class NWIndex():
self.indexBroken = True
return False
- self._tagIndex = theData.get("tagIndex", {})
- self._refIndex = theData.get("refIndex", {})
+ self._tagIndex = theData.get("tagIndex", {})
+ self._refIndex = theData.get("refIndex", {})
self._novelIndex = theData.get("novelIndex", {})
- self._noteIndex = theData.get("noteIndex", {})
+ self._noteIndex = theData.get("noteIndex", {})
self._textCounts = theData.get("textCounts", {})
nowTime = round(time())
@@ -181,12 +181,12 @@ class NWIndex():
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
try:
- with open(indexFile, mode="w+", encoding="utf8") as outFile:
+ with open(indexFile, mode="w+", encoding="utf-8") as outFile:
json.dump({
- "tagIndex": self._tagIndex,
- "refIndex": self._refIndex,
+ "tagIndex": self._tagIndex,
+ "refIndex": self._refIndex,
"novelIndex": self._novelIndex,
- "noteIndex": self._noteIndex,
+ "noteIndex": self._noteIndex,
"textCounts": self._textCounts,
}, outFile, indent=2)
except Exception:
@@ -292,12 +292,12 @@ class NWIndex():
for aTag in clearTags:
self._tagIndex.pop(aTag)
- nLine = 0
+ nLine = 0
nTitle = 0
theLines = theText.splitlines()
for aLine in theLines:
nLine += 1
- nChar = len(aLine.strip())
+ nChar = len(aLine.strip())
if nChar == 0:
continue
@@ -352,16 +352,16 @@ class NWIndex():
"""
if aLine.startswith("# "):
hDepth = "H1"
- hText = aLine[2:].strip()
+ hText = aLine[2:].strip()
elif aLine.startswith("## "):
hDepth = "H2"
- hText = aLine[3:].strip()
+ hText = aLine[3:].strip()
elif aLine.startswith("### "):
hDepth = "H3"
- hText = aLine[4:].strip()
+ hText = aLine[4:].strip()
elif aLine.startswith("#### "):
hDepth = "H4"
- hText = aLine[5:].strip()
+ hText = aLine[5:].strip()
else:
return False
diff --git a/nw/core/options.py b/nw/core/options.py
index f89146c0..a32bf3f2 100644
--- a/nw/core/options.py
+++ b/nw/core/options.py
@@ -125,12 +125,12 @@ class OptionState():
return False
stateFile = os.path.join(self.theProject.projMeta, nwFiles.OPTS_FILE)
- theState = {}
+ theState = {}
if os.path.isfile(stateFile):
logger.debug("Loading GUI options file")
try:
- with open(stateFile, mode="r", encoding="utf8") as inFile:
+ with open(stateFile, mode="r", encoding="utf-8") as inFile:
theState = json.load(inFile)
except Exception:
logger.error("Failed to load GUI options file")
@@ -157,7 +157,7 @@ class OptionState():
logger.debug("Saving GUI options file")
try:
- with open(stateFile, mode="w+", encoding="utf8") as outFile:
+ with open(stateFile, mode="w+", encoding="utf-8") as outFile:
json.dump(self.theState, outFile, indent=2)
except Exception:
logger.error("Failed to save GUI options file")
diff --git a/nw/core/project.py b/nw/core/project.py
index 3a73fd03..752178af 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -355,7 +355,7 @@ class NWProject():
def openProject(self, fileName, overrideLock=False):
"""Open the project file provided, or if doesn't exist, assume
- it is a folder, and look for the file within it. If successful,
+ it is a folder and look for the file within it. If successful,
parse the XML of the file and populate the project variables and
build the tree of project items.
"""
@@ -483,10 +483,11 @@ class NWProject():
msgYes = self.theParent.askQuestion(
self.tr("Version Conflict"),
self.tr(
- "This project was saved by a newer version of novelWriter, version "
- "{0}. This is version {1}. If you continue to open the project, "
- "some attributes and settings may not be preserved, but the "
- "overall project should be fine. Continue opening the project?"
+ "This project was saved by a newer version of "
+ "novelWriter, version {0}. This is version {1}. If you "
+ "continue to open the project, some attributes and "
+ "settings may not be preserved, but the overall project "
+ "should be fine. Continue opening the project?"
).format(appVersion, nw.__version__)
)
if not msgYes:
@@ -1219,7 +1220,7 @@ class NWProject():
loadFile = chkFile2
try:
- with open(loadFile, mode="r", encoding="utf8") as inFile:
+ with open(loadFile, mode="r", encoding="utf-8") as inFile:
self.langData = json.load(inFile)
logger.debug("Loaded project language file: %s", os.path.basename(loadFile))
@@ -1242,7 +1243,7 @@ class NWProject():
theLines = []
try:
- with open(lockFile, mode="r", encoding="utf8") as inFile:
+ with open(lockFile, mode="r", encoding="utf-8") as inFile:
theData = inFile.read()
theLines = theData.splitlines()
if len(theLines) != 4:
@@ -1263,7 +1264,7 @@ class NWProject():
lockFile = os.path.join(self.projPath, nwFiles.PROJ_LOCK)
try:
- with open(lockFile, mode="w+", encoding="utf8") as outFile:
+ with open(lockFile, mode="w+", encoding="utf-8") as outFile:
outFile.write("%s\n" % self.mainConf.hostName)
outFile.write("%s\n" % self.mainConf.osType)
outFile.write("%s\n" % self.mainConf.kernelVer)
@@ -1442,7 +1443,7 @@ class NWProject():
return False
try:
- with open(sessionFile, mode="a+", encoding="utf8") as outFile:
+ with open(sessionFile, mode="a+", encoding="utf-8") as outFile:
if not isFile:
# It's a new file, so add a header
if self.lastWCount > 0:
@@ -1481,7 +1482,6 @@ class NWProject():
logger.info("Old data folder %s found", theFolder)
# Move Documents to Content
- # =========================
for dataItem in os.listdir(theData):
theFile = os.path.join(theData, dataItem)
if not os.path.isfile(theFile):
@@ -1517,7 +1517,6 @@ class NWProject():
errList.append(theErr)
# Remove Data Folder
- # ==================
try:
os.rmdir(theData)
logger.info("Deleted folder: %s", theFolder)
@@ -1563,13 +1562,13 @@ class NWProject():
os.path.join(self.projCache, "nwProject.nwx.7"),
os.path.join(self.projCache, "nwProject.nwx.8"),
os.path.join(self.projCache, "nwProject.nwx.9"),
- os.path.join(self.projMeta, "mainOptions.json"),
- os.path.join(self.projMeta, "exportOptions.json"),
- os.path.join(self.projMeta, "outlineOptions.json"),
- os.path.join(self.projMeta, "timelineOptions.json"),
- os.path.join(self.projMeta, "docMergeOptions.json"),
- os.path.join(self.projMeta, "sessionLogOptions.json"),
- os.path.join(self.projPath, "ToC.json"),
+ os.path.join(self.projMeta, "mainOptions.json"),
+ os.path.join(self.projMeta, "exportOptions.json"),
+ os.path.join(self.projMeta, "outlineOptions.json"),
+ os.path.join(self.projMeta, "timelineOptions.json"),
+ os.path.join(self.projMeta, "docMergeOptions.json"),
+ os.path.join(self.projMeta, "sessionLogOptions.json"),
+ os.path.join(self.projPath, "ToC.json"),
]
for rmFile in rmList:
diff --git a/nw/core/spellcheck.py b/nw/core/spellcheck.py
index b24d027f..455b8f4c 100644
--- a/nw/core/spellcheck.py
+++ b/nw/core/spellcheck.py
@@ -235,8 +235,7 @@ class FakeEnchant:
class NWSpellSimple(NWSpellCheck):
"""Internal spell check tool that uses standard Python packages with
no other external dependencies. This is the fallback spell checker
- when no other is available. This method is fairly slow compared to
- other implementations.
+ when no other is available. This method is slower than enchant.
"""
theWords = set()
diff --git a/nw/core/status.py b/nw/core/status.py
index f2f00fe8..57e56bd1 100644
--- a/nw/core/status.py
+++ b/nw/core/status.py
@@ -35,12 +35,14 @@ logger = logging.getLogger(__name__)
class NWStatus():
def __init__(self):
- self._theLabels = []
+
+ self._theLabels = []
self._theColours = []
- self._theCounts = []
- self._theMap = {}
- self._theLength = 0
- self._theIndex = 0
+ self._theCounts = []
+ self._theMap = {}
+ self._theLength = 0
+ self._theIndex = 0
+
return
def addEntry(self, theLabel, theColours):
@@ -87,12 +89,12 @@ class NWStatus():
replaceMap = {}
if newList is not None:
- self._theLabels = []
+ self._theLabels = []
self._theColours = []
- self._theCounts = []
- self._theMap = {}
- self._theLength = 0
- self._theIndex = 0
+ self._theCounts = []
+ self._theMap = {}
+ self._theLength = 0
+ self._theIndex = 0
for nName, nR, nG, nB, oName in newList:
self.addEntry(nName, (nR, nG, nB))
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index d4a7b13c..7ce843ec 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -40,9 +40,9 @@ class ToHtml(Tokenizer):
def __init__(self, theProject):
Tokenizer.__init__(self, theProject)
- self.genMode = self.M_EXPORT
+ self.genMode = self.M_EXPORT
self.cssStyles = True
- self.fullHTML = []
+ self.fullHTML = []
# Internals
self._trMap = {}
@@ -59,7 +59,7 @@ class ToHtml(Tokenizer):
need to make a few changes to formatting, which is managed by
these flags.
"""
- self.genMode = self.M_PREVIEW
+ self.genMode = self.M_PREVIEW
self.doKeywords = True
self.doComments = doComments
self.doSynopsis = doSynopsis
@@ -268,7 +268,7 @@ class ToHtml(Tokenizer):
def saveHTML5(self, savePath):
"""Save the data to an .html file.
"""
- with open(savePath, mode="w", encoding="utf8") as outFile:
+ with open(savePath, mode="w", encoding="utf-8") as outFile:
theStyle = self.getStyleSheet()
theStyle.append("article {width: 800px; margin: 40px auto;}")
bodyText = "".join(self.fullHTML)
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index 1ab56072..daa8021b 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -24,8 +24,8 @@ along with this program. If not, see .
"""
import nw
-import logging
import re
+import logging
from operator import itemgetter
from functools import partial
@@ -43,12 +43,12 @@ logger = logging.getLogger(__name__)
class Tokenizer():
# In-Text Format
- FMT_B_B = 1 # Begin bold
- FMT_B_E = 2 # End bold
- FMT_I_B = 3 # Begin italics
- FMT_I_E = 4 # End italics
- FMT_D_B = 5 # Begin strikeout
- FMT_D_E = 6 # End strikeout
+ FMT_B_B = 1 # Begin bold
+ FMT_B_E = 2 # End bold
+ FMT_I_B = 3 # Begin italics
+ FMT_I_E = 4 # End italics
+ FMT_D_B = 5 # Begin strikeout
+ FMT_D_E = 6 # End strikeout
# Block Type
T_EMPTY = 1 # Empty line (new paragraph)
@@ -86,11 +86,11 @@ class Tokenizer():
self.mainConf = nw.CONFIG
# Data Variables
- self.theText = "" # The raw text to be tokenized
- self.theHandle = None # The handle associated with the text
- self.theItem = None # The NWItem associated with the handle
- self.theTokens = [] # The list of the processed tokens
- self.theResult = "" # The result of the last document
+ self.theText = "" # The raw text to be tokenized
+ self.theHandle = None # The handle associated with the text
+ self.theItem = None # The NWItem associated with the handle
+ self.theTokens = [] # The list of the processed tokens
+ self.theResult = "" # The result of the last document
self.keepMarkdown = False # Whether to keep the markdown text
self.theMarkdown = [] # The result novelWriter markdown of all documents
@@ -117,11 +117,11 @@ class Tokenizer():
self.marginMeta = (0.000, 0.584)
# Title Formats
- self.fmtTitle = "%title%" # Formatting for titles
- self.fmtChapter = "%title%" # Formatting for numbered chapters
- self.fmtUnNum = "%title%" # Formatting for unnumbered chapters
- self.fmtScene = "%title%" # Formatting for scenes
- self.fmtSection = "%title%" # Formatting for sections
+ self.fmtTitle = "%title%" # Formatting for titles
+ self.fmtChapter = "%title%" # Formatting for numbered chapters
+ self.fmtUnNum = "%title%" # Formatting for unnumbered chapters
+ self.fmtScene = "%title%" # Formatting for scenes
+ self.fmtSection = "%title%" # Formatting for sections
self.hideScene = False # Do not include scene headers
self.hideSection = False # Do not include section headers
@@ -320,7 +320,7 @@ class Tokenizer():
return True
def doPreProcessing(self):
- """Reun trough the various replace doctionaries.
+ """Run trough the various replace doctionaries.
"""
# Process the user's auto-replace dictionary
if len(self.theProject.autoReplace) > 0:
@@ -701,7 +701,7 @@ class Tokenizer():
def saveRawMarkdown(self, savePath):
"""Save the data to a plain text file.
"""
- with open(savePath, mode="w", encoding="utf8") as outFile:
+ with open(savePath, mode="w", encoding="utf-8") as outFile:
for nwdPage in self.theMarkdown:
outFile.write(nwdPage)
return
diff --git a/nw/core/tomd.py b/nw/core/tomd.py
index 580640ae..896f17d5 100644
--- a/nw/core/tomd.py
+++ b/nw/core/tomd.py
@@ -72,16 +72,22 @@ class ToMarkdown(Tokenizer):
if self.genMode == self.M_STD:
# Standard
mdTags = {
- self.FMT_B_B: "**", self.FMT_B_E: "**",
- self.FMT_I_B: "_", self.FMT_I_E: "_",
- self.FMT_D_B: "", self.FMT_D_E: "",
+ self.FMT_B_B: "**",
+ self.FMT_B_E: "**",
+ self.FMT_I_B: "_",
+ self.FMT_I_E: "_",
+ self.FMT_D_B: "",
+ self.FMT_D_E: "",
}
else:
# GitHub
mdTags = {
- self.FMT_B_B: "**", self.FMT_B_E: "**",
- self.FMT_I_B: "_", self.FMT_I_E: "_",
- self.FMT_D_B: "~~", self.FMT_D_E: "~~",
+ self.FMT_B_B: "**",
+ self.FMT_B_E: "**",
+ self.FMT_I_B: "_",
+ self.FMT_I_E: "_",
+ self.FMT_D_B: "~~",
+ self.FMT_D_E: "~~",
}
self.theResult = ""
@@ -149,7 +155,7 @@ class ToMarkdown(Tokenizer):
def saveMarkdown(self, savePath):
"""Save the data to a plain text file.
"""
- with open(savePath, mode="w", encoding="utf8") as outFile:
+ with open(savePath, mode="w", encoding="utf-8") as outFile:
theText = "".join(self.fullMD)
outFile.write(theText)
@@ -173,7 +179,7 @@ class ToMarkdown(Tokenizer):
def _formatKeywords(self, tText, tStyle):
"""Apply Markdown formatting to keywords.
"""
- isValid, theBits, thePos = self.theParent.theIndex.scanThis("@"+tText)
+ isValid, theBits, _ = self.theParent.theIndex.scanThis("@"+tText)
if not isValid or not theBits:
return ""
diff --git a/nw/core/tree.py b/nw/core/tree.py
index 9539c986..ebf91d77 100644
--- a/nw/core/tree.py
+++ b/nw/core/tree.py
@@ -24,11 +24,11 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
-from lxml import etree
from time import time
+from lxml import etree
from hashlib import sha256
from nw.enum import nwItemType, nwItemClass, nwItemLayout
@@ -193,7 +193,7 @@ class NWTree():
try:
# Dump the text
tocText = os.path.join(self.theProject.projPath, nwFiles.TOC_TXT)
- with open(tocText, mode="w", encoding="utf8") as outFile:
+ with open(tocText, mode="w", encoding="utf-8") as outFile:
outFile.write("\n")
outFile.write("Table of Contents\n")
outFile.write("=================\n")
diff --git a/nw/dialogs/about.py b/nw/dialogs/about.py
index 0c8a3c25..b3763026 100644
--- a/nw/dialogs/about.py
+++ b/nw/dialogs/about.py
@@ -24,13 +24,13 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
from datetime import datetime
-from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
+from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QTabWidget,
QTextBrowser, QLabel
@@ -229,7 +229,7 @@ class GuiAbout(QDialog):
"""
docPath = os.path.join(self.mainConf.assetPath, "text", "release_notes.htm")
if os.path.isfile(docPath):
- with open(docPath, mode="r", encoding="utf8") as inFile:
+ with open(docPath, mode="r", encoding="utf-8") as inFile:
helpText = inFile.read()
self.pageNotes.setHtml(helpText)
else:
@@ -241,7 +241,7 @@ class GuiAbout(QDialog):
"""
docPath = os.path.join(self.mainConf.assetPath, "text", "gplv3_en.htm")
if os.path.isfile(docPath):
- with open(docPath, mode="r", encoding="utf8") as inFile:
+ with open(docPath, mode="r", encoding="utf-8") as inFile:
helpText = inFile.read()
self.pageLicense.setHtml(helpText)
else:
diff --git a/nw/dialogs/itemeditor.py b/nw/dialogs/itemeditor.py
index ca27e5ca..46258a82 100644
--- a/nw/dialogs/itemeditor.py
+++ b/nw/dialogs/itemeditor.py
@@ -137,7 +137,7 @@ class GuiItemEditor(QDialog):
# Assemble
##
- nameLabel = QLabel(self.tr("Label"))
+ nameLabel = QLabel(self.tr("Label"))
statusLabel = QLabel(self.tr("Status"))
layoutLabel = QLabel(self.tr("Layout"))
@@ -179,7 +179,7 @@ class GuiItemEditor(QDialog):
"""
logger.verbose("ItemEditor save button clicked")
- itemName = self.editName.text()
+ itemName = self.editName.text()
itemStatus = self.editStatus.currentData()
itemLayout = self.editLayout.currentData()
isExported = self.editExport.isChecked()
diff --git a/nw/dialogs/preferences.py b/nw/dialogs/preferences.py
index e68cd158..c9a24c11 100644
--- a/nw/dialogs/preferences.py
+++ b/nw/dialogs/preferences.py
@@ -24,11 +24,11 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
-from PyQt5.QtCore import Qt, QLocale
from PyQt5.QtGui import QFont
+from PyQt5.QtCore import Qt, QLocale
from PyQt5.QtWidgets import (
QDialog, QWidget, QComboBox, QSpinBox, QPushButton, QDialogButtonBox,
QLineEdit, QFileDialog, QFontDialog, QDoubleSpinBox
@@ -127,7 +127,7 @@ class GuiPreferences(PagedDialog):
def _saveWindowSize(self):
"""Save the dialog window size.
"""
- winWidth = self.mainConf.rpxInt(self.width())
+ winWidth = self.mainConf.rpxInt(self.width())
winHeight = self.mainConf.rpxInt(self.height())
self.mainConf.setPreferencesSize(winWidth, winHeight)
return
@@ -272,12 +272,12 @@ class GuiPreferencesGeneral(QWidget):
def saveValues(self):
"""Save the values set for this tab.
"""
- guiLang = self.guiLang.currentData()
- guiTheme = self.guiTheme.currentData()
- guiIcons = self.guiIcons.currentData()
- guiDark = self.guiDark.isChecked()
- guiFont = self.guiFont.text()
- guiFontSize = self.guiFontSize.value()
+ guiLang = self.guiLang.currentData()
+ guiTheme = self.guiTheme.currentData()
+ guiIcons = self.guiIcons.currentData()
+ guiDark = self.guiDark.isChecked()
+ guiFont = self.guiFont.text()
+ guiFontSize = self.guiFontSize.value()
# Check if restart is needed
needsRestart = False
diff --git a/nw/dialogs/projload.py b/nw/dialogs/projload.py
index f1d3a599..d7df41c6 100644
--- a/nw/dialogs/projload.py
+++ b/nw/dialogs/projload.py
@@ -24,13 +24,13 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
from datetime import datetime
-from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QKeySequence
+from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (
QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QPushButton, QTreeWidget,
QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel, QShortcut,
@@ -105,8 +105,8 @@ class GuiProjectLoad(QDialog):
treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
self.lblRecent = QLabel("%s" % self.tr("Recently Opened Projects"))
- self.lblPath = QLabel("%s" % self.tr("Path"))
- self.selPath = QLineEdit("")
+ self.lblPath = QLabel("%s" % self.tr("Path"))
+ self.selPath = QLineEdit("")
self.selPath.setReadOnly(True)
self.browseButton = QPushButton("...")
diff --git a/nw/dialogs/projsettings.py b/nw/dialogs/projsettings.py
index edf84806..5e3e8caa 100644
--- a/nw/dialogs/projsettings.py
+++ b/nw/dialogs/projsettings.py
@@ -26,8 +26,8 @@ along with this program. If not, see .
import nw
import logging
-from PyQt5.QtCore import Qt, QLocale
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush
+from PyQt5.QtCore import Qt, QLocale
from PyQt5.QtWidgets import (
QHBoxLayout, QVBoxLayout, QLineEdit, QPlainTextEdit, QLabel, QWidget,
QDialogButtonBox, QPushButton, QColorDialog, QTreeWidget, QTreeWidgetItem,
@@ -393,7 +393,7 @@ class GuiProjectEditStatus(QWidget):
"""
selItem = self._getSelectedItem()
if selItem is not None:
- iRow = self.listBox.indexOfTopLevelItem(selItem)
+ iRow = self.listBox.indexOfTopLevelItem(selItem)
selIdx = selItem.data(self.COL_LABEL, Qt.UserRole)
if self.colCounts[selIdx] == 0:
self.listBox.takeTopLevelItem(iRow)
@@ -626,8 +626,8 @@ class GuiProjectEditReplace(QWidget):
if selItem is None:
return False
- newKey = self.editKey.text()
- newVal = self.editValue.text()
+ newKey = self.editKey.text()
+ newVal = self.editValue.text()
saveKey = self._stripNotAllowed(newKey)
if len(saveKey) > 0 and len(newVal) > 0:
diff --git a/nw/dialogs/wordlist.py b/nw/dialogs/wordlist.py
index e328ecf2..4b05590c 100644
--- a/nw/dialogs/wordlist.py
+++ b/nw/dialogs/wordlist.py
@@ -24,8 +24,8 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
@@ -155,7 +155,7 @@ class GuiWordList(QDialog):
tmpFile = dctFile + "~"
try:
- with open(tmpFile, mode="w", encoding="utf8") as outFile:
+ with open(tmpFile, mode="w", encoding="utf-8") as outFile:
for i in range(self.listBox.count()):
outFile.write(self.listBox.item(i).text() + "\n")
@@ -193,7 +193,7 @@ class GuiWordList(QDialog):
logger.debug("No project dictionary file found")
return False
- with open(wordList, mode="r", encoding="utf8") as inFile:
+ with open(wordList, mode="r", encoding="utf-8") as inFile:
for inLine in inFile:
theWord = inLine.strip()
if len(theWord) == 0:
diff --git a/nw/enum.py b/nw/enum.py
index c0db68a4..0e22315e 100644
--- a/nw/enum.py
+++ b/nw/enum.py
@@ -104,11 +104,11 @@ class nwDocAction(Enum):
class nwDocInsert(Enum):
- NO_INSERT = 0
- QUOTE_LS = 1
- QUOTE_RS = 2
- QUOTE_LD = 3
- QUOTE_RD = 4
+ NO_INSERT = 0
+ QUOTE_LS = 1
+ QUOTE_RS = 2
+ QUOTE_LD = 3
+ QUOTE_RD = 4
# END Enum nwDocInsert
diff --git a/nw/gui/custom.py b/nw/gui/custom.py
index 89045e6b..2a0e3407 100644
--- a/nw/gui/custom.py
+++ b/nw/gui/custom.py
@@ -311,13 +311,13 @@ class QSwitch(QAbstractButton):
if self.isChecked():
trackBrush = qPalette.highlight()
thumbBrush = qPalette.highlightedText()
- textColor = qPalette.highlight().color()
- thumbText = nwUnicode.U_CHECK
+ textColor = qPalette.highlight().color()
+ thumbText = nwUnicode.U_CHECK
else:
trackBrush = qPalette.dark()
thumbBrush = qPalette.light()
- textColor = qPalette.dark().color()
- thumbText = nwUnicode.U_CROSS
+ textColor = qPalette.dark().color()
+ thumbText = nwUnicode.U_CROSS
if self.isEnabled():
trackOpacity = 1.0
@@ -325,7 +325,7 @@ class QSwitch(QAbstractButton):
trackOpacity = 0.6
trackBrush = qPalette.shadow()
thumbBrush = qPalette.mid()
- textColor = qPalette.shadow().color()
+ textColor = qPalette.shadow().color()
qPaint.setBrush(trackBrush)
qPaint.setOpacity(trackOpacity)
@@ -379,18 +379,18 @@ class PagedDialog(QDialog):
def __init__(self, theParent=None):
QDialog.__init__(self, parent=theParent)
- self._outerBox = QVBoxLayout()
- self._buttonBox = QHBoxLayout()
- self._tabBox = QTabWidget()
-
self._tabBar = VerticalTabBar(self)
- self._tabBox.setTabBar(self._tabBar)
- self._tabBox.setTabPosition(QTabWidget.West)
self._tabBar.setExpanding(False)
+ self._tabBox = QTabWidget()
+ self._tabBox.setTabBar(self._tabBar)
+ self._tabBox.setTabPosition(QTabWidget.West)
+
+ self._buttonBox = QHBoxLayout()
+
+ self._outerBox = QVBoxLayout()
self._outerBox.addWidget(self._tabBox)
self._outerBox.addLayout(self._buttonBox)
- self.setLayout(self._outerBox)
# Default Margins
qM = self._outerBox.contentsMargins()
@@ -399,11 +399,14 @@ class PagedDialog(QDialog):
mT = qM.top()
mB = qM.bottom()
+ # Set Margins
self.setContentsMargins(0, 0, 0, 0)
self._outerBox.setContentsMargins(0, 0, 0, mB)
self._buttonBox.setContentsMargins(mL, 0, mR, 0)
self._outerBox.setSpacing(mT)
+ self.setLayout(self._outerBox)
+
return
def addTab(self, tabWidget, tabLabel):
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index a599fb83..8e203a41 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -1090,7 +1090,7 @@ class GuiDocEditor(QTextEdit):
# Spell Checking
# ==============
- posCursor = self.cursorForPosition(thePos)
+ posCursor = self.cursorForPosition(thePos)
spellCheck = self._spellCheck
if posCursor.block().text().startswith("@"):
@@ -1272,7 +1272,7 @@ class GuiDocEditor(QTextEdit):
findOpt |= QTextDocument.FindWholeWords
searchFor = self.docSearch.getSearchObject()
- wasFound = self.find(searchFor, findOpt)
+ wasFound = self.find(searchFor, findOpt)
if not wasFound:
if self.docSearch.doNextFile and not goBack:
self.theParent.openNextDocument(
@@ -1330,7 +1330,7 @@ class GuiDocEditor(QTextEdit):
return
searchFor = self.docSearch.getSearchText()
- replWith = self.docSearch.getReplaceText()
+ replWith = self.docSearch.getReplaceText()
if self.docSearch.doMatchCap:
replWith = transferCase(theCursor.selectedText(), replWith)
@@ -1376,7 +1376,7 @@ class GuiDocEditor(QTextEdit):
theCursor = self.textCursor()
theBlock = theCursor.block()
- theText = theBlock.text()
+ theText = theBlock.text()
if len(theText) == 0:
return False
@@ -1413,16 +1413,16 @@ class GuiDocEditor(QTextEdit):
if not theBlock.isValid():
return
- theText = theBlock.text()
+ theText = theBlock.text()
theCursor = self.textCursor()
- thePos = theCursor.positionInBlock()
- theLen = len(theText)
+ thePos = theCursor.positionInBlock()
+ theLen = len(theText)
if theLen < 1 or thePos-1 > theLen:
return
- theOne = theText[thePos-1:thePos]
- theTwo = theText[thePos-2:thePos]
+ theOne = theText[thePos-1:thePos]
+ theTwo = theText[thePos-2:thePos]
theThree = theText[thePos-3:thePos]
if not theOne: # Makes Neo sad
@@ -2028,7 +2028,7 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.searchOpt.setIconSize(QSize(tPx, tPx))
self.searchOpt.setContentsMargins(0, 0, 0, 0)
- self.searchOpt.setStyleSheet(r"QToolBar {padding: 0;}")
+ self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
self.searchLabel = QLabel(self.tr("Search"))
self.searchLabel.setFont(boxFont)
@@ -2100,7 +2100,7 @@ class GuiDocEditSearch(QFrame):
self.showReplace.setArrowType(Qt.RightArrow)
self.showReplace.setCheckable(True)
self.showReplace.setToolTip(self.tr("Show/hide the replace text box"))
- self.showReplace.setStyleSheet(r"QToolButton {border: none; background: transparent;}")
+ self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
self.showReplace.toggled.connect(self._doToggleReplace)
self.searchButton = QPushButton(self.theTheme.getIcon("search"), "")
@@ -2139,9 +2139,9 @@ class GuiDocEditSearch(QFrame):
# Construct Box Colours
qPalette = self.searchBox.palette()
baseCol = qPalette.base().color()
- rCol = baseCol.redF() + 0.1
+ rCol = baseCol.redF() + 0.1
gCol = baseCol.greenF() - 0.1
- bCol = baseCol.blueF() - 0.1
+ bCol = baseCol.blueF() - 0.1
mCol = max(rCol, gCol, bCol, 1.0)
errCol = QColor()
@@ -2161,10 +2161,10 @@ class GuiDocEditSearch(QFrame):
def closeSearch(self):
"""Close the search box.
"""
- self.mainConf.searchCase = self.isCaseSense
- self.mainConf.searchWord = self.isWholeWord
- self.mainConf.searchRegEx = self.isRegEx
- self.mainConf.searchLoop = self.doLoop
+ self.mainConf.searchCase = self.isCaseSense
+ self.mainConf.searchWord = self.isWholeWord
+ self.mainConf.searchRegEx = self.isRegEx
+ self.mainConf.searchLoop = self.doLoop
self.mainConf.searchNextFile = self.doNextFile
self.mainConf.searchMatchCap = self.doMatchCap
@@ -2367,7 +2367,8 @@ class GuiDocEditHeader(QWidget):
self.theParent = docEditor.theParent
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
- self._docHandle = None
+
+ self._docHandle = None
fPx = int(0.9*self.theTheme.fontPixelSize)
hSp = self.mainConf.pxInt(6)
@@ -2591,8 +2592,9 @@ class GuiDocEditFooter(QWidget):
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
self.optState = docEditor.theProject.optState
- self._docHandle = None
- self.theItem = None
+
+ self._theItem = None
+ self._docHandle = None
self.sPx = int(round(0.9*self.theTheme.baseIconSize))
fPx = int(0.9*self.theTheme.fontPixelSize)
@@ -2708,9 +2710,9 @@ class GuiDocEditFooter(QWidget):
self._docHandle = tHandle
if self._docHandle is None:
logger.verbose("No handle set, so clearing the editor footer")
- self.theItem = None
+ self._theItem = None
else:
- self.theItem = self.theProject.projTree[self._docHandle]
+ self._theItem = self.theProject.projTree[self._docHandle]
self.updateInfo()
self.updateCounts()
@@ -2720,12 +2722,12 @@ class GuiDocEditFooter(QWidget):
def updateInfo(self):
"""Update the content of text labels.
"""
- if self.theItem is None:
+ if self._theItem is None:
sIcon = QPixmap()
sText = ""
else:
- iStatus = self.theItem.itemStatus
- if self.theItem.itemClass == nwItemClass.NOVEL:
+ iStatus = self._theItem.itemStatus
+ if self._theItem.itemClass == nwItemClass.NOVEL:
iStatus = self.theProject.statusItems.checkEntry(iStatus)
theIcon = self.theParent.statusIcons[iStatus]
else:
@@ -2733,9 +2735,9 @@ class GuiDocEditFooter(QWidget):
theIcon = self.theParent.importIcons[iStatus]
sIcon = theIcon.pixmap(self.sPx, self.sPx)
- sClass = trConst(nwLabels.CLASS_NAME[self.theItem.itemClass])
- sLayout = trConst(nwLabels.LAYOUT_NAME[self.theItem.itemLayout])
- sText = f"{self.theItem.itemStatus} / {sClass} / {sLayout}"
+ sClass = trConst(nwLabels.CLASS_NAME[self._theItem.itemClass])
+ sLayout = trConst(nwLabels.LAYOUT_NAME[self._theItem.itemLayout])
+ sText = f"{self._theItem.itemStatus} / {sClass} / {sLayout}"
self.statusIcon.setPixmap(sIcon)
self.statusText.setText(sText)
@@ -2745,7 +2747,7 @@ class GuiDocEditFooter(QWidget):
def updateLineCount(self):
"""Update the word count.
"""
- if self.theItem is None:
+ if self._theItem is None:
iLine = 0
iDist = 0
else:
@@ -2762,12 +2764,12 @@ class GuiDocEditFooter(QWidget):
def updateCounts(self):
"""Update the word count.
"""
- if self.theItem is None:
+ if self._theItem is None:
wCount = 0
- wDiff = 0
+ wDiff = 0
else:
- wCount = self.theItem.wordCount
- wDiff = wCount - self.theItem.initCount
+ wCount = self._theItem.wordCount
+ wDiff = wCount - self._theItem.initCount
self.wordsText.setText(
self.tr("Words: {0} ({1})").format(f"{wCount:n}", f"{wDiff:+n}")
diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py
index e6417b8c..86e137fe 100644
--- a/nw/gui/docviewer.py
+++ b/nw/gui/docviewer.py
@@ -60,7 +60,7 @@ class GuiDocViewer(QTextBrowser):
self.theProject = theParent.theProject
# Internal Variables
- self._docHandle = None
+ self._docHandle = None
self._qDocument = self.document()
# Settings
@@ -312,9 +312,7 @@ class GuiDocViewer(QTextBrowser):
return
def updateDocMargins(self):
- """Automatically adjust the margins so the text is centred if
- Config.textFixedW is enabled or we're in Focus Mode. Otherwise,
- just ensure the margins are set correctly.
+ """Automatically adjust the margins so the text is centred.
"""
vBar = self.verticalScrollBar()
sW = vBar.width() if vBar.isVisible() else 0
@@ -1152,7 +1150,6 @@ class GuiDocViewDetails(QScrollArea):
self.theParent = theParent
self.theProject = theParent.theProject
self.theTheme = theParent.theTheme
- self.currHandle = None
self.refList = QLabel("")
self.refList.setWordWrap(True)
@@ -1185,7 +1182,6 @@ class GuiDocViewDetails(QScrollArea):
"""Update the current list of document references from the
project index.
"""
- self.currHandle = tHandle
if self.theParent.docViewer.stickyRef:
return
diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py
index c297380a..9efd7a49 100644
--- a/nw/gui/mainmenu.py
+++ b/nw/gui/mainmenu.py
@@ -47,7 +47,7 @@ class GuiMainMenu(QMenuBar):
self.theProject = theParent.theProject
# Internals
- self.assistProc = None
+ self._assistProc = None
# Build Menu
self._buildProjectMenu()
@@ -92,19 +92,19 @@ class GuiMainMenu(QMenuBar):
def closeHelp(self):
"""Close the process used for the Qt Assistant, if it is open.
"""
- if self.assistProc is None:
+ if self._assistProc is None:
return
- if self.assistProc.state() == QProcess.Starting:
- if self.assistProc.waitForStarted(10000):
- self.assistProc.terminate()
+ if self._assistProc.state() == QProcess.Starting:
+ if self._assistProc.waitForStarted(10000):
+ self._assistProc.terminate()
else:
- self.assistProc.kill()
+ self._assistProc.kill()
- elif self.assistProc.state() == QProcess.Running:
- self.assistProc.terminate()
- if not self.assistProc.waitForFinished(10000):
- self.assistProc.kill()
+ elif self._assistProc.state() == QProcess.Running:
+ self._assistProc.terminate()
+ if not self._assistProc.waitForFinished(10000):
+ self._assistProc.kill()
return
@@ -134,7 +134,7 @@ class GuiMainMenu(QMenuBar):
# Slots
##
- def _toggleSpellCheck(self, isChecked=False):
+ def _toggleSpellCheck(self):
"""Toggle spell checking. The active status of the spell check
flag is handled by the document editor class, so we make no
decision, just pass a None to the function and let it decide.
@@ -155,10 +155,10 @@ class GuiMainMenu(QMenuBar):
self._openWebsite(nw.__docurl__)
return False
- self.assistProc = QProcess(self)
- self.assistProc.start("assistant", ["-collectionFile", self.mainConf.helpPath])
+ self._assistProc = QProcess(self)
+ self._assistProc.start("assistant", ["-collectionFile", self.mainConf.helpPath])
- if not self.assistProc.waitForStarted(10000):
+ if not self._assistProc.waitForStarted(10000):
self._openWebsite(nw.__docurl__)
return False
@@ -239,11 +239,9 @@ class GuiMainMenu(QMenuBar):
self.rootItems[nwItemClass.ENTITY] = QAction(self.tr("Entity Root"), self.rootMenu)
self.rootItems[nwItemClass.CUSTOM] = QAction(self.tr("Custom Root"), self.rootMenu)
self.rootItems[nwItemClass.ARCHIVE] = QAction(self.tr("Outtakes Root"), self.rootMenu)
- nCount = 0
- for itemClass in self.rootItems.keys():
- nCount += 1 # This forces the lambdas to be unique
+ for n, itemClass in enumerate(self.rootItems.keys()):
self.rootItems[itemClass].triggered.connect(
- lambda nCount, itemClass=itemClass: self._newTreeItem(nwItemType.ROOT, itemClass)
+ lambda n, itemClass=itemClass: self._newTreeItem(nwItemType.ROOT, itemClass)
)
self.rootMenu.addAction(self.rootItems[itemClass])
diff --git a/nw/gui/noveltree.py b/nw/gui/noveltree.py
index ec7187c2..0a5d2269 100644
--- a/nw/gui/noveltree.py
+++ b/nw/gui/noveltree.py
@@ -247,9 +247,9 @@ class GuiNovelTree(QTreeWidget):
"""
self.clearTree()
- currTitle = None
+ currTitle = None
currChapter = None
- currScene = None
+ currScene = None
for tKey, tHandle, sTitle, novIdx in self.theIndex.novelStructure(skipExcluded=True):
@@ -259,9 +259,9 @@ class GuiNovelTree(QTreeWidget):
tLevel = novIdx["level"]
if tLevel == "H1":
self.addTopLevelItem(tItem)
- currTitle = tItem
+ currTitle = tItem
currChapter = None
- currScene = None
+ currScene = None
elif tLevel == "H2":
if currTitle is None:
@@ -269,7 +269,7 @@ class GuiNovelTree(QTreeWidget):
else:
currTitle.addChild(tItem)
currChapter = tItem
- currScene = None
+ currScene = None
elif tLevel == "H3":
if currChapter is None:
diff --git a/nw/gui/outline.py b/nw/gui/outline.py
index 0f91d9c2..3f67cc35 100644
--- a/nw/gui/outline.py
+++ b/nw/gui/outline.py
@@ -28,7 +28,7 @@ import logging
from time import time
-from PyQt5.QtCore import Qt, QSize
+from PyQt5.QtCore import Qt, QSize, pyqtSlot
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QMenu, QAction, QAbstractItemView
)
@@ -94,9 +94,6 @@ class GuiOutline(QTreeWidget):
self.optState = theParent.theProject.optState
self.headerMenu = GuiOutlineHeaderMenu(self)
- self.firstView = True
- self.lastBuild = 0
-
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setExpandsOnDoubleClick(False)
@@ -113,16 +110,18 @@ class GuiOutline(QTreeWidget):
self.treeHead.customContextMenuRequested.connect(self._headerRightClick)
self.treeHead.sectionMoved.connect(self._columnMoved)
- self.treeMap = {}
- self.treeOrder = []
- self.colWidth = {}
- self.colHidden = {}
- self.colIndex = {}
- self.treeNCols = 0
+ # Internals
+ self._treeOrder = []
+ self._colWidth = {}
+ self._colHidden = {}
+ self._colIdx = {}
+ self._treeNCols = 0
+ self._firstView = True
+ self._lastBuild = 0
self.initOutline()
self.clearOutline()
- self.headerMenu.setHiddenState(self.colHidden)
+ self.headerMenu.setHiddenState(self._colHidden)
logger.debug("GuiOutline initialisation complete")
@@ -152,18 +151,18 @@ class GuiOutline(QTreeWidget):
self.setColumnCount(1)
self.setHeaderLabel(trConst(nwLabels.OUTLINE_COLS[nwOutline.TITLE]))
- self.treeOrder = []
- self.colWidth = {}
- self.colHidden = {}
- self.colIndex = {}
- self.treeNCols = 0
+ self._treeOrder = []
+ self._colWidth = {}
+ self._colHidden = {}
+ self._colIdx = {}
+ self._treeNCols = 0
- for i, hItem in enumerate(nwOutline):
- self.treeOrder.append(hItem)
- self.colWidth[hItem] = self.DEF_WIDTH[hItem]
- self.colHidden[hItem] = self.DEF_HIDDEN[hItem]
+ for hItem in nwOutline:
+ self._treeOrder.append(hItem)
+ self._colWidth[hItem] = self.DEF_WIDTH[hItem]
+ self._colHidden[hItem] = self.DEF_HIDDEN[hItem]
- self.treeNCols = len(self.treeOrder)
+ self._treeNCols = len(self._treeOrder)
return
@@ -173,15 +172,15 @@ class GuiOutline(QTreeWidget):
tree.
"""
# If it's the first time, we always build
- if self.firstView or self.firstView and overRide:
+ if self._firstView or self._firstView and overRide:
self._loadHeaderState()
self._populateTree()
- self.firstView = False
+ self._firstView = False
return
# If the novel index or novel tree has changed since the tree
# was last built, we rebuild the tree from the updated index.
- indexChanged = self.theIndex.novelChangedSince(self.lastBuild)
+ indexChanged = self.theIndex.novelChangedSince(self._lastBuild)
doBuild = (novelChanged or indexChanged) and self.theProject.autoOutline
if doBuild or overRide:
logger.debug("Rebuilding Project Outline")
@@ -194,21 +193,22 @@ class GuiOutline(QTreeWidget):
"""
self._saveHeaderState()
self.clearOutline()
- self.firstView = True
+ self._firstView = True
return
##
# Slots
##
+ @pyqtSlot("QTreeWidgetItem*", int)
def _treeDoubleClick(self, tItem, tCol):
"""Extract the handle and line number of the title double-
clicked, and send it to the main gui class for opening in the
document editor.
"""
- tHandle = tItem.data(self.colIndex[nwOutline.TITLE], Qt.UserRole)
+ tHandle = tItem.data(self._colIdx[nwOutline.TITLE], Qt.UserRole)
try:
- tLine = int(tItem.text(self.colIndex[nwOutline.LINE]))
+ tLine = int(tItem.text(self._colIdx[nwOutline.LINE]))
except Exception:
tLine = 1
@@ -217,30 +217,33 @@ class GuiOutline(QTreeWidget):
return
+ @pyqtSlot()
def _itemSelected(self):
"""Extract the handle and line number of the currently selected
title, and send it to the details panel.
"""
selItems = self.selectedItems()
if selItems:
- tHandle = selItems[0].data(self.colIndex[nwOutline.TITLE], Qt.UserRole)
- sTitle = selItems[0].data(self.colIndex[nwOutline.LINE], Qt.UserRole)
+ tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], Qt.UserRole)
+ sTitle = selItems[0].data(self._colIdx[nwOutline.LINE], Qt.UserRole)
self.theParent.projMeta.showItem(tHandle, sTitle)
self.theParent.treeView.setSelectedHandle(tHandle)
return
+ @pyqtSlot("QPoint")
def _headerRightClick(self, clickPos):
"""Show the header column menu.
"""
self.headerMenu.exec_(self.mapToGlobal(clickPos))
return
+ @pyqtSlot(int, int, int)
def _columnMoved(self, logIdx, oldVisualIdx, newVisualIdx):
"""Make sure the order array is up to date with the actual order
of the columns.
"""
- self.treeOrder.insert(newVisualIdx, self.treeOrder.pop(oldVisualIdx))
+ self._treeOrder.insert(newVisualIdx, self._treeOrder.pop(oldVisualIdx))
self._saveHeaderState()
return
@@ -249,8 +252,8 @@ class GuiOutline(QTreeWidget):
header context menu.
"""
logger.verbose("User toggled Outline column '%s'", theItem.name)
- if theItem in self.colIndex:
- self.setColumnHidden(self.colIndex[theItem], not isChecked)
+ if theItem in self._colIdx:
+ self.setColumnHidden(self._colIdx[theItem], not isChecked)
self._saveHeaderState()
return
@@ -281,29 +284,29 @@ class GuiOutline(QTreeWidget):
# Check that we now have a complete list, and only if so, save
# the order loaded from file. Otherwise, we keep the default.
- if len(treeOrder) == self.treeNCols:
- self.treeOrder = treeOrder
+ if len(treeOrder) == self._treeNCols:
+ self._treeOrder = treeOrder
else:
logger.error("Failed to extract outline column order from previous session")
- logger.error("Column count doesn't match %d != %d", len(treeOrder), self.treeNCols)
+ logger.error("Column count doesn't match %d != %d", len(treeOrder), self._treeNCols)
# We load whatever column widths and hidden states we find in
# the file, and leave the rest in their default state.
tmpWidth = self.optState.getValue("GuiOutline", "columnWidth", {})
for hName in tmpWidth:
try:
- self.colWidth[nwOutline[hName]] = self.mainConf.pxInt(tmpWidth[hName])
+ self._colWidth[nwOutline[hName]] = self.mainConf.pxInt(tmpWidth[hName])
except Exception:
logger.warning("Ignored unknown outline column '%s'", str(hName))
tmpHidden = self.optState.getValue("GuiOutline", "columnHidden", {})
for hName in tmpHidden:
try:
- self.colHidden[nwOutline[hName]] = tmpHidden[hName]
+ self._colHidden[nwOutline[hName]] = tmpHidden[hName]
except Exception:
logger.warning("Ignored unknown outline column '%s'", str(hName))
- self.headerMenu.setHiddenState(self.colHidden)
+ self.headerMenu.setHiddenState(self._colHidden)
return
@@ -314,19 +317,19 @@ class GuiOutline(QTreeWidget):
the last known width in case they're unhidden again.
"""
# If we haven't built the tree, there is nothing to save.
- if self.lastBuild == 0:
+ if self._lastBuild == 0:
return
treeOrder = []
- colWidth = {}
+ colWidth = {}
colHidden = {}
for hItem in nwOutline:
- colWidth[hItem.name] = self.mainConf.rpxInt(self.colWidth[hItem])
- colHidden[hItem.name] = self.colHidden[hItem]
+ colWidth[hItem.name] = self.mainConf.rpxInt(self._colWidth[hItem])
+ colHidden[hItem.name] = self._colHidden[hItem]
for iCol in range(self.columnCount()):
- hName = self.treeOrder[iCol].name
+ hName = self._treeOrder[iCol].name
treeOrder.append(hName)
iLog = self.treeHead.logicalIndex(iCol)
@@ -353,41 +356,40 @@ class GuiOutline(QTreeWidget):
"""
self.clear()
- if self.firstView:
+ if self._firstView:
theLabels = []
- for i, hItem in enumerate(self.treeOrder):
+ for i, hItem in enumerate(self._treeOrder):
theLabels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
- self.colIndex[hItem] = i
+ self._colIdx[hItem] = i
self.setHeaderLabels(theLabels)
- for hItem in self.treeOrder:
- self.setColumnWidth(self.colIndex[hItem], self.colWidth[hItem])
- self.setColumnHidden(self.colIndex[hItem], self.colHidden[hItem])
+ for hItem in self._treeOrder:
+ self.setColumnWidth(self._colIdx[hItem], self._colWidth[hItem])
+ self.setColumnHidden(self._colIdx[hItem], self._colHidden[hItem])
# Make sure title column is always visible,
# and handle column always hidden
- self.setColumnHidden(self.colIndex[nwOutline.TITLE], False)
+ self.setColumnHidden(self._colIdx[nwOutline.TITLE], False)
headItem = self.headerItem()
- headItem.setTextAlignment(self.colIndex[nwOutline.CCOUNT], Qt.AlignRight)
- headItem.setTextAlignment(self.colIndex[nwOutline.WCOUNT], Qt.AlignRight)
- headItem.setTextAlignment(self.colIndex[nwOutline.PCOUNT], Qt.AlignRight)
+ headItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight)
+ headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
+ headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
- currTitle = None
+ currTitle = None
currChapter = None
- currScene = None
+ currScene = None
for tKey, tHandle, sTitle, novIdx in self.theIndex.novelStructure(skipExcluded=True):
tItem = self._createTreeItem(tHandle, sTitle, novIdx)
- self.treeMap[tKey] = tItem
tLevel = novIdx["level"]
if tLevel == "H1":
self.addTopLevelItem(tItem)
- currTitle = tItem
+ currTitle = tItem
currChapter = None
- currScene = None
+ currScene = None
elif tLevel == "H2":
if currTitle is None:
@@ -395,7 +397,7 @@ class GuiOutline(QTreeWidget):
else:
currTitle.addChild(tItem)
currChapter = tItem
- currScene = None
+ currScene = None
elif tLevel == "H3":
if currChapter is None:
@@ -421,47 +423,47 @@ class GuiOutline(QTreeWidget):
tItem.setExpanded(True)
- self.lastBuild = time()
+ self._lastBuild = time()
return
def _createTreeItem(self, tHandle, sTitle, novIdx):
"""Populate a tree item with all the column values.
"""
- nwItem = self.theProject.projTree[tHandle]
+ nwItem = self.theProject.projTree[tHandle]
newItem = QTreeWidgetItem()
- hIcon = "doc_%s" % novIdx["level"].lower()
+ hIcon = "doc_%s" % novIdx["level"].lower()
cC = int(novIdx["cCount"])
wC = int(novIdx["wCount"])
pC = int(novIdx["pCount"])
- newItem.setText(self.colIndex[nwOutline.TITLE], novIdx["title"])
- newItem.setData(self.colIndex[nwOutline.TITLE], Qt.UserRole, tHandle)
- newItem.setIcon(self.colIndex[nwOutline.TITLE], self.theTheme.getIcon(hIcon))
- newItem.setText(self.colIndex[nwOutline.LEVEL], novIdx["level"])
- newItem.setText(self.colIndex[nwOutline.LABEL], nwItem.itemName)
- newItem.setIcon(self.colIndex[nwOutline.LABEL], self.theTheme.getIcon("proj_document"))
- newItem.setText(self.colIndex[nwOutline.LINE], sTitle[1:].lstrip("0"))
- newItem.setData(self.colIndex[nwOutline.LINE], Qt.UserRole, sTitle)
- newItem.setText(self.colIndex[nwOutline.SYNOP], novIdx["synopsis"])
- newItem.setText(self.colIndex[nwOutline.CCOUNT], f"{cC:n}")
- newItem.setText(self.colIndex[nwOutline.WCOUNT], f"{wC:n}")
- newItem.setText(self.colIndex[nwOutline.PCOUNT], f"{pC:n}")
- newItem.setTextAlignment(self.colIndex[nwOutline.CCOUNT], Qt.AlignRight)
- newItem.setTextAlignment(self.colIndex[nwOutline.WCOUNT], Qt.AlignRight)
- newItem.setTextAlignment(self.colIndex[nwOutline.PCOUNT], Qt.AlignRight)
+ newItem.setText(self._colIdx[nwOutline.TITLE], novIdx["title"])
+ newItem.setData(self._colIdx[nwOutline.TITLE], Qt.UserRole, tHandle)
+ newItem.setIcon(self._colIdx[nwOutline.TITLE], self.theTheme.getIcon(hIcon))
+ newItem.setText(self._colIdx[nwOutline.LEVEL], novIdx["level"])
+ newItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
+ newItem.setIcon(self._colIdx[nwOutline.LABEL], self.theTheme.getIcon("proj_document"))
+ newItem.setText(self._colIdx[nwOutline.LINE], sTitle[1:].lstrip("0"))
+ newItem.setData(self._colIdx[nwOutline.LINE], Qt.UserRole, sTitle)
+ newItem.setText(self._colIdx[nwOutline.SYNOP], novIdx["synopsis"])
+ newItem.setText(self._colIdx[nwOutline.CCOUNT], f"{cC:n}")
+ newItem.setText(self._colIdx[nwOutline.WCOUNT], f"{wC:n}")
+ newItem.setText(self._colIdx[nwOutline.PCOUNT], f"{pC:n}")
+ newItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight)
+ newItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
+ newItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
theRefs = self.theIndex.getReferences(tHandle, sTitle)
- newItem.setText(self.colIndex[nwOutline.POV], ", ".join(theRefs[nwKeyWords.POV_KEY]))
- newItem.setText(self.colIndex[nwOutline.FOCUS], ", ".join(theRefs[nwKeyWords.FOCUS_KEY]))
- newItem.setText(self.colIndex[nwOutline.CHAR], ", ".join(theRefs[nwKeyWords.CHAR_KEY]))
- newItem.setText(self.colIndex[nwOutline.PLOT], ", ".join(theRefs[nwKeyWords.PLOT_KEY]))
- newItem.setText(self.colIndex[nwOutline.TIME], ", ".join(theRefs[nwKeyWords.TIME_KEY]))
- newItem.setText(self.colIndex[nwOutline.WORLD], ", ".join(theRefs[nwKeyWords.WORLD_KEY]))
- newItem.setText(self.colIndex[nwOutline.OBJECT], ", ".join(theRefs[nwKeyWords.OBJECT_KEY]))
- newItem.setText(self.colIndex[nwOutline.ENTITY], ", ".join(theRefs[nwKeyWords.ENTITY_KEY]))
- newItem.setText(self.colIndex[nwOutline.CUSTOM], ", ".join(theRefs[nwKeyWords.CUSTOM_KEY]))
+ newItem.setText(self._colIdx[nwOutline.POV], ", ".join(theRefs[nwKeyWords.POV_KEY]))
+ newItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(theRefs[nwKeyWords.FOCUS_KEY]))
+ newItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(theRefs[nwKeyWords.CHAR_KEY]))
+ newItem.setText(self._colIdx[nwOutline.PLOT], ", ".join(theRefs[nwKeyWords.PLOT_KEY]))
+ newItem.setText(self._colIdx[nwOutline.TIME], ", ".join(theRefs[nwKeyWords.TIME_KEY]))
+ newItem.setText(self._colIdx[nwOutline.WORLD], ", ".join(theRefs[nwKeyWords.WORLD_KEY]))
+ newItem.setText(self._colIdx[nwOutline.OBJECT], ", ".join(theRefs[nwKeyWords.OBJECT_KEY]))
+ newItem.setText(self._colIdx[nwOutline.ENTITY], ", ".join(theRefs[nwKeyWords.ENTITY_KEY]))
+ newItem.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(theRefs[nwKeyWords.CUSTOM_KEY]))
return newItem
diff --git a/nw/gui/outlinedetails.py b/nw/gui/outlinedetails.py
index 97a7d03e..87b9aba6 100644
--- a/nw/gui/outlinedetails.py
+++ b/nw/gui/outlinedetails.py
@@ -191,7 +191,7 @@ class GuiOutlineDetails(QScrollArea):
# Selected Item Tags
self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
- self.tagsForm = QGridLayout()
+ self.tagsForm = QGridLayout()
self.tagsGroup.setLayout(self.tagsForm)
self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
@@ -279,8 +279,8 @@ class GuiOutlineDetails(QScrollArea):
"""Update the content of the tree with the given handle and line
number pointing to a header.
"""
- nwItem = self.theProject.projTree[tHandle]
- novIdx = self.theIndex.getNovelData(tHandle, sTitle)
+ nwItem = self.theProject.projTree[tHandle]
+ novIdx = self.theIndex.getNovelData(tHandle, sTitle)
theRefs = self.theIndex.getReferences(tHandle, sTitle)
if nwItem is None or novIdx is None:
return False
diff --git a/nw/gui/projdetails.py b/nw/gui/projdetails.py
index a780ea9f..8746a232 100644
--- a/nw/gui/projdetails.py
+++ b/nw/gui/projdetails.py
@@ -24,8 +24,8 @@ along with this program. If not, see .
"""
import nw
-import logging
import math
+import logging
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont
@@ -66,10 +66,10 @@ class GuiProjectDetails(PagedDialog):
self.mainConf.pxInt(self.optState.getInt("GuiProjectDetails", "winHeight", wH))
)
- self.tabMain = GuiProjectDetailsMain(self.theParent, self.theProject)
+ self.tabMain = GuiProjectDetailsMain(self.theParent, self.theProject)
self.tabContents = GuiProjectDetailsContents(self.theParent, self.theProject)
- self.addTab(self.tabMain, self.tr("Overview"))
+ self.addTab(self.tabMain, self.tr("Overview"))
self.addTab(self.tabContents, self.tr("Contents"))
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
@@ -413,8 +413,8 @@ class GuiProjectDetailsContents(QWidget):
"""Set the content of the chapter/page tree.
"""
dblPages = self.dblValue.isChecked()
- wpPage = self.wpValue.value()
- fstPage = self.poValue.value() - 1
+ wpPage = self.wpValue.value()
+ fstPage = self.poValue.value() - 1
pTotal = 0
tPages = 1
diff --git a/nw/gui/projtree.py b/nw/gui/projtree.py
index da8de118..a5ad0e04 100644
--- a/nw/gui/projtree.py
+++ b/nw/gui/projtree.py
@@ -132,7 +132,7 @@ class GuiProjectTree(QTreeWidget):
self.initTree()
# Internal Function Mapping
- self.makeAlert = self.theParent.makeAlert
+ self.makeAlert = self.theParent.makeAlert
self.askQuestion = self.theParent.askQuestion
logger.debug("GuiProjectTree initialisation complete")
@@ -1167,7 +1167,7 @@ class GuiProjectTreeMenu(QMenu):
inTrash = theItem.itemParent == trashHandle and trashHandle is not None
isTrash = theItem.itemHandle == trashHandle and trashHandle is not None
- isFile = theItem.itemType == nwItemType.FILE
+ isFile = theItem.itemType == nwItemType.FILE
allowNew = not (isTrash or inTrash)
diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py
index e1fdb8da..5b369e36 100644
--- a/nw/gui/statusbar.py
+++ b/nw/gui/statusbar.py
@@ -51,8 +51,8 @@ class GuiMainStatus(QStatusBar):
self.refTime = None
self.userIdle = False
- colNone = QColor(*self.theTheme.statNone)
- colTrue = QColor(*self.theTheme.statUnsaved)
+ colNone = QColor(*self.theTheme.statNone)
+ colTrue = QColor(*self.theTheme.statUnsaved)
colFalse = QColor(*self.theTheme.statSaved)
iPx = self.theTheme.baseIconSize
@@ -243,8 +243,8 @@ class StatusLED(QAbstractButton):
self._colNone = colNone
self._colGood = colGood
- self._colBad = colBad
- self._theCol = colNone
+ self._colBad = colBad
+ self._theCol = colNone
self.setFixedWidth(sW)
self.setFixedHeight(sH)
diff --git a/nw/gui/theme.py b/nw/gui/theme.py
index c3ee1f24..1932ace8 100644
--- a/nw/gui/theme.py
+++ b/nw/gui/theme.py
@@ -25,9 +25,9 @@ along with this program. If not, see .
"""
import nw
+import os
import logging
import configparser
-import os
from math import ceil
from functools import partial
@@ -272,7 +272,7 @@ class GuiTheme:
cssData = ""
try:
if os.path.isfile(self.cssFile):
- with open(self.cssFile, mode="r", encoding="utf8") as inFile:
+ with open(self.cssFile, mode="r", encoding="utf-8") as inFile:
cssData = inFile.read()
except Exception:
logger.error("Could not load theme css file")
@@ -282,7 +282,7 @@ class GuiTheme:
# Config File
confParser = configparser.ConfigParser()
try:
- with open(self.confFile, mode="r", encoding="utf8") as inFile:
+ with open(self.confFile, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception:
logger.error("Could not load theme settings from: %s", self.confFile)
@@ -340,7 +340,7 @@ class GuiTheme:
confParser = configparser.ConfigParser()
try:
- with open(self.syntaxFile, mode="r", encoding="utf8") as inFile:
+ with open(self.syntaxFile, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception:
logger.error("Could not load syntax colours from: %s", self.syntaxFile)
@@ -395,7 +395,7 @@ class GuiTheme:
)
logger.verbose("Checking theme config for '%s'", themeDir)
try:
- with open(themeConf, mode="r", encoding="utf8") as inFile:
+ with open(themeConf, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception as e:
self.makeAlert([
@@ -421,14 +421,14 @@ class GuiTheme:
return self.syntaxList
confParser = configparser.ConfigParser()
- syntaxDir = os.path.join(self.mainConf.themeRoot, self.syntaxPath)
+ syntaxDir = os.path.join(self.mainConf.themeRoot, self.syntaxPath)
for syntaxFile in os.listdir(syntaxDir):
syntaxPath = os.path.join(syntaxDir, syntaxFile)
if not os.path.isfile(syntaxPath):
continue
logger.verbose("Checking theme syntax for '%s'", syntaxFile)
try:
- with open(syntaxPath, mode="r", encoding="utf8") as inFile:
+ with open(syntaxPath, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception as e:
self.makeAlert([
@@ -646,7 +646,7 @@ class GuiIcons:
# Config File
confParser = configparser.ConfigParser()
try:
- with open(self.confFile, mode="r", encoding="utf8") as inFile:
+ with open(self.confFile, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception:
logger.error("Could not load icon theme settings from: %s", self.confFile)
@@ -744,7 +744,7 @@ class GuiIcons:
themeConf = os.path.join(themePath, self.confName)
logger.verbose("Checking icon theme config for '%s'", themeDir)
try:
- with open(themeConf, mode="r", encoding="utf8") as inFile:
+ with open(themeConf, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile)
except Exception as e:
self.makeAlert([
diff --git a/nw/guimain.py b/nw/guimain.py
index 76e725e2..936bfcda 100644
--- a/nw/guimain.py
+++ b/nw/guimain.py
@@ -24,11 +24,11 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
-from datetime import datetime
from time import time
+from datetime import datetime
from PyQt5.QtCore import Qt, QTimer, QSize, QThreadPool, pyqtSlot
from PyQt5.QtGui import QIcon, QPixmap, QColor, QKeySequence, QCursor
@@ -71,15 +71,12 @@ class GuiMain(QMainWindow):
logger.info("OS: %s", self.mainConf.osType)
logger.info("Kernel: %s", self.mainConf.kernelVer)
logger.info("Host: %s", self.mainConf.hostName)
- logger.info(
- "Qt5 Version: %s (%d)", self.mainConf.verQtString, self.mainConf.verQtValue
- )
- logger.info(
- "PyQt5 Version: %s (%d)", self.mainConf.verPyQtString, self.mainConf.verPyQtValue
- )
- logger.info(
- "Python Version: %s (0x%x)", self.mainConf.verPyString, self.mainConf.verPyHexVal
- )
+ logger.info("Qt5 Version: %s (%d)",
+ self.mainConf.verQtString, self.mainConf.verQtValue)
+ logger.info("PyQt5 Version: %s (%d)",
+ self.mainConf.verPyQtString, self.mainConf.verPyQtValue)
+ logger.info("Python Version: %s (0x%x)",
+ self.mainConf.verPyString, self.mainConf.verPyHexVal)
logger.info("GUI Language: %s", self.mainConf.guiLang)
# Core Classes
@@ -137,7 +134,7 @@ class GuiMain(QMainWindow):
# Project Tree Tabs
self.projTabs = QTabWidget()
self.projTabs.setTabPosition(QTabWidget.South)
- self.projTabs.setStyleSheet(r"QTabWidget::pane {border: 0;};")
+ self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
self.projTabs.addTab(self.treeView, self.tr("Project"))
self.projTabs.addTab(self.novelView, self.tr("Novel"))
self.projTabs.currentChanged.connect(self._projTabsChanged)
@@ -152,7 +149,7 @@ class GuiMain(QMainWindow):
self.treeButtons.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.treeButtons.setIconSize(QSize(btnSize, btnSize))
self.treeButtons.setContentsMargins(0, 0, 0, 0)
- self.treeButtons.setStyleSheet(r"QToolBar {padding: 0;}")
+ self.treeButtons.setStyleSheet("QToolBar {padding: 0;}")
self.projTabs.setCornerWidget(self.treeButtons, Qt.BottomRightCorner)
self.projDetailsBtn = QAction(self.tr("Project Details"))
@@ -199,7 +196,7 @@ class GuiMain(QMainWindow):
# Main Tabs : Editor / Outline
self.mainTabs = QTabWidget()
self.mainTabs.setTabPosition(QTabWidget.East)
- self.mainTabs.setStyleSheet(r"QTabWidget::pane {border: 0;}")
+ self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
self.mainTabs.addTab(self.splitDocs, self.tr("Editor"))
self.mainTabs.addTab(self.splitOutline, self.tr("Outline"))
self.mainTabs.currentChanged.connect(self._mainTabChanged)
@@ -415,7 +412,7 @@ class GuiMain(QMainWindow):
self.saveDocument()
if self.theProject.projAltered:
- saveOK = self.saveProject()
+ saveOK = self.saveProject()
doBackup = False
if self.theProject.doBackup and self.mainConf.backupOnClose:
doBackup = True
@@ -438,7 +435,7 @@ class GuiMain(QMainWindow):
self.theProject.closeProject(self.idleTime)
self.idleRefTime = time()
- self.idleTime = 0.0
+ self.idleTime = 0.0
self.theIndex.clearIndex()
self.clearGUI()
@@ -490,14 +487,16 @@ class GuiMain(QMainWindow):
self, self.tr("Project Locked"),
"%s
%s
%s" % (
self.tr(
- "The project is already open by another instance of novelWriter, and "
- "is therefore locked. Override lock and continue anyway?"
+ "The project is already open by another instance of "
+ "novelWriter, and is therefore locked. Override lock "
+ "and continue anyway?"
),
self.tr(
- "Note: If the program or the computer previously crashed, the lock "
- "can safely be overridden. If, however, another instance of "
- "novelWriter has the project open, overriding the lock may corrupt "
- "the project, and is not recommended."
+ "Note: If the program or the computer previously "
+ "crashed, the lock can safely be overridden. If, "
+ "however, another instance of novelWriter has the "
+ "project open, overriding the lock may corrupt the "
+ "project, and is not recommended."
),
lockDetails
),
@@ -510,9 +509,9 @@ class GuiMain(QMainWindow):
return False
# Project is loaded
- self.hasProject = True
+ self.hasProject = True
self.idleRefTime = time()
- self.idleTime = 0.0
+ self.idleTime = 0.0
# Load the tag index
self.theIndex.loadIndex()
@@ -721,7 +720,7 @@ class GuiMain(QMainWindow):
theText = None
try:
- with open(loadFile, mode="rt", encoding="utf8") as inFile:
+ with open(loadFile, mode="rt", encoding="utf-8") as inFile:
theText = inFile.read()
self.mainConf.setLastPath(loadFile)
except Exception as e:
@@ -740,8 +739,8 @@ class GuiMain(QMainWindow):
msgYes = self.askQuestion(
self.tr("Import Document"),
self.tr(
- "Importing the file will overwrite the current content of the document. "
- "Do you want to proceed?"
+ "Importing the file will overwrite the current content of "
+ "the document. Do you want to proceed?"
)
)
if not msgYes:
diff --git a/nw/tools/build.py b/nw/tools/build.py
index 45dc17db..4e15b6d3 100644
--- a/nw/tools/build.py
+++ b/nw/tools/build.py
@@ -24,24 +24,24 @@ along with this program. If not, see .
"""
import nw
-import logging
-import json
import os
+import json
+import logging
from time import time
from datetime import datetime
-from PyQt5.QtCore import Qt, QTimer
-from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtGui import (
QPalette, QColor, QFont, QCursor, QFontInfo
)
+from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import (
qApp, QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction,
QFileDialog, QFontDialog, QSpinBox, QScrollArea, QSplitter, QWidget,
QSizePolicy, QDoubleSpinBox, QComboBox
)
+from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from nw.core import ToHtml, ToOdt, ToMarkdown
from nw.enum import nwAlert, nwItemType, nwItemLayout, nwItemClass
@@ -55,14 +55,12 @@ logger = logging.getLogger(__name__)
class GuiBuildNovel(QDialog):
FMT_PDF = 1 # Print to PDF
-
FMT_ODT = 2 # Open Document file
FMT_FODT = 3 # Flat Open Document file
FMT_HTM = 4 # HTML5
FMT_NWD = 5 # nW Markdown
FMT_MD = 6 # Standard Markdown
FMT_GH = 7 # GitHub Markdown
-
FMT_JSON_H = 8 # HTML5 wrapped in JSON
FMT_JSON_M = 9 # nW Markdown wrapped in JSON
@@ -560,8 +558,8 @@ class GuiBuildNovel(QDialog):
"""Load the previously generated document from cache.
"""
if self._loadCache():
- textFont = self.textFont.text()
- textSize = self.textSize.value()
+ textFont = self.textFont.text()
+ textSize = self.textSize.value()
justifyText = self.justifyText.isChecked()
self.docView.setTextFont(textFont, textSize)
self.docView.setJustify(justifyText)
@@ -596,14 +594,14 @@ class GuiBuildNovel(QDialog):
"""
# Get Settings
justifyText = self.justifyText.isChecked()
- noStyling = self.noStyling.isChecked()
- textFont = self.textFont.text()
- textSize = self.textSize.value()
+ noStyling = self.noStyling.isChecked()
+ textFont = self.textFont.text()
+ textSize = self.textSize.value()
replaceTabs = self.replaceTabs.isChecked()
- self.htmlText = []
+ self.htmlText = []
self.htmlStyle = []
- self.htmlSize = 0
+ self.htmlSize = 0
# Build Preview
# =============
@@ -672,7 +670,7 @@ class GuiBuildNovel(QDialog):
textFixed = fontInfo.fixedPitch()
isHtml = isinstance(bldObj, ToHtml)
- isOdt = isinstance(bldObj, ToOdt)
+ isOdt = isinstance(bldObj, ToOdt)
bldObj.setTitleFormat(fmtTitle)
bldObj.setChapterFormat(fmtChapter)
@@ -706,7 +704,7 @@ class GuiBuildNovel(QDialog):
for nItt, tItem in enumerate(self.theProject.projTree):
- noteRoot = noteFiles
+ noteRoot = noteFiles
noteRoot &= tItem.itemType == nwItemType.ROOT
noteRoot &= tItem.itemClass != nwItemClass.NOVEL
noteRoot &= tItem.itemClass != nwItemClass.ARCHIVE
@@ -848,12 +846,12 @@ class GuiBuildNovel(QDialog):
# ==================
cleanName = makeFileNameSafe(self.theProject.projName)
- fileName = "%s.%s" % (cleanName, fileExt)
- saveDir = self.mainConf.lastPath
+ fileName = "%s.%s" % (cleanName, fileExt)
+ saveDir = self.mainConf.lastPath
if not os.path.isdir(saveDir):
saveDir = os.path.expanduser("~")
- savePath = os.path.join(saveDir, fileName)
+ savePath = os.path.join(saveDir, fileName)
savePath, _ = QFileDialog.getSaveFileName(
self, self.tr("Save Document As"), savePath
)
@@ -967,7 +965,7 @@ class GuiBuildNovel(QDialog):
}
try:
- with open(savePath, mode="w", encoding="utf8") as outFile:
+ with open(savePath, mode="w", encoding="utf-8") as outFile:
outFile.write(json.dumps(jsonData, indent=2))
wSuccess = True
except Exception as e:
@@ -1045,10 +1043,9 @@ class GuiBuildNovel(QDialog):
buildCache = os.path.join(self.theProject.projCache, nwFiles.BUILD_CACHE)
dataCount = 0
if os.path.isfile(buildCache):
-
logger.debug("Loading build cache")
try:
- with open(buildCache, mode="r", encoding="utf8") as inFile:
+ with open(buildCache, mode="r", encoding="utf-8") as inFile:
theJson = inFile.read()
theData = json.loads(theJson)
except Exception:
@@ -1071,10 +1068,9 @@ class GuiBuildNovel(QDialog):
"""Save the current data to cache.
"""
buildCache = os.path.join(self.theProject.projCache, nwFiles.BUILD_CACHE)
-
logger.debug("Saving build cache")
try:
- with open(buildCache, mode="w+", encoding="utf8") as outFile:
+ with open(buildCache, mode="w+", encoding="utf-8") as outFile:
outFile.write(json.dumps({
"buildTime": self.buildTime,
"htmlStyle": self.htmlStyle,
@@ -1311,10 +1307,10 @@ class GuiBuildNovelDocView(QTextBrowser):
"""Set the stylesheet for the preview document.
"""
if not theStyles:
- theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
- theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
- theStyles.append(r"a {color: rgb(66, 113, 174);}")
- theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
+ theStyles.append("h1, h2 {color: rgb(66, 113, 174);}")
+ theStyles.append("h3, h4 {color: rgb(50, 50, 50);}")
+ theStyles.append("a {color: rgb(66, 113, 174);}")
+ theStyles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}")
self.qDocument.setDefaultStyleSheet("\n".join(theStyles))
diff --git a/nw/tools/projwizard.py b/nw/tools/projwizard.py
index 846a67e8..80082009 100644
--- a/nw/tools/projwizard.py
+++ b/nw/tools/projwizard.py
@@ -24,8 +24,8 @@ along with this program. If not, see .
"""
import nw
-import logging
import os
+import logging
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
diff --git a/nw/tools/writingstats.py b/nw/tools/writingstats.py
index e37c03c7..5f919ee5 100644
--- a/nw/tools/writingstats.py
+++ b/nw/tools/writingstats.py
@@ -24,14 +24,14 @@ along with this program. If not, see .
"""
import nw
-import logging
-import json
import os
+import json
+import logging
from datetime import datetime
-from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QCursor
+from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
qApp, QDialog, QTreeWidget, QTreeWidgetItem, QDialogButtonBox, QGridLayout,
QLabel, QGroupBox, QMenu, QAction, QFileDialog, QSpinBox, QHBoxLayout
@@ -132,7 +132,7 @@ class GuiWritingStats(QDialog):
self.barImage.fill(self.palette().highlight().color())
# Session Info
- self.infoBox = QGroupBox(self.tr("Sum Totals"), self)
+ self.infoBox = QGroupBox(self.tr("Sum Totals"), self)
self.infoForm = QGridLayout(self)
self.infoBox.setLayout(self.infoForm)
@@ -186,7 +186,7 @@ class GuiWritingStats(QDialog):
# Filter Options
sPx = self.theTheme.baseIconSize
- self.filterBox = QGroupBox(self.tr("Filters"), self)
+ self.filterBox = QGroupBox(self.tr("Filters"), self)
self.filterForm = QGridLayout(self)
self.filterBox.setLayout(self.filterForm)
@@ -382,7 +382,7 @@ class GuiWritingStats(QDialog):
errMsg = ""
try:
- with open(savePath, mode="w", encoding="utf8") as outFile:
+ with open(savePath, mode="w", encoding="utf-8") as outFile:
if dataFmt == self.FMT_JSON:
jsonData = []
for _, sD, tT, wD, wA, wB, tI in self.filterData:
@@ -436,8 +436,8 @@ class GuiWritingStats(QDialog):
ttNovel = 0
ttNotes = 0
- ttTime = 0
- ttIdle = 0
+ ttTime = 0
+ ttIdle = 0
logFile = os.path.join(self.theProject.projMeta, nwFiles.SESS_STATS)
if not os.path.isfile(logFile):
@@ -445,7 +445,7 @@ class GuiWritingStats(QDialog):
return False
try:
- with open(logFile, mode="r", encoding="utf8") as inFile:
+ with open(logFile, mode="r", encoding="utf-8") as inFile:
for inLine in inFile:
if inLine.startswith("#"):
if inLine.startswith("# Offset"):
diff --git a/tests/conftest.py b/tests/conftest.py
index 8db6da21..dbe5f318 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -143,7 +143,7 @@ def fncConf(fncDir):
@pytest.fixture(scope="function")
-def dummyGUI(monkeypatch, tmpConf):
+def mockGUI(monkeypatch, tmpConf):
"""Create a mock instance of novelWriter's main GUI class.
"""
monkeypatch.setattr("nw.CONFIG", tmpConf)
diff --git a/tests/test_core/test_core_document.py b/tests/test_core/test_core_document.py
index f165655b..85ae47af 100644
--- a/tests/test_core/test_core_document.py
+++ b/tests/test_core/test_core_document.py
@@ -23,16 +23,17 @@ import os
import pytest
from mock import causeOSError
+from tools import readFile
from nw.core import NWProject, NWDoc
from nw.enum import nwItemClass, nwItemLayout
@pytest.mark.core
-def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
+def testCoreDocument_LoadSave(monkeypatch, mockGUI, nwMinimal):
"""Test loading and saving a document with the NWDoc class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
assert theProject.openProject(nwMinimal)
assert theProject.projPath == nwMinimal
@@ -75,21 +76,18 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
# Check file content
docPath = os.path.join(nwMinimal, "content", xHandle+".nwd")
- with open(docPath, mode="r", encoding="utf8") as inFile:
- assert inFile.read() == (
- "%%~name: New File\n"
- f"%%~path: a508bb932959c/{xHandle}\n"
- "%%~kind: NOVEL/SCENE\n"
- "### Test File\n\n"
- "Text ...\n\n"
- )
+ assert readFile(docPath) == (
+ "%%~name: New File\n"
+ f"%%~path: a508bb932959c/{xHandle}\n"
+ "%%~kind: NOVEL/SCENE\n"
+ "### Test File\n\n"
+ "Text ...\n\n"
+ )
# Force no meta data
theDoc._theItem = None
assert theDoc.writeDocument(theText)
-
- with open(docPath, mode="r", encoding="utf8") as inFile:
- assert inFile.read() == theText
+ assert readFile(docPath) == theText
# Cause open() to fail while saving
with monkeypatch.context() as mp:
@@ -122,10 +120,10 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
@pytest.mark.core
-def testCoreDocument_Methods(dummyGUI, nwMinimal):
+def testCoreDocument_Methods(mockGUI, nwMinimal):
"""Test other methods of the NWDoc class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
assert theProject.openProject(nwMinimal)
assert theProject.projPath == nwMinimal
@@ -151,15 +149,14 @@ def testCoreDocument_Methods(dummyGUI, nwMinimal):
# Add meta data garbage
assert theDoc.writeDocument("%%~ stuff\n### Test File\n\nText ...\n\n")
- with open(docPath, mode="r", encoding="utf8") as inFile:
- assert inFile.read() == (
- "%%~name: New Scene\n"
- f"%%~path: a6d311a93600a/{sHandle}\n"
- "%%~kind: NOVEL/SCENE\n"
- "%%~ stuff\n"
- "### Test File\n\n"
- "Text ...\n\n"
- )
+ assert readFile(docPath) == (
+ "%%~name: New Scene\n"
+ f"%%~path: a6d311a93600a/{sHandle}\n"
+ "%%~kind: NOVEL/SCENE\n"
+ "%%~ stuff\n"
+ "### Test File\n\n"
+ "Text ...\n\n"
+ )
assert theDoc.readDocument() == "### Test File\n\nText ...\n\n"
diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py
index 4dcbbfd2..e82ed90e 100644
--- a/tests/test_core/test_core_index.py
+++ b/tests/test_core/test_core_index.py
@@ -34,7 +34,7 @@ from nw.enum import nwItemClass, nwItemLayout
@pytest.mark.core
-def testCoreIndex_LoadSave(monkeypatch, nwLipsum, dummyGUI, outDir, refDir):
+def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
"""Test core functionality of scaning, saving, loading and checking
the index cache file.
"""
@@ -42,7 +42,7 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, dummyGUI, outDir, refDir):
testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwLipsum)
@@ -126,10 +126,10 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, dummyGUI, outDir, refDir):
@pytest.mark.core
-def testCoreIndex_ScanThis(nwMinimal, dummyGUI):
+def testCoreIndex_ScanThis(nwMinimal, mockGUI):
"""Test the tag scanner function scanThis.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
@@ -178,10 +178,10 @@ def testCoreIndex_ScanThis(nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreIndex_CheckThese(nwMinimal, dummyGUI):
+def testCoreIndex_CheckThese(nwMinimal, mockGUI):
"""Test the tag checker function checkThese.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
@@ -240,10 +240,10 @@ def testCoreIndex_CheckThese(nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreIndex_ScanText(nwMinimal, dummyGUI):
+def testCoreIndex_ScanText(nwMinimal, mockGUI):
"""Check the index text scanner.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
@@ -446,10 +446,10 @@ def testCoreIndex_ScanText(nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
+def testCoreIndex_ExtractData(nwMinimal, mockGUI):
"""Check the index data extraction functions.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
@@ -679,10 +679,10 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreIndex_CheckTagIndex(dummyGUI):
+def testCoreIndex_CheckTagIndex(mockGUI):
"""Test the tag index checker.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theIndex = NWIndex(theProject)
# Valid Index
@@ -744,10 +744,10 @@ def testCoreIndex_CheckTagIndex(dummyGUI):
@pytest.mark.core
-def testCoreIndex_CheckRefIndex(dummyGUI):
+def testCoreIndex_CheckRefIndex(mockGUI):
"""Test the reference index checker.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theIndex = NWIndex(theProject)
# Valid Index
@@ -867,10 +867,10 @@ def testCoreIndex_CheckRefIndex(dummyGUI):
@pytest.mark.core
-def testCoreIndex_CheckNovelNoteIndex(dummyGUI):
+def testCoreIndex_CheckNovelNoteIndex(mockGUI):
"""Test the novel and note index checkers.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theIndex = NWIndex(theProject)
# Valid Index
@@ -1126,10 +1126,10 @@ def testCoreIndex_CheckNovelNoteIndex(dummyGUI):
@pytest.mark.core
-def testCoreIndex_CheckTextCounts(dummyGUI):
+def testCoreIndex_CheckTextCounts(mockGUI):
"""Test the text counts checker.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theIndex = NWIndex(theProject)
# Valid Index
diff --git a/tests/test_core/test_core_item.py b/tests/test_core/test_core_item.py
index 9f9a2432..6b2df2b2 100644
--- a/tests/test_core/test_core_item.py
+++ b/tests/test_core/test_core_item.py
@@ -29,10 +29,10 @@ from nw.enum import nwItemClass, nwItemType, nwItemLayout
@pytest.mark.core
-def testCoreItem_Setters(dummyGUI):
+def testCoreItem_Setters(mockGUI):
"""Test all the simple setters for the NWItem class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theItem = NWItem(theProject)
# Name
@@ -167,11 +167,11 @@ def testCoreItem_Setters(dummyGUI):
@pytest.mark.core
-def testCoreItem_TypeSetter(dummyGUI):
+def testCoreItem_TypeSetter(mockGUI):
"""Test the setter for all the nwItemType values for the NWItem
class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theItem = NWItem(theProject)
# Type
@@ -196,11 +196,11 @@ def testCoreItem_TypeSetter(dummyGUI):
@pytest.mark.core
-def testCoreItem_ClassSetter(dummyGUI):
+def testCoreItem_ClassSetter(mockGUI):
"""Test the setter for all the nwItemClass values for the NWItem
class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theItem = NWItem(theProject)
# Class
@@ -237,11 +237,11 @@ def testCoreItem_ClassSetter(dummyGUI):
@pytest.mark.core
-def testCoreItem_LayoutSetter(dummyGUI):
+def testCoreItem_LayoutSetter(mockGUI):
"""Test the setter for all the nwItemLayout values for the NWItem
class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theItem = NWItem(theProject)
# Layout
@@ -274,10 +274,10 @@ def testCoreItem_LayoutSetter(dummyGUI):
@pytest.mark.core
-def testCoreItem_XMLPackUnpack(dummyGUI, caplog):
+def testCoreItem_XMLPackUnpack(mockGUI, caplog):
"""Test packing and unpacking XML objects for the NWItem class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
nwXML = etree.Element("novelWriterXML")
# File
diff --git a/tests/test_core/test_core_options.py b/tests/test_core/test_core_options.py
index d41ba293..a01bcd45 100644
--- a/tests/test_core/test_core_options.py
+++ b/tests/test_core/test_core_options.py
@@ -24,6 +24,7 @@ import json
import pytest
from mock import causeOSError
+from tools import writeFile
from nw.core import NWProject
from nw.core.options import OptionState
@@ -31,28 +32,27 @@ from nw.constants import nwFiles
@pytest.mark.core
-def testCoreOptions_LoadSave(monkeypatch, dummyGUI, tmpDir):
+def testCoreOptions_LoadSave(monkeypatch, mockGUI, tmpDir):
"""Test loading and saving from the OptionState class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
# Write a test file
optFile = os.path.join(tmpDir, nwFiles.OPTS_FILE)
- with open(optFile, mode="w+", encoding="utf8") as outFile:
- json.dump({
- "GuiBuildNovel": {
- "winWidth": 1000,
- "winHeight": 700,
- "addNovel": True,
- "addNotes": False,
- "textFont": "Cantarell",
- "dummyItem": None,
- },
- "DummyGroup": {
- "dummyItem": None,
- },
- }, outFile)
+ writeFile(optFile, json.dumps({
+ "GuiBuildNovel": {
+ "winWidth": 1000,
+ "winHeight": 700,
+ "addNovel": True,
+ "addNotes": False,
+ "textFont": "Cantarell",
+ "dummyItem": None,
+ },
+ "DummyGroup": {
+ "dummyItem": None,
+ },
+ }))
# Load and save with no path set
theProject.projMeta = None
@@ -102,10 +102,10 @@ def testCoreOptions_LoadSave(monkeypatch, dummyGUI, tmpDir):
@pytest.mark.core
-def testCoreOptions_SetGet(dummyGUI):
+def testCoreOptions_SetGet(mockGUI):
"""Test setting and getting values from the OptionState class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
# Set invalid values
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 7bc6b612..801c8803 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -36,7 +36,7 @@ from nw.constants import nwFiles
@pytest.mark.core
-def testCoreProject_NewMinimal(fncDir, outDir, refDir, dummyGUI):
+def testCoreProject_NewMinimal(fncDir, outDir, refDir, mockGUI):
"""Create a new project from a project wizard dictionary. With
default setting, creating a Minimal project.
"""
@@ -44,7 +44,7 @@ def testCoreProject_NewMinimal(fncDir, outDir, refDir, dummyGUI):
testFile = os.path.join(outDir, "coreProject_NewMinimal_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewMinimal_nwProject.nwx")
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
# Setting no data should fail
@@ -85,7 +85,7 @@ def testCoreProject_NewMinimal(fncDir, outDir, refDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI):
+def testCoreProject_NewCustomA(fncDir, outDir, refDir, mockGUI):
"""Create a new project from a project wizard dictionary.
Custom type with chapters and scenes.
"""
@@ -113,7 +113,7 @@ def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI):
"numScenes": 3,
"chFolders": True,
}
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.newProject(projData)
@@ -127,7 +127,7 @@ def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_NewCustomB(fncDir, outDir, refDir, dummyGUI):
+def testCoreProject_NewCustomB(fncDir, outDir, refDir, mockGUI):
"""Create a new project from a project wizard dictionary.
Custom type without chapters, but with scenes.
"""
@@ -155,7 +155,7 @@ def testCoreProject_NewCustomB(fncDir, outDir, refDir, dummyGUI):
"numScenes": 6,
"chFolders": True,
}
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.newProject(projData)
@@ -169,7 +169,7 @@ def testCoreProject_NewCustomB(fncDir, outDir, refDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_NewSampleA(fncDir, tmpConf, dummyGUI, tmpDir):
+def testCoreProject_NewSampleA(fncDir, tmpConf, mockGUI, tmpDir):
"""Check that we can create a new project can be created from the
provided sample project via a zip file.
"""
@@ -182,7 +182,7 @@ def testCoreProject_NewSampleA(fncDir, tmpConf, dummyGUI, tmpDir):
"popMinimal": False,
"popCustom": False,
}
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
# Sample set, but no path
@@ -218,7 +218,7 @@ def testCoreProject_NewSampleA(fncDir, tmpConf, dummyGUI, tmpDir):
@pytest.mark.core
-def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, dummyGUI, tmpDir):
+def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, mockGUI, tmpDir):
"""Check that we can create a new project can be created from the
provided sample project folder.
"""
@@ -231,7 +231,7 @@ def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, dummyGUI, tmpDir):
"popMinimal": False,
"popCustom": False,
}
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
# Make sure we do not pick up the nw/assets/sample.zip file
@@ -256,14 +256,14 @@ def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, dummyGUI, tmpDir):
@pytest.mark.core
-def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI):
+def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI):
"""Check that new root folders can be added to the project.
"""
projFile = os.path.join(fncDir, "nwProject.nwx")
testFile = os.path.join(outDir, "coreProject_NewRoot_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewRoot_nwProject.nwx")
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.newProject({"projPath": fncDir})
@@ -293,14 +293,14 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI):
+def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI):
"""Check that new files can be added to the project.
"""
projFile = os.path.join(fncDir, "nwProject.nwx")
testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx")
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.newProject({"projPath": fncDir})
@@ -323,10 +323,10 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI):
+def testCoreProject_Open(monkeypatch, nwMinimal, mockGUI):
"""Test opening a project.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
# Rename the project file to check handling
rName = os.path.join(nwMinimal, nwFiles.PROJ_FILE)
@@ -382,9 +382,9 @@ def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI):
"timeStamp=\"2020-01-01 00:00:00\">\n"
"\n"
))
- dummyGUI.askResponse = False
+ mockGUI.askResponse = False
assert theProject.openProject(nwMinimal) is False
- dummyGUI.undo()
+ mockGUI.undo()
# Future file version
writeFile(rName, (
@@ -408,9 +408,9 @@ def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI):
"timeStamp=\"2020-01-01 00:00:00\">\n"
"\n"
))
- dummyGUI.askResponse = False
+ mockGUI.askResponse = False
assert theProject.openProject(nwMinimal) is False
- dummyGUI.undo()
+ mockGUI.undo()
# Test skipping XML entries
writeFile(rName, (
@@ -436,19 +436,19 @@ def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI):
writeFile(os.path.join(nwMinimal, "junk"), "stuff")
os.mkdir(os.path.join(nwMinimal, "data_0"))
writeFile(os.path.join(nwMinimal, "data_0", "junk"), "stuff")
- dummyGUI.clear()
+ mockGUI.clear()
assert theProject.openProject(nwMinimal) is True
- assert "data_0" in dummyGUI.lastAlert
+ assert "data_0" in mockGUI.lastAlert
assert theProject.closeProject()
# END Test testCoreProject_Open
@pytest.mark.core
-def testCoreProject_Save(monkeypatch, nwMinimal, dummyGUI, refDir):
+def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
"""Test saving a project.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
testFile = os.path.join(nwMinimal, "nwProject.nwx")
compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx")
@@ -491,10 +491,10 @@ def testCoreProject_Save(monkeypatch, nwMinimal, dummyGUI, refDir):
@pytest.mark.core
-def testCoreProject_LockFile(monkeypatch, fncDir, dummyGUI):
+def testCoreProject_LockFile(monkeypatch, fncDir, mockGUI):
"""Test lock file functions for the project folder.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
lockFile = os.path.join(fncDir, nwFiles.PROJ_LOCK)
@@ -551,10 +551,10 @@ def testCoreProject_LockFile(monkeypatch, fncDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_Helpers(monkeypatch, fncDir, dummyGUI):
+def testCoreProject_Helpers(monkeypatch, fncDir, mockGUI):
"""Test helper functions for the project folder.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
# No path
assert theProject.ensureFolderStructure() is False
@@ -595,10 +595,10 @@ def testCoreProject_Helpers(monkeypatch, fncDir, dummyGUI):
@pytest.mark.core
-def testCoreProject_AccessItems(nwMinimal, dummyGUI):
+def testCoreProject_AccessItems(nwMinimal, mockGUI):
"""Test helper functions for the project folder.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.openProject(nwMinimal)
# Move Novel ROOT to after its files
@@ -655,10 +655,10 @@ def testCoreProject_AccessItems(nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI, tmpDir):
+def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
"""Test other project class methods and functions.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
assert theProject.projPath == nwMinimal
@@ -906,13 +906,13 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI, tmpDir):
@pytest.mark.core
-def testCoreProject_OrphanedFiles(dummyGUI, nwLipsum):
+def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
"""Check that files in the content folder that are not tracked in
the project XML file are handled correctly by the orphaned files
function. It should also restore as much meta data as possible from
the meta line at the top of the document file.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
assert theProject.openProject(nwLipsum)
assert theProject.projTree["636b6aa9b697b"] is None
@@ -920,32 +920,29 @@ def testCoreProject_OrphanedFiles(dummyGUI, nwLipsum):
# First Item with Meta Data
orphPath = os.path.join(nwLipsum, "content", "636b6aa9b697b.nwd")
- with open(orphPath, mode="w", encoding="utf8") as outFile:
- outFile.write("%%~name:[Recovered] Mars\n")
- outFile.write("%%~path:5eaea4e8cdee8/636b6aa9b697b\n")
- outFile.write("%%~kind:WORLD/NOTE\n")
- outFile.write("%%~invalid\n")
- outFile.write("\n")
+ writeFile(orphPath, (
+ "%%~name:[Recovered] Mars\n"
+ "%%~path:5eaea4e8cdee8/636b6aa9b697b\n"
+ "%%~kind:WORLD/NOTE\n"
+ "%%~invalid\n"
+ "\n"
+ ))
# Second Item without Meta Data
orphPath = os.path.join(nwLipsum, "content", "736b6aa9b697b.nwd")
- with open(orphPath, mode="w", encoding="utf8") as outFile:
- outFile.write("\n")
+ writeFile(orphPath, "\n")
# Invalid File Name
- dummyPath = os.path.join(nwLipsum, "content", "636b6aa9b697b.txt")
- with open(dummyPath, mode="w", encoding="utf8") as outFile:
- outFile.write("\n")
+ tstPath = os.path.join(nwLipsum, "content", "636b6aa9b697b.txt")
+ writeFile(tstPath, "\n")
# Invalid File Name
- dummyPath = os.path.join(nwLipsum, "content", "636b6aa9b697bb.nwd")
- with open(dummyPath, mode="w", encoding="utf8") as outFile:
- outFile.write("\n")
+ tstPath = os.path.join(nwLipsum, "content", "636b6aa9b697bb.nwd")
+ writeFile(tstPath, "\n")
# Invalid File Name
- dummyPath = os.path.join(nwLipsum, "content", "abcdefghijklm.nwd")
- with open(dummyPath, mode="w", encoding="utf8") as outFile:
- outFile.write("\n")
+ tstPath = os.path.join(nwLipsum, "content", "abcdefghijklm.nwd")
+ writeFile(tstPath, "\n")
assert theProject.openProject(nwLipsum)
assert theProject.projPath is not None
@@ -983,13 +980,13 @@ def testCoreProject_OrphanedFiles(dummyGUI, nwLipsum):
@pytest.mark.core
-def testCoreProject_OldFormat(dummyGUI, nwOldProj):
+def testCoreProject_OldFormat(mockGUI, nwOldProj):
"""Test that a project folder structure of version 1.0 can be
converted to the latest folder structure. Version 1.0 split the
documents into 'data_0' ... 'data_f' folders, which are now all
contained in a single 'content' folder.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
# Create mock files for known legacy files
deleteFiles = [
@@ -1073,11 +1070,11 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj):
@pytest.mark.core
-def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir):
+def testCoreProject_LegacyData(monkeypatch, mockGUI, fncDir):
"""Test the functins that handle legacy data folders and structure
with additional tests of failure handling.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.setProjectPath(fncDir)
# assert theProject.newProject({"projPath": fncDir})
@@ -1179,21 +1176,21 @@ def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir):
@pytest.mark.core
-def testCoreProject_Backup(monkeypatch, dummyGUI, nwMinimal, tmpDir):
+def testCoreProject_Backup(monkeypatch, mockGUI, nwMinimal, tmpDir):
"""Test the automated backup feature of the project class. The test
creates a backup of the Minimal test project, and then unzips the
backupd file and checks that the project XML file is identical to
the original file.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
assert theProject.openProject(nwMinimal)
# Test faulty settings
# No project
- dummyGUI.hasProject = False
+ mockGUI.hasProject = False
assert not theProject.zipIt(doNotify=False)
- dummyGUI.hasProject = True
+ mockGUI.hasProject = True
# Invalid path
theProject.mainConf.backupPath = None
diff --git a/tests/test_core/test_core_tohtml.py b/tests/test_core/test_core_tohtml.py
index cff7798f..30185f42 100644
--- a/tests/test_core/test_core_tohtml.py
+++ b/tests/test_core/test_core_tohtml.py
@@ -28,11 +28,11 @@ from nw.core import NWProject, NWIndex, ToHtml
@pytest.mark.core
-def testCoreToHtml_Format(dummyGUI):
+def testCoreToHtml_Format(mockGUI):
"""Test all the formatters for the ToHtml class.
"""
- theProject = NWProject(dummyGUI)
- dummyGUI.theIndex = NWIndex(theProject)
+ theProject = NWProject(mockGUI)
+ mockGUI.theIndex = NWIndex(theProject)
theHtml = ToHtml(theProject)
# Export Mode
@@ -81,11 +81,11 @@ def testCoreToHtml_Format(dummyGUI):
@pytest.mark.core
-def testCoreToHtml_Convert(dummyGUI):
+def testCoreToHtml_Convert(mockGUI):
"""Test the converter of the ToHtml class.
"""
- theProject = NWProject(dummyGUI)
- dummyGUI.theIndex = NWIndex(theProject)
+ theProject = NWProject(mockGUI)
+ mockGUI.theIndex = NWIndex(theProject)
theHtml = ToHtml(theProject)
# Export Mode
@@ -347,10 +347,10 @@ def testCoreToHtml_Convert(dummyGUI):
@pytest.mark.core
-def testCoreToHtml_Complex(dummyGUI, fncDir):
+def testCoreToHtml_Complex(mockGUI, fncDir):
"""Test the ave method of the ToHtml class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theHtml = ToHtml(theProject)
# Build Project
@@ -421,10 +421,10 @@ def testCoreToHtml_Complex(dummyGUI, fncDir):
@pytest.mark.core
-def testCoreToHtml_Methods(dummyGUI):
+def testCoreToHtml_Methods(mockGUI):
"""Test all the other methods of the ToHtml class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theHtml = ToHtml(theProject)
theHtml.setKeepMarkdown(True)
diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py
index 5202edb2..37623d86 100644
--- a/tests/test_core/test_core_tokenizer.py
+++ b/tests/test_core/test_core_tokenizer.py
@@ -29,10 +29,10 @@ from nw.core.tokenizer import Tokenizer
@pytest.mark.core
-def testCoreToken_Setters(dummyGUI):
+def testCoreToken_Setters(mockGUI):
"""Test all the setters for the Tokenizer class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theToken = Tokenizer(theProject)
# Verify defaults
@@ -113,10 +113,10 @@ def testCoreToken_Setters(dummyGUI):
@pytest.mark.core
-def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI):
+def testCoreToken_TextOps(monkeypatch, nwMinimal, mockGUI):
"""Test handling files and text in the Tokenizer class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
theProject.projLang = "en"
theProject._loadProjectLocalisation()
@@ -196,10 +196,10 @@ def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI):
@pytest.mark.core
-def testCoreToken_Tokenize(dummyGUI):
+def testCoreToken_Tokenize(mockGUI):
"""Test the tokenization of the Tokenizer class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theToken = Tokenizer(theProject)
theToken.setKeepMarkdown(True)
@@ -498,10 +498,10 @@ def testCoreToken_Tokenize(dummyGUI):
@pytest.mark.core
-def testCoreToken_Headers(dummyGUI):
+def testCoreToken_Headers(mockGUI):
"""Test the header and page parser of the Tokenizer class.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theProject.projLang = "en"
theProject._loadProjectLocalisation()
theToken = Tokenizer(theProject)
diff --git a/tests/test_core/test_core_toodt.py b/tests/test_core/test_core_toodt.py
index 0221c8b4..aa5bcdeb 100644
--- a/tests/test_core/test_core_toodt.py
+++ b/tests/test_core/test_core_toodt.py
@@ -45,11 +45,11 @@ def xmlToText(xElem):
@pytest.mark.core
-def testCoreToOdt_Convert(dummyGUI):
+def testCoreToOdt_Convert(mockGUI):
"""Test the converter of the ToHtml class.
"""
- theProject = NWProject(dummyGUI)
- dummyGUI.theIndex = NWIndex(theProject)
+ theProject = NWProject(mockGUI)
+ mockGUI.theIndex = NWIndex(theProject)
theDoc = ToOdt(theProject, isFlat=True)
# Export Mode
diff --git a/tests/test_core/test_core_tree.py b/tests/test_core/test_core_tree.py
index 6be08c31..50e52422 100644
--- a/tests/test_core/test_core_tree.py
+++ b/tests/test_core/test_core_tree.py
@@ -25,16 +25,18 @@ import pytest
from lxml import etree
from hashlib import sha256
+from tools import readFile
+
from nw.core.project import NWProject, NWItem, NWTree
from nw.enum import nwItemClass, nwItemType, nwItemLayout
from nw.constants import nwFiles
@pytest.fixture(scope="function")
-def dummyItems(dummyGUI):
+def dummyItems(mockGUI):
"""Create a list of mock items.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
itemA = NWItem(theProject)
itemA.itemName = "Novel"
@@ -108,10 +110,10 @@ def dummyItems(dummyGUI):
@pytest.mark.core
-def testCoreTree_BuildTree(dummyGUI, dummyItems):
+def testCoreTree_BuildTree(mockGUI, dummyItems):
"""Test building a project tree from a list of items.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
theTree.setSeed(42)
@@ -205,10 +207,10 @@ def testCoreTree_BuildTree(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_Methods(dummyGUI, dummyItems):
+def testCoreTree_Methods(mockGUI, dummyItems):
"""Test bvarious class methods.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
for tHandle, pHandle, nwItem in dummyItems:
@@ -262,10 +264,10 @@ def testCoreTree_Methods(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_UpdateItemLayout(dummyGUI, dummyItems):
+def testCoreTree_UpdateItemLayout(mockGUI, dummyItems):
"""Test building a project tree from a list of items.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
for tHandle, pHandle, nwItem in dummyItems:
@@ -388,10 +390,10 @@ def testCoreTree_UpdateItemLayout(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_MakeHandles(monkeypatch, dummyGUI):
+def testCoreTree_MakeHandles(monkeypatch, mockGUI):
"""Test generating item handles.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
theTree.setSeed(42)
@@ -431,10 +433,10 @@ def testCoreTree_MakeHandles(monkeypatch, dummyGUI):
@pytest.mark.core
-def testCoreTree_Stats(dummyGUI, dummyItems):
+def testCoreTree_Stats(mockGUI, dummyItems):
"""Test project stats methods.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
for tHandle, pHandle, nwItem in dummyItems:
@@ -458,10 +460,10 @@ def testCoreTree_Stats(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_Reorder(dummyGUI, dummyItems):
+def testCoreTree_Reorder(mockGUI, dummyItems):
"""Test changing tree order.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
aHandle = []
@@ -490,10 +492,10 @@ def testCoreTree_Reorder(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_XMLPackUnpack(dummyGUI, dummyItems):
+def testCoreTree_XMLPackUnpack(mockGUI, dummyItems):
"""Test packing and unpacking the tree to and from XML.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
for tHandle, pHandle, nwItem in dummyItems:
@@ -546,10 +548,10 @@ def testCoreTree_XMLPackUnpack(dummyGUI, dummyItems):
@pytest.mark.core
-def testCoreTree_ToCFile(monkeypatch, dummyGUI, dummyItems, tmpDir):
+def testCoreTree_ToCFile(monkeypatch, mockGUI, dummyItems, tmpDir):
"""Test writing the ToC.txt file.
"""
- theProject = NWProject(dummyGUI)
+ theProject = NWProject(mockGUI)
theTree = NWTree(theProject)
for tHandle, pHandle, nwItem in dummyItems:
@@ -579,17 +581,16 @@ def testCoreTree_ToCFile(monkeypatch, dummyGUI, dummyItems, tmpDir):
pathB = os.path.join("content", "c000000000002.nwd")
pathC = os.path.join("content", "b000000000002.nwd")
- with open(os.path.join(tmpDir, nwFiles.TOC_TXT), mode="r", encoding="utf8") as inFile:
- assert inFile.read() == (
- "\n"
- "Table of Contents\n"
- "=================\n"
- "\n"
- "File Name Class Layout Document Label\n"
- "-------------------------------------------------------------\n"
- f"{pathA} NOVEL CHAPTER Chapter One\n"
- f"{pathB} NOVEL SCENE Scene One\n"
- f"{pathC} CHARACTER NOTE Jane Doe\n"
- )
+ assert readFile(os.path.join(tmpDir, nwFiles.TOC_TXT)) == (
+ "\n"
+ "Table of Contents\n"
+ "=================\n"
+ "\n"
+ "File Name Class Layout Document Label\n"
+ "-------------------------------------------------------------\n"
+ f"{pathA} NOVEL CHAPTER Chapter One\n"
+ f"{pathB} NOVEL SCENE Scene One\n"
+ f"{pathC} CHARACTER NOTE Jane Doe\n"
+ )
# END Test testCoreTree_ToCFile
diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py
index 9eacb197..1abd1dab 100644
--- a/tests/test_gui/test_gui_mainmenu.py
+++ b/tests/test_gui/test_gui_mainmenu.py
@@ -26,6 +26,8 @@ from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextCursor, QTextBlock
from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
+from tools import writeFile
+
from nw.gui.doceditor import GuiDocEditor
from nw.enum import nwDocAction, nwDocInsert, nwWidget
from nw.constants import nwKeyWords, nwUnicode
@@ -659,8 +661,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
assert not nwGUI.importDocument()
# Create the file and try again, but with no target document open
- with open(theFile, mode="w+", encoding="utf8") as outFile:
- outFile.write("Foo")
+ writeFile(theFile, "Foo")
assert not nwGUI.importDocument()
# Open the document from before, and add some text to it
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 83a9d57f..ee1c81db 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -54,7 +54,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
qtbot.mouseClick(nwGUI.projView, Qt.LeftButton)
nwGUI.projView._loadHeaderState()
- assert not nwGUI.projView.colHidden[nwOutline.CCOUNT]
+ assert not nwGUI.projView._colHidden[nwOutline.CCOUNT]
# First Item
nwGUI.rebuildOutline()
diff --git a/tests/tools.py b/tests/tools.py
index 6c8b2512..03f23d34 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -32,13 +32,13 @@ def cmpFiles(fileOne, fileTwo, ignoreLines=None):
ignoreLines = []
try:
- foOne = open(fileOne, mode="r", encoding="utf8")
+ foOne = open(fileOne, mode="r", encoding="utf-8")
except Exception as e:
print(str(e))
return False
try:
- foTwo = open(fileTwo, mode="r", encoding="utf8")
+ foTwo = open(fileTwo, mode="r", encoding="utf-8")
except Exception as e:
print(str(e))
return False
@@ -83,14 +83,14 @@ def getGuiItem(theName):
def readFile(fileName):
"""Returns the content of a file as a string.
"""
- with open(fileName, mode="r", encoding="utf8") as inFile:
+ with open(fileName, mode="r", encoding="utf-8") as inFile:
return inFile.read()
def writeFile(fileName, fileData):
"""Write the contents of a string to a file.
"""
- with open(fileName, mode="w", encoding="utf8") as outFile:
+ with open(fileName, mode="w", encoding="utf-8") as outFile:
outFile.write(fileData)