Merge branch 'dev' into item_layouts
This commit is contained in:
+162
-30
@@ -36,11 +36,13 @@ from nw.constants import (
|
||||
)
|
||||
from nw.core.document import NWDoc
|
||||
from nw.core.tools import countWords
|
||||
from nw.common import isHandle, isTitleTag, isItemClass, isItemLayout
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class NWIndex():
|
||||
|
||||
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
||||
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||
|
||||
def __init__(self, theProject, theParent):
|
||||
@@ -155,9 +157,14 @@ class NWIndex():
|
||||
try:
|
||||
with open(indexFile, mode="r", encoding="utf8") as inFile:
|
||||
theData = json.load(inFile)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to load index file")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
self.indexBroken = True
|
||||
self.theParent.makeAlert(
|
||||
"Could not load cached index file. Rebuilding index.",
|
||||
nwAlert.WARN
|
||||
)
|
||||
return False
|
||||
|
||||
self._tagIndex = theData.get("tagIndex", {})
|
||||
@@ -193,9 +200,9 @@ class NWIndex():
|
||||
"textCounts" : self._textCounts,
|
||||
"firstTitle" : self._firstTitle,
|
||||
}, outFile, indent=2)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to save index file")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -205,43 +212,29 @@ class NWIndex():
|
||||
elements it should.
|
||||
"""
|
||||
logger.debug("Checking index")
|
||||
self.indexBroken = False
|
||||
tStart = time()
|
||||
|
||||
try:
|
||||
for tTag in self._tagIndex:
|
||||
if len(self._tagIndex[tTag]) != 4:
|
||||
self.indexBroken = True
|
||||
|
||||
for tHandle in self._refIndex:
|
||||
for sTitle in self._refIndex[tHandle]:
|
||||
for tEntry in self._refIndex[tHandle][sTitle]["tags"]:
|
||||
if len(tEntry) != 3:
|
||||
self.indexBroken = True
|
||||
|
||||
for tHandle in self._novelIndex:
|
||||
for sLine in self._novelIndex[tHandle]:
|
||||
if len(self._novelIndex[tHandle][sLine].keys()) != 8:
|
||||
self.indexBroken = True
|
||||
|
||||
for tHandle in self._noteIndex:
|
||||
for sLine in self._noteIndex[tHandle]:
|
||||
if len(self._noteIndex[tHandle][sLine].keys()) != 8:
|
||||
self.indexBroken = True
|
||||
|
||||
for tHandle in self._textCounts:
|
||||
if len(self._textCounts[tHandle]) != 3:
|
||||
self.indexBroken = True
|
||||
self._checkTagIndex()
|
||||
self._checkRefIndex()
|
||||
self._checkNovelNoteIndex("novelIndex")
|
||||
self._checkNovelNoteIndex("noteIndex")
|
||||
self._checkTextCounts()
|
||||
self.indexBroken = False
|
||||
|
||||
for tHandle in self._firstTitle:
|
||||
if len(self._firstTitle[tHandle]) != 2:
|
||||
self.indexBroken = True
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Error while checking index")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
self.indexBroken = True
|
||||
|
||||
tEnd = time()
|
||||
logger.debug("Index check took %.3f ms" % ((tEnd - tStart)*1000))
|
||||
logger.debug("Index check complete")
|
||||
|
||||
if self.indexBroken:
|
||||
self.clearIndex()
|
||||
self.theParent.makeAlert(
|
||||
@@ -765,4 +758,143 @@ class NWIndex():
|
||||
|
||||
return theHandles
|
||||
|
||||
##
|
||||
# Index Checkers
|
||||
##
|
||||
|
||||
def _checkTagIndex(self):
|
||||
"""Scan the tag index for errors.
|
||||
Waring: This function raises exceptions.
|
||||
"""
|
||||
for tTag in self._tagIndex:
|
||||
if not isinstance(tTag, str):
|
||||
raise KeyError("tagIndex key is not a string")
|
||||
|
||||
tEntry = self._tagIndex[tTag]
|
||||
if len(tEntry) != 4:
|
||||
raise IndexError("tagIndex[a] expected 4 values")
|
||||
if not isinstance(tEntry[0], int):
|
||||
raise ValueError("tagIndex[a][0] is not an integer")
|
||||
if not isHandle(tEntry[1]):
|
||||
raise ValueError("tagIndex[a][1] is not a handle")
|
||||
if not isItemClass(tEntry[2]):
|
||||
raise ValueError("tagIndex[a][2] is not an nwItemClass")
|
||||
if not isTitleTag(tEntry[3]):
|
||||
raise ValueError("tagIndex[a][3] is not a title tag")
|
||||
|
||||
return
|
||||
|
||||
def _checkRefIndex(self):
|
||||
"""Scan the reference index for errors.
|
||||
Waring: This function raises exceptions.
|
||||
"""
|
||||
for tHandle in self._refIndex:
|
||||
if not isHandle(tHandle):
|
||||
raise KeyError("refIndex key is not a handle")
|
||||
|
||||
hEntry = self._refIndex[tHandle]
|
||||
for sTitle in hEntry:
|
||||
if not isTitleTag(sTitle):
|
||||
raise KeyError("refIndex[a] key is not a title tag")
|
||||
|
||||
sEntry = hEntry[sTitle]
|
||||
if "tags" not in sEntry:
|
||||
raise KeyError("refIndex[a][b] has no 'tag' key")
|
||||
for tEntry in sEntry["tags"]:
|
||||
if len(tEntry) != 3:
|
||||
raise IndexError("refIndex[a][b][tags][i] expected 3 values")
|
||||
if not isinstance(tEntry[0], int):
|
||||
raise ValueError("refIndex[a][b][tags][i][0] is not an integer")
|
||||
if not tEntry[1] in nwKeyWords.VALID_KEYS:
|
||||
raise ValueError("refIndex[a][b][tags][i][1] is not a keyword")
|
||||
if not isinstance(tEntry[2], str):
|
||||
raise ValueError("refIndex[a][b][tags][i][2] is not a string")
|
||||
|
||||
if "updated" not in sEntry:
|
||||
raise KeyError("refIndex[a][b] has no 'updated' key")
|
||||
if not isinstance(sEntry["updated"], int):
|
||||
raise ValueError("%refIndex[a][b][updated] is not an integer")
|
||||
|
||||
return
|
||||
|
||||
def _checkNovelNoteIndex(self, idxName):
|
||||
"""Scan the novel or note index for errors.
|
||||
Waring: This function raises exceptions.
|
||||
"""
|
||||
if idxName == "novelIndex":
|
||||
theIndex = self._novelIndex
|
||||
elif idxName == "noteIndex":
|
||||
theIndex = self._noteIndex
|
||||
else:
|
||||
raise IndexError("Unknown index %s" % idxName)
|
||||
|
||||
for tHandle in theIndex:
|
||||
if not isHandle(tHandle):
|
||||
raise KeyError("%s key is not a handle" % idxName)
|
||||
|
||||
hEntry = theIndex[tHandle]
|
||||
for sTitle in theIndex[tHandle]:
|
||||
if not isTitleTag(sTitle):
|
||||
raise KeyError("%s[a] key is not a title tag" % idxName)
|
||||
|
||||
sEntry = hEntry[sTitle]
|
||||
if len(sEntry) != 8:
|
||||
raise IndexError("%s[a][b] expected 8 values" % idxName)
|
||||
|
||||
if "level" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'level' key" % idxName)
|
||||
if "title" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'title' key" % idxName)
|
||||
if "layout" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'layout' key" % idxName)
|
||||
if "synopsis" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'synopsis' key" % idxName)
|
||||
if "cCount" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'cCount' key" % idxName)
|
||||
if "wCount" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'wCount' key" % idxName)
|
||||
if "pCount" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'pCount' key" % idxName)
|
||||
if "updated" not in sEntry:
|
||||
raise KeyError("%s[a][b] has no 'updated' key" % idxName)
|
||||
|
||||
if not sEntry["level"] in self.H_VALID:
|
||||
raise ValueError("%s[a][b][level] is not a header level" % idxName)
|
||||
if not isinstance(sEntry["title"], str):
|
||||
raise ValueError("%s[a][b][title] is not a string" % idxName)
|
||||
if not isItemLayout(sEntry["layout"]):
|
||||
raise ValueError("%s[a][b][layout] is not an nwItemLayout" % idxName)
|
||||
if not isinstance(sEntry["synopsis"], str):
|
||||
raise ValueError("%s[a][b][synopsis] is not a string" % idxName)
|
||||
if not isinstance(sEntry["cCount"], int):
|
||||
raise ValueError("%s[a][b][cCount] is not an integer" % idxName)
|
||||
if not isinstance(sEntry["wCount"], int):
|
||||
raise ValueError("%s[a][b][wCount] is not an integer" % idxName)
|
||||
if not isinstance(sEntry["pCount"], int):
|
||||
raise ValueError("%s[a][b][pCount] is not an integer" % idxName)
|
||||
if not isinstance(sEntry["updated"], int):
|
||||
raise ValueError("%s[a][b][updated] is not an integer" % idxName)
|
||||
|
||||
return
|
||||
|
||||
def _checkTextCounts(self):
|
||||
"""Scan the text counts index for errors.
|
||||
Waring: This function raises exceptions.
|
||||
"""
|
||||
for tHandle in self._textCounts:
|
||||
if not isHandle(tHandle):
|
||||
raise KeyError("textCounts key is not a handle")
|
||||
|
||||
tEntry = self._textCounts[tHandle]
|
||||
if len(tEntry) != 3:
|
||||
raise IndexError("textCounts[a] expected 3 values")
|
||||
if not isinstance(tEntry[0], int):
|
||||
raise ValueError("textCounts[a][0] is not an integer")
|
||||
if not isinstance(tEntry[1], int):
|
||||
raise ValueError("textCounts[a][1] is not an integer")
|
||||
if not isinstance(tEntry[2], int):
|
||||
raise ValueError("textCounts[a][2] is not an integer")
|
||||
|
||||
return
|
||||
|
||||
# END Class NWIndex
|
||||
|
||||
+6
-4
@@ -28,8 +28,10 @@ import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from nw.common import checkInt, isHandle
|
||||
from nw.constants import nwItemType, nwItemClass, nwItemLayout
|
||||
from nw.common import (
|
||||
checkInt, isHandle, isItemClass, isItemLayout, isItemType
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -201,7 +203,7 @@ class NWItem():
|
||||
"""
|
||||
if isinstance(theType, nwItemType):
|
||||
self.itemType = theType
|
||||
elif theType in nwItemType.__members__:
|
||||
elif isItemType(theType):
|
||||
self.itemType = nwItemType[theType]
|
||||
else:
|
||||
logger.error("Unrecognised item type '%s'" % theType)
|
||||
@@ -214,7 +216,7 @@ class NWItem():
|
||||
"""
|
||||
if isinstance(theClass, nwItemClass):
|
||||
self.itemClass = theClass
|
||||
elif theClass in nwItemClass.__members__:
|
||||
elif isItemClass(theClass):
|
||||
self.itemClass = nwItemClass[theClass]
|
||||
else:
|
||||
logger.error("Unrecognised item class '%s'" % theClass)
|
||||
@@ -227,7 +229,7 @@ class NWItem():
|
||||
"""
|
||||
if isinstance(theLayout, nwItemLayout):
|
||||
self.itemLayout = theLayout
|
||||
elif theLayout in nwItemLayout.__members__:
|
||||
elif isItemLayout(theLayout):
|
||||
self.itemLayout = nwItemLayout[theLayout]
|
||||
else:
|
||||
logger.error("Unrecognised item layout '%s'" % theLayout)
|
||||
|
||||
+5
-4
@@ -25,6 +25,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import nw
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
@@ -121,9 +122,9 @@ class OptionState():
|
||||
try:
|
||||
with open(stateFile, mode="r", encoding="utf8") as inFile:
|
||||
theState = json.load(inFile)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to load GUI options file")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
# Filter out unused variables
|
||||
@@ -148,9 +149,9 @@ class OptionState():
|
||||
try:
|
||||
with open(stateFile, mode="w+", encoding="utf8") as outFile:
|
||||
json.dump(self.theState, outFile, indent=2)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to save GUI options file")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
+23
-18
@@ -1219,9 +1219,9 @@ class NWProject():
|
||||
if len(theLines) != 4:
|
||||
return ["ERROR"]
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to read project lockfile")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return ["ERROR"]
|
||||
|
||||
return theLines
|
||||
@@ -1240,9 +1240,9 @@ class NWProject():
|
||||
outFile.write("%s\n" % self.mainConf.kernelVer)
|
||||
outFile.write("%d\n" % time())
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to write project lockfile")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -1257,9 +1257,9 @@ class NWProject():
|
||||
if os.path.isfile(lockFile):
|
||||
try:
|
||||
os.unlink(lockFile)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to remove project lockfile")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -1415,9 +1415,9 @@ class NWProject():
|
||||
self.notesWCount,
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to write session stats file")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -1453,17 +1453,19 @@ class NWProject():
|
||||
os.rename(theFile, newPath)
|
||||
logger.info("Moved file: %s" % theFile)
|
||||
logger.info("New location: %s" % newPath)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
errList.append("Could not move: %s" % theFile)
|
||||
logger.error("Could not move: %s" % theFile)
|
||||
nw.logException()
|
||||
|
||||
elif len(dataItem) == 21 and dataItem.endswith("_main.bak"):
|
||||
try:
|
||||
os.unlink(theFile)
|
||||
logger.info("Deleted file: %s" % theFile)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
errList.append("Could not delete: %s" % theFile)
|
||||
logger.error("Could not delete: %s" % theFile)
|
||||
nw.logException()
|
||||
|
||||
else:
|
||||
theErr = self._moveUnknownItem(theData, dataItem)
|
||||
@@ -1475,9 +1477,10 @@ class NWProject():
|
||||
try:
|
||||
os.rmdir(theData)
|
||||
logger.info("Removed folder: %s" % theFolder)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
errList.append("Failed to remove: %s" % theFolder)
|
||||
logger.error("Failed to remove: %s" % theFolder)
|
||||
nw.logException()
|
||||
|
||||
return errList
|
||||
|
||||
@@ -1495,8 +1498,9 @@ class NWProject():
|
||||
try:
|
||||
os.rename(theSrc, theDst)
|
||||
logger.info("Moved to junk: %s" % theSrc)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
logger.error("Could not move item %s to junk." % theSrc)
|
||||
nw.logException()
|
||||
return "Could not move item %s to junk." % theSrc
|
||||
|
||||
return ""
|
||||
@@ -1529,8 +1533,9 @@ class NWProject():
|
||||
logger.info("Deleting: %s" % rmFile)
|
||||
try:
|
||||
os.unlink(rmFile)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
logger.error("Could not delete: %s" % rmFile)
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -72,9 +72,9 @@ class NWSpellCheck():
|
||||
with open(self.projectDict, mode="a+", encoding="utf-8") as outFile:
|
||||
outFile.write("%s\n" % newWord)
|
||||
self.projDict.append(newWord)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to add word to project word list %s" % str(self.projectDict))
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
@@ -123,9 +123,9 @@ class NWSpellCheck():
|
||||
if len(theLine) > 0 and theLine not in self.projDict:
|
||||
self.projDict.append(theLine)
|
||||
logger.debug("Project word list contains %d words" % len(self.projDict))
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to load project word list")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -201,9 +201,9 @@ class NWSpellEnchant(NWSpellCheck):
|
||||
try:
|
||||
spTag = self.theDict.tag
|
||||
spName = self.theDict.provider.name
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to extract information about the dictionary")
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
spTag = ""
|
||||
spName = ""
|
||||
|
||||
@@ -261,9 +261,9 @@ class NWSpellSimple(NWSpellCheck):
|
||||
logger.debug("Spell check word list for language %s loaded" % theLang)
|
||||
logger.debug("Word list contains %d words" % len(self.WORDS))
|
||||
self.spellLanguage = theLang
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error("Failed to load spell check word list for language %s" % theLang)
|
||||
logger.error(str(e))
|
||||
nw.logException()
|
||||
self.spellLanguage = None
|
||||
|
||||
self._readProjectDictionary(projectDict)
|
||||
|
||||
+4
-2
@@ -24,6 +24,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import nw
|
||||
import logging
|
||||
import os
|
||||
|
||||
@@ -204,8 +205,9 @@ class NWTree():
|
||||
outFile.write("\n".join(tocList))
|
||||
outFile.write("\n")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
except Exception:
|
||||
logger.error("Could not write ToC file")
|
||||
nw.logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user