Move the spell check instance to the shared class

This commit is contained in:
Veronica Berglyd Olsen
2023-08-24 20:17:23 +02:00
parent 4507489f0b
commit f7ed133b2e
9 changed files with 95 additions and 98 deletions
+36 -34
View File
@@ -47,11 +47,15 @@ class NWSpellEnchant:
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
self._project = project self._project = project
self._dictObj = FakeEnchant() self._enchant = FakeEnchant()
self._userDict = UserDictionary(project) self._userDict = UserDictionary(project)
self._language = None self._language = None
self._broker = None self._broker = None
logger.debug("Enchant spell checking activated") logger.debug("Ready: NWSpellEnchant")
return
def __del__(self): # pragma: no cover
logger.debug("Delete: NWSpellEnchant")
return return
## ##
@@ -72,7 +76,7 @@ class NWSpellEnchant:
crash. Note that enchant will allow loading an empty string as crash. Note that enchant will allow loading an empty string as
a tag, but this will fail later on. See issue #1096. a tag, but this will fail later on. See issue #1096.
""" """
self._dictObj = FakeEnchant() self._enchant = FakeEnchant()
self._broker = None self._broker = None
self._language = None self._language = None
@@ -81,7 +85,7 @@ class NWSpellEnchant:
if language and enchant.dict_exists(language): if language and enchant.dict_exists(language):
self._broker = enchant.Broker() self._broker = enchant.Broker()
self._dictObj = self._broker.request_dict(language) self._enchant = self._broker.request_dict(language)
self._language = language self._language = language
logger.debug("Enchant spell checking for language '%s' loaded", language) logger.debug("Enchant spell checking for language '%s' loaded", language)
else: else:
@@ -90,12 +94,11 @@ class NWSpellEnchant:
except Exception: except Exception:
logger.error("Failed to load enchant spell checking for language '%s'", language) logger.error("Failed to load enchant spell checking for language '%s'", language)
if self._dictObj is None: if self._enchant is None:
self._dictObj = FakeEnchant() self._enchant = FakeEnchant()
else: else:
self._userDict.load() for word in self._userDict:
for pWord in self._userDict: self._enchant.add_to_session(word)
self._dictObj.add_to_session(pWord)
return return
@@ -106,14 +109,14 @@ class NWSpellEnchant:
def checkWord(self, word: str) -> bool: def checkWord(self, word: str) -> bool:
"""Wrapper function for pyenchant.""" """Wrapper function for pyenchant."""
try: try:
return bool(self._dictObj.check(word)) return bool(self._enchant.check(word))
except Exception: except Exception:
return True return True
def suggestWords(self, word: str) -> list[str]: def suggestWords(self, word: str) -> list[str]:
"""Wrapper function for pyenchant.""" """Wrapper function for pyenchant."""
try: try:
return self._dictObj.suggest(word) return self._enchant.suggest(word)
except Exception: except Exception:
return [] return []
@@ -123,7 +126,7 @@ class NWSpellEnchant:
if not word: if not word:
return False return False
try: try:
self._dictObj.add_to_session(word) self._enchant.add_to_session(word)
except Exception: except Exception:
return False return False
@@ -133,6 +136,11 @@ class NWSpellEnchant:
return added return added
def loadUserWordList(self) -> None:
"""Load the user word list from the project."""
self._userDict.load()
return
def listDictionaries(self) -> list[tuple[str, str]]: def listDictionaries(self) -> list[tuple[str, str]]:
"""Wrapper function for pyenchant.""" """Wrapper function for pyenchant."""
retList = [] retList = []
@@ -142,22 +150,18 @@ class NWSpellEnchant:
retList.append((spTag, spProvider.name)) retList.append((spTag, spProvider.name))
except Exception: except Exception:
logger.error("Failed to list languages for enchant spell checking") logger.error("Failed to list languages for enchant spell checking")
return retList return retList
def describeDict(self) -> tuple[str, str]: def describeDict(self) -> tuple[str, str]:
"""Return the tag and provider of the currently loaded """Describe the currently loaded dictionary."""
dictionary.
"""
try: try:
tag = self._dictObj.tag tag = self._enchant.tag
name = self._dictObj.provider.name # type: ignore name = self._enchant.provider.name # type: ignore
except Exception: except Exception:
logger.error("Failed to extract information about the dictionary") logger.error("Failed to extract information about the dictionary")
logException() logException()
tag = "" tag = ""
name = "" name = ""
return tag, name return tag, name
# END Class NWSpellEnchant # END Class NWSpellEnchant
@@ -192,7 +196,6 @@ class UserDictionary:
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
self._project = project self._project = project
self._words = set() self._words = set()
self._path = None
return return
def __contains__(self, word: str) -> bool: def __contains__(self, word: str) -> bool:
@@ -212,13 +215,14 @@ class UserDictionary:
def load(self) -> None: def load(self) -> None:
"""Load the user's dictionary.""" """Load the user's dictionary."""
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
self._words = set() self._words = set()
if isinstance(self._path, Path) and self._path.is_file(): wordList = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
if isinstance(wordList, Path) and wordList.is_file():
try: try:
with open(self._path, mode="r", encoding="utf-8") as fObj: with open(wordList, mode="r", encoding="utf-8") as fObj:
data = json.load(fObj) data = json.load(fObj)
self._words = set(data.get("novelWriter.userDict", [])) self._words = set(data.get("novelWriter.userDict", []))
logger.info("Loaded: %s", nwFiles.DICT_FILE)
except Exception: except Exception:
logger.error("Failed to load user dictionary") logger.error("Failed to load user dictionary")
logException() logException()
@@ -226,17 +230,15 @@ class UserDictionary:
def save(self) -> None: def save(self) -> None:
"""Save the user's dictionary.""" """Save the user's dictionary."""
if self._path is None: wordList = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE) if isinstance(wordList, Path):
if not isinstance(self._path, Path): try:
return with open(wordList, mode="w", encoding="utf-8") as fObj:
try: data = {"novelWriter.userDict": list(self._words)}
with open(self._path, mode="w", encoding="utf-8") as fObj: json.dump(data, fObj, indent=2)
data = {"novelWriter.userDict": list(self._words)} except Exception:
json.dump(data, fObj, indent=2) logger.error("Failed to save user dictionary")
except Exception: logException()
logger.error("Failed to save user dictionary")
logException()
return return
# END Class UserDictionary # END Class UserDictionary
+1 -5
View File
@@ -49,8 +49,6 @@ class GuiPreferences(NPagedDialog):
logger.debug("Create: GuiPreferences") logger.debug("Create: GuiPreferences")
self.setObjectName("GuiPreferences") self.setObjectName("GuiPreferences")
self.mainGui = mainGui
self.setWindowTitle(self.tr("Preferences")) self.setWindowTitle(self.tr("Preferences"))
self.tabGeneral = GuiPreferencesGeneral(self) self.tabGeneral = GuiPreferencesGeneral(self)
@@ -645,8 +643,6 @@ class GuiPreferencesEditor(QWidget):
def __init__(self, prefsGui): def __init__(self, prefsGui):
super().__init__(parent=prefsGui) super().__init__(parent=prefsGui)
self.mainGui = prefsGui.mainGui
# The Form # The Form
self.mainForm = NConfigLayout() self.mainForm = NConfigLayout()
self.mainForm.setHelpTextStyle(SHARED.theme.helpText) self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
@@ -662,7 +658,7 @@ class GuiPreferencesEditor(QWidget):
self.spellLanguage = QComboBox(self) self.spellLanguage = QComboBox(self)
self.spellLanguage.setMaximumWidth(mW) self.spellLanguage.setMaximumWidth(mW)
langAvail = self.mainGui.docEditor.spEnchant.listDictionaries() langAvail = SHARED.spelling.listDictionaries()
if CONFIG.hasEnchant and langAvail: if CONFIG.hasEnchant and langAvail:
for spTag, spProv in langAvail: for spTag, spProv in langAvail:
qLocal = QLocale(spTag) qLocal = QLocale(spTag)
+1 -3
View File
@@ -199,8 +199,6 @@ class GuiProjectEditMain(QWidget):
def __init__(self, projGui): def __init__(self, projGui):
super().__init__(parent=projGui) super().__init__(parent=projGui)
self.mainGui = projGui.mainGui
# The Form # The Form
self.mainForm = NConfigLayout() self.mainForm = NConfigLayout()
self.mainForm.setHelpTextStyle(SHARED.theme.helpText) self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
@@ -244,7 +242,7 @@ class GuiProjectEditMain(QWidget):
self.spellLang = QComboBox(self) self.spellLang = QComboBox(self)
self.spellLang.setMaximumWidth(xW) self.spellLang.setMaximumWidth(xW)
self.spellLang.addItem(self.tr("Default"), "None") self.spellLang.addItem(self.tr("Default"), "None")
langAvail = self.mainGui.docEditor.spEnchant.listDictionaries() langAvail = SHARED.spelling.listDictionaries()
for spTag, spProv in langAvail: for spTag, spProv in langAvail:
qLocal = QLocale(spTag) qLocal = QLocale(spTag)
spLang = qLocal.nativeLanguageName().title() spLang = qLocal.nativeLanguageName().title()
+20 -22
View File
@@ -54,7 +54,6 @@ from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass
from novelwriter.common import minmax, transferCase from novelwriter.common import minmax, transferCase
from novelwriter.constants import nwConst, nwKeyWords, nwUnicode from novelwriter.constants import nwConst, nwKeyWords, nwUnicode
from novelwriter.core.index import countWords from novelwriter.core.index import countWords
from novelwriter.core.spellcheck import NWSpellEnchant
from novelwriter.gui.dochighlight import GuiDocHighlighter from novelwriter.gui.dochighlight import GuiDocHighlighter
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
@@ -133,8 +132,7 @@ class GuiDocEditor(QTextEdit):
self.docSearch = GuiDocEditSearch(self) self.docSearch = GuiDocEditSearch(self)
# Syntax # Syntax
self.spEnchant = NWSpellEnchant(SHARED.project) self.highLight = GuiDocHighlighter(qDoc)
self.highLight = GuiDocHighlighter(qDoc, self.spEnchant)
# Context Menu # Context Menu
self.setContextMenuPolicy(Qt.CustomContextMenu) self.setContextMenuPolicy(Qt.CustomContextMenu)
@@ -702,8 +700,8 @@ class GuiDocEditor(QTextEdit):
else: else:
theLang = SHARED.project.data.spellLang theLang = SHARED.project.data.spellLang
self.spEnchant.setLanguage(theLang) SHARED.spelling.setLanguage(theLang)
_, theProvider = self.spEnchant.describeDict() _, theProvider = SHARED.spelling.describeDict()
self.spellDictionaryChanged.emit(str(theLang), str(theProvider)) self.spellDictionaryChanged.emit(str(theLang), str(theProvider))
if not self._bigDoc: if not self._bigDoc:
@@ -711,37 +709,37 @@ class GuiDocEditor(QTextEdit):
return True return True
def toggleSpellCheck(self, theMode): def toggleSpellCheck(self, state: bool) -> None:
"""This is the main spell check setting function, and this one """This is the main spell check setting function, and this one
should call all other setSpellCheck functions in other classes. should call all other setSpellCheck functions in other classes.
If the spell check mode (theMode) is not defined (None), then If the spell check mode (theMode) is not defined (None), then
toggle the current status saved in this class. toggle the current status saved in this class.
""" """
if theMode is None: if state is None:
theMode = not self._spellCheck state = not self._spellCheck
if not CONFIG.hasEnchant: if not CONFIG.hasEnchant:
if theMode: if state:
SHARED.info(self.tr( SHARED.info(self.tr(
"Spell checking requires the package PyEnchant. " "Spell checking requires the package PyEnchant. "
"It does not appear to be installed." "It does not appear to be installed."
)) ))
theMode = False state = False
if self.spEnchant.spellLanguage is None: if SHARED.spelling.spellLanguage is None:
theMode = False state = False
self._spellCheck = theMode self._spellCheck = state
self.mainGui.mainMenu.setSpellCheck(theMode) self.mainGui.mainMenu.setSpellCheck(state)
SHARED.project.data.setSpellCheck(theMode) SHARED.project.data.setSpellCheck(state)
self.highLight.setSpellCheck(theMode) self.highLight.setSpellCheck(state)
if not self._bigDoc or theMode is False: if not self._bigDoc or state is False:
# We don't run the spell checker automatically on big docs # We don't run the spell checker automatically on big docs
self.spellCheckDocument() self.spellCheckDocument()
logger.debug("Spell check is set to '%s'", str(theMode)) logger.debug("Spell check is set to '%s'", str(state))
return True return
def spellCheckDocument(self) -> None: def spellCheckDocument(self) -> None:
"""Rerun the highlighter to update spell checking status of the """Rerun the highlighter to update spell checking status of the
@@ -1193,14 +1191,14 @@ class GuiDocEditor(QTextEdit):
if spellCheck: if spellCheck:
logger.debug("Looking up '%s' in the dictionary", theWord) logger.debug("Looking up '%s' in the dictionary", theWord)
spellCheck &= not self.spEnchant.checkWord(theWord) spellCheck &= not SHARED.spelling.checkWord(theWord)
if spellCheck: if spellCheck:
mnuContext.addSeparator() mnuContext.addSeparator()
mnuHead = QAction(self.tr("Spelling Suggestion(s)"), mnuContext) mnuHead = QAction(self.tr("Spelling Suggestion(s)"), mnuContext)
mnuContext.addAction(mnuHead) mnuContext.addAction(mnuHead)
theSuggest = self.spEnchant.suggestWords(theWord)[:15] theSuggest = SHARED.spelling.suggestWords(theWord)[:15]
if len(theSuggest) > 0: if len(theSuggest) > 0:
for aWord in theSuggest: for aWord in theSuggest:
mnuWord = QAction("%s %s" % (nwUnicode.U_ENDASH, aWord), mnuContext) mnuWord = QAction("%s %s" % (nwUnicode.U_ENDASH, aWord), mnuContext)
@@ -1245,7 +1243,7 @@ class GuiDocEditor(QTextEdit):
""" """
theWord = theCursor.selectedText().strip().strip(self._nonWord) theWord = theCursor.selectedText().strip().strip(self._nonWord)
logger.debug("Added '%s' to project dictionary", theWord) logger.debug("Added '%s' to project dictionary", theWord)
self.spEnchant.addWord(theWord) SHARED.spelling.addWord(theWord)
self.highLight.rehighlightBlock(theCursor.block()) self.highLight.rehighlightBlock(theCursor.block())
return return
+4 -6
View File
@@ -29,7 +29,7 @@ from time import time
from PyQt5.QtCore import Qt, QRegularExpression from PyQt5.QtCore import Qt, QRegularExpression
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QBrush QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QBrush, QTextDocument
) )
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
@@ -46,13 +46,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
BLOCK_META = 2 BLOCK_META = 2
BLOCK_TITLE = 4 BLOCK_TITLE = 4
def __init__(self, theDoc, spEnchant): def __init__(self, document: QTextDocument) -> None:
super().__init__(theDoc) super().__init__(document)
logger.debug("Create: GuiDocHighlighter") logger.debug("Create: GuiDocHighlighter")
self.theDoc = theDoc
self.spEnchant = spEnchant
self.theHandle = None self.theHandle = None
self.spellCheck = False self.spellCheck = False
self.spellRx = None self.spellRx = None
@@ -387,7 +385,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
rxSpell = self.spellRx.globalMatch(theText.replace("_", " "), 0) rxSpell = self.spellRx.globalMatch(theText.replace("_", " "), 0)
while rxSpell.hasNext(): while rxSpell.hasNext():
rxMatch = rxSpell.next() rxMatch = rxSpell.next()
if not self.spEnchant.checkWord(rxMatch.captured(0)): if not SHARED.spelling.checkWord(rxMatch.captured(0)):
if rxMatch.captured(0).isupper() or rxMatch.captured(0).isnumeric(): if rxMatch.captured(0).isupper() or rxMatch.captured(0).isnumeric():
continue continue
xPos = rxMatch.capturedStart(0) xPos = rxMatch.capturedStart(0)
+16 -2
View File
@@ -32,6 +32,8 @@ from pathlib import Path
from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QMessageBox, QWidget from PyQt5.QtWidgets import QMessageBox, QWidget
from novelwriter.core.spellcheck import NWSpellEnchant
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain from novelwriter.guimain import GuiMain
from novelwriter.gui.theme import GuiTheme from novelwriter.gui.theme import GuiTheme
@@ -43,18 +45,20 @@ logger = logging.getLogger(__name__)
class SharedData(QObject): class SharedData(QObject):
__slots__ = ( __slots__ = (
"_gui", "_theme", "_project", "_lockedBy", "_alert", "_gui", "_theme", "_project", "_spelling", "_lockedBy", "_alert",
"_idleTime", "_idleRefTime", "_idleTime", "_idleRefTime",
) )
projectStatusChanged = pyqtSignal(bool) projectStatusChanged = pyqtSignal(bool)
projectStatusMessage = pyqtSignal(str) projectStatusMessage = pyqtSignal(str)
spellLanguageChanged = pyqtSignal(str, str)
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self._gui = None self._gui = None
self._theme = None self._theme = None
self._project = None self._project = None
self._spelling = None
self._lockedBy = None self._lockedBy = None
self._alert = None self._alert = None
self._idleTime = 0.0 self._idleTime = 0.0
@@ -82,6 +86,13 @@ class SharedData(QObject):
raise Exception("SharedData class not fully initialised") raise Exception("SharedData class not fully initialised")
return self._project return self._project
@property
def spelling(self) -> NWSpellEnchant:
"""Return the active NWProject instance."""
if self._spelling is None:
raise Exception("SharedData class not fully initialised")
return self._spelling
@property @property
def hasProject(self) -> bool: def hasProject(self) -> bool:
"""Return True if the project instance is populated.""" """Return True if the project instance is populated."""
@@ -130,6 +141,7 @@ class SharedData(QObject):
self._lockedBy = self.project.lockStatus self._lockedBy = self.project.lockStatus
self._resetProject() self._resetProject()
self.spelling.loadUserWordList()
self._resetIdleTimer() self._resetIdleTimer()
return status return status
@@ -220,11 +232,13 @@ class SharedData(QObject):
## ##
def _resetProject(self) -> None: def _resetProject(self) -> None:
"""Create a new project instance.""" """Create a new project and spell checking instance."""
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
if isinstance(self._project, NWProject): if isinstance(self._project, NWProject):
del self._project del self._project
del self._spelling
self._project = NWProject() self._project = NWProject()
self._spelling = NWSpellEnchant(self._project)
return return
def _resetIdleTimer(self) -> None: def _resetIdleTimer(self) -> None:
+10 -17
View File
@@ -58,17 +58,14 @@ def testCoreSpell_UserDictionary(monkeypatch, mockGUI, fncPath):
assert sorted(userDict) == ["bar", "foo"] assert sorted(userDict) == ["bar", "foo"]
# Save the file, but fail # Save the file, but fail
assert userDict._path is None
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError) mp.setattr("builtins.open", causeOSError)
userDict.save() userDict.save()
# There should be no file, but the file path should now be cached # There should be no file
assert userDict._path == dictFile
assert not dictFile.exists() assert not dictFile.exists()
# Break the path check # Break the path check
userDict._path = None
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None) mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None)
userDict.save() userDict.save()
@@ -85,23 +82,19 @@ def testCoreSpell_UserDictionary(monkeypatch, mockGUI, fncPath):
assert sorted(userDict) == [] assert sorted(userDict) == []
# Load the file, but fail # Load the file, but fail
userDict._path = None
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError) mp.setattr("builtins.open", causeOSError)
userDict.load() userDict.load()
# Path is now set, but no words # No words loaded
assert userDict._path == dictFile
assert sorted(userDict) == [] assert sorted(userDict) == []
# Break the path check # Break the path check
userDict._path = None
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None) mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None)
userDict.load() userDict.load()
# Path is now None, and no words # No words loaded
assert userDict._path is None
assert sorted(userDict) == [] assert sorted(userDict) == []
# Load the words again, properly # Load the words again, properly
@@ -122,18 +115,18 @@ def testCoreSpell_FakeEnchant(monkeypatch, mockGUI, fncPath):
mp.setitem(sys.modules, "enchant", None) mp.setitem(sys.modules, "enchant", None)
spChk = NWSpellEnchant(project) spChk = NWSpellEnchant(project)
spChk.setLanguage("en_US") spChk.setLanguage("en_US")
assert isinstance(spChk._dictObj, FakeEnchant) assert isinstance(spChk._enchant, FakeEnchant)
# Request a non-existent dictionary # Request a non-existent dictionary
spChk = NWSpellEnchant(project) spChk = NWSpellEnchant(project)
spChk.setLanguage("whatchamajig") spChk.setLanguage("whatchamajig")
assert isinstance(spChk._dictObj, FakeEnchant) assert isinstance(spChk._enchant, FakeEnchant)
# Request an empty language string # Request an empty language string
# See issue https://github.com/vkbo/novelWriter/issues/1096 # See issue https://github.com/vkbo/novelWriter/issues/1096
spChk = NWSpellEnchant(project) spChk = NWSpellEnchant(project)
spChk.setLanguage("") spChk.setLanguage("")
assert isinstance(spChk._dictObj, FakeEnchant) assert isinstance(spChk._enchant, FakeEnchant)
# FakeEnchant should handle requests # FakeEnchant should handle requests
fkChk = FakeEnchant() fkChk = FakeEnchant()
@@ -164,14 +157,14 @@ def testCoreSpell_Enchant(monkeypatch, mockGUI, fncPath):
assert spChk.spellLanguage is None assert spChk.spellLanguage is None
# Check that the FakeEnchant class is actually handling this # Check that the FakeEnchant class is actually handling this
assert isinstance(spChk._dictObj, FakeEnchant) assert isinstance(spChk._enchant, FakeEnchant)
assert spChk.checkWord("word") is True assert spChk.checkWord("word") is True
assert spChk.suggestWords("word") == [] assert spChk.suggestWords("word") == []
assert spChk.addWord("word") is True assert spChk.addWord("word") is True
# Set the dict to None, and check enchant error handling # Set the dict to None, and check enchant error handling
spChk = NWSpellEnchant(project) spChk = NWSpellEnchant(project)
spChk._dictObj = None # type: ignore spChk._enchant = None # type: ignore
assert spChk.checkWord("word") is True assert spChk.checkWord("word") is True
assert spChk.suggestWords("word") == [] assert spChk.suggestWords("word") == []
assert spChk.addWord("word") is False assert spChk.addWord("word") is False
@@ -182,7 +175,7 @@ def testCoreSpell_Enchant(monkeypatch, mockGUI, fncPath):
spChk = NWSpellEnchant(project) spChk = NWSpellEnchant(project)
spChk.setLanguage("en_US") spChk.setLanguage("en_US")
spChk.setLanguage("en_US") spChk.setLanguage("en_US")
assert isinstance(spChk._dictObj, enchant.Dict) assert isinstance(spChk._enchant, enchant.Dict)
assert spChk.spellLanguage == "en_US" assert spChk.spellLanguage == "en_US"
assert spChk.listDictionaries() != [] assert spChk.listDictionaries() != []
assert spChk.describeDict() != ("", "") assert spChk.describeDict() != ("", "")
@@ -194,6 +187,6 @@ def testCoreSpell_Enchant(monkeypatch, mockGUI, fncPath):
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr("enchant.Broker.request_dict", lambda *a: None) mp.setattr("enchant.Broker.request_dict", lambda *a: None)
spChk.setLanguage("en_US") spChk.setLanguage("en_US")
assert isinstance(spChk._dictObj, FakeEnchant) assert isinstance(spChk._enchant, FakeEnchant)
# END Test testCoreSpell_Enchant # END Test testCoreSpell_Enchant
+2 -2
View File
@@ -30,7 +30,7 @@ from PyQt5.QtWidgets import (
QDialogButtonBox, QDialog, QAction, QFileDialog, QFontDialog QDialogButtonBox, QDialog, QAction, QFileDialog, QFontDialog
) )
from novelwriter import CONFIG from novelwriter import CONFIG, SHARED
from novelwriter.dialogs.quotes import GuiQuoteSelect from novelwriter.dialogs.quotes import GuiQuoteSelect
from novelwriter.dialogs.preferences import GuiPreferences from novelwriter.dialogs.preferences import GuiPreferences
@@ -42,7 +42,7 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
"""Test the preferences dialog.""" """Test the preferences dialog."""
monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None) monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None)
monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted) monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")]) monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "none")])
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(GuiPreferences, "updateTheme", lambda *a: True) mp.setattr(GuiPreferences, "updateTheme", lambda *a: True)
+5 -7
View File
@@ -84,10 +84,9 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
@pytest.mark.gui @pytest.mark.gui
def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd): def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
"""Test the main tab of the project settings dialog. """Test the main tab of the project settings dialog."""
"""
# Mock components # Mock components
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")]) monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "none")])
# Create new project # Create new project
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
@@ -152,7 +151,7 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True)) monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
# Mock components # Mock components
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")]) monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "none")])
# Create new project # Create new project
mockRnd.reset() mockRnd.reset()
@@ -348,12 +347,11 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
@pytest.mark.gui @pytest.mark.gui
def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd): def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
"""Test the auto-replace tab of the project settings dialog. """Test the auto-replace tab of the project settings dialog."""
"""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True)) monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
# Mock components # Mock components
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")]) monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "none")])
# Create new project # Create new project
mockRnd.reset() mockRnd.reset()