Remove the difflib spellchecker (#875)
* Delete simple spell checker * Clean up the spell checker code * Update tests * Delete the bundled dictionaries * Update documentation * Use set() for user word list * Fix tests so they pass also without dictionaries installed
This commit is contained in:
committed by
GitHub
parent
4b52f343c1
commit
f6845a9820
@@ -1,5 +1,5 @@
|
||||
[Main]
|
||||
timestamp = 2021-08-26 17:48:02
|
||||
timestamp = 2021-08-30 21:27:27
|
||||
theme = default
|
||||
syntax = default_light
|
||||
icons = typicons_light
|
||||
@@ -53,7 +53,6 @@ fmtdoublequote = “, ”
|
||||
fmtpadbefore =
|
||||
fmtpadafter =
|
||||
fmtpadthin = False
|
||||
spelltool = internal
|
||||
spellcheck = en
|
||||
showtabsnspaces = False
|
||||
showlineendings = False
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Main]
|
||||
timestamp = 2021-08-26 17:48:04
|
||||
timestamp = 2021-08-30 21:45:17
|
||||
theme = default
|
||||
syntax = default_light
|
||||
icons = typicons_light
|
||||
@@ -53,7 +53,6 @@ fmtdoublequote = “, ”
|
||||
fmtpadbefore =
|
||||
fmtpadafter =
|
||||
fmtpadthin = False
|
||||
spelltool = internal
|
||||
spellcheck = en
|
||||
showtabsnspaces = True
|
||||
showlineendings = True
|
||||
|
||||
@@ -29,7 +29,7 @@ from mock import causeOSError, MockApp
|
||||
from tools import cmpFiles, writeFile
|
||||
|
||||
from novelwriter.config import Config
|
||||
from novelwriter.constants import nwConst, nwFiles
|
||||
from novelwriter.constants import nwFiles
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
@@ -133,7 +133,6 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
|
||||
# This should create a config file as well
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("os.path.expanduser", lambda *a: "")
|
||||
tstConf.spellTool = nwConst.SP_INTERNAL
|
||||
tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
|
||||
assert tstConf.confPath == tmpDir
|
||||
assert tstConf.dataPath == tmpDir
|
||||
|
||||
@@ -26,53 +26,7 @@ import pytest
|
||||
from mock import causeOSError
|
||||
from tools import readFile, writeFile
|
||||
|
||||
from novelwriter.core.spellcheck import (
|
||||
NWSpellCheck, NWSpellEnchant, NWSpellSimple
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreSpell_Super(monkeypatch, tmpDir):
|
||||
"""Test the spell checker super class
|
||||
"""
|
||||
wList = os.path.join(tmpDir, "wordlist.txt")
|
||||
writeFile(wList, "a_word\nb_word\nc_word\n")
|
||||
|
||||
spChk = NWSpellCheck()
|
||||
|
||||
# Check that default functions return results that reflects that spell
|
||||
# checking is effectively disabled
|
||||
assert spChk.setLanguage("", "") is None
|
||||
assert spChk.checkWord("")
|
||||
assert spChk.suggestWords("") == []
|
||||
assert spChk.listDictionaries() == []
|
||||
assert spChk.describeDict() == ("", "")
|
||||
|
||||
# Add a word to the user's dictionary
|
||||
assert spChk._readProjectDictionary("stuff") is False
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
assert spChk._readProjectDictionary(wList) is False
|
||||
|
||||
assert spChk._readProjectDictionary(None) is False
|
||||
assert spChk._readProjectDictionary(wList) is True
|
||||
assert spChk.projectDict == wList
|
||||
|
||||
# Cannot write to file
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
assert spChk.addWord("d_word") is False
|
||||
assert readFile(wList) == "a_word\nb_word\nc_word\n"
|
||||
|
||||
# First time, OK
|
||||
assert spChk.addWord("d_word") is True
|
||||
assert readFile(wList) == "a_word\nb_word\nc_word\nd_word\n"
|
||||
|
||||
# But not added twice
|
||||
assert spChk.addWord("d_word") is False
|
||||
assert readFile(wList) == "a_word\nb_word\nc_word\nd_word\n"
|
||||
|
||||
# END Test testCoreSpell_Super
|
||||
from novelwriter.core.spellcheck import NWSpellEnchant
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
@@ -99,11 +53,32 @@ def testCoreSpell_Enchant(monkeypatch, tmpDir):
|
||||
spChk.setLanguage("en", wList)
|
||||
spChk.setLanguage("en", wList)
|
||||
|
||||
# Add a word to the user's dictionary
|
||||
assert spChk._readProjectDictionary("stuff") is False
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
assert spChk._readProjectDictionary(wList) is False
|
||||
|
||||
assert spChk._readProjectDictionary(None) is False
|
||||
assert spChk._readProjectDictionary(wList) is True
|
||||
assert spChk.projectDict == wList
|
||||
|
||||
# Cannot write to file
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
assert spChk.addWord("d_word") is False
|
||||
|
||||
assert readFile(wList) == "a_word\nb_word\nc_word\n"
|
||||
assert spChk.addWord("d_word") is True
|
||||
assert readFile(wList) == "a_word\nb_word\nc_word\nd_word\n"
|
||||
assert spChk.addWord("d_word") is False
|
||||
|
||||
# Check words
|
||||
assert spChk.checkWord("a_word") is True
|
||||
assert spChk.checkWord("b_word") is True
|
||||
assert spChk.checkWord("c_word") is True
|
||||
assert spChk.checkWord("d_word") is False
|
||||
assert spChk.checkWord("d_word") is True
|
||||
assert spChk.checkWord("e_word") is False
|
||||
|
||||
spChk.addWord("d_word")
|
||||
assert spChk.checkWord("d_word") is True
|
||||
@@ -120,68 +95,3 @@ def testCoreSpell_Enchant(monkeypatch, tmpDir):
|
||||
assert aName != ""
|
||||
|
||||
# END Test testCoreSpell_Enchant
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreSpell_Simple(monkeypatch, tmpDir):
|
||||
"""Test the fallback simple spell checker
|
||||
"""
|
||||
wList = os.path.join(tmpDir, "wordlist.txt")
|
||||
wDict = os.path.join(tmpDir, "en.dict")
|
||||
writeFile(wList, "a_word\nb_word\nc_word\n")
|
||||
writeFile(wDict, "# Comment\ne_word\nf_word\ng_word\n")
|
||||
|
||||
spChk = NWSpellSimple()
|
||||
spChk.mainConf.dictPath = tmpDir
|
||||
|
||||
# Load dictionary, but fail
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
spChk.setLanguage("en", wList)
|
||||
assert spChk.spellLanguage is None
|
||||
assert spChk.theWords == set(spChk.projDict)
|
||||
|
||||
# Load dictionary properly
|
||||
spChk.setLanguage("en", wList)
|
||||
assert spChk.projDict == ["a_word", "b_word", "c_word"]
|
||||
assert spChk.theWords == {"e_word", "f_word", "g_word", "a_word", "b_word", "c_word"}
|
||||
|
||||
# Check words
|
||||
assert spChk.checkWord("a_word")
|
||||
assert spChk.checkWord("b_word")
|
||||
assert spChk.checkWord("c_word")
|
||||
assert not spChk.checkWord("d_word")
|
||||
assert spChk.checkWord("e_word")
|
||||
assert spChk.checkWord("f_word")
|
||||
assert spChk.checkWord("g_word")
|
||||
|
||||
# Add word
|
||||
spChk.addWord("d_word")
|
||||
assert spChk.checkWord("d_word")
|
||||
|
||||
# Check spelling
|
||||
assert spChk.suggestWords(" \t") == []
|
||||
|
||||
wSuggest = spChk.suggestWords("d_wrod")
|
||||
assert len(wSuggest) > 0
|
||||
assert "d_word" in wSuggest
|
||||
|
||||
# Break the matching
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("difflib.get_close_matches", lambda *args, **kwargs: [""])
|
||||
assert spChk.suggestWords("word") == []
|
||||
|
||||
# Capitalisation
|
||||
wSuggest = spChk.suggestWords("D_wrod")
|
||||
assert len(wSuggest) > 0
|
||||
assert "D_word" in wSuggest
|
||||
|
||||
# List dictionaries
|
||||
assert spChk.listDictionaries() == [("en", "difflib")]
|
||||
|
||||
# Description
|
||||
aTag, aName = spChk.describeDict()
|
||||
assert aTag == "en"
|
||||
assert aName == ""
|
||||
|
||||
# END Test testCoreSpell_Simple
|
||||
|
||||
@@ -33,7 +33,6 @@ from PyQt5.QtWidgets import (
|
||||
|
||||
from novelwriter.config import Config
|
||||
from novelwriter.dialogs import GuiPreferences, GuiQuoteSelect
|
||||
from novelwriter.constants import nwConst
|
||||
|
||||
keyDelay = 2
|
||||
typeDelay = 1
|
||||
@@ -67,10 +66,11 @@ def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
|
||||
|
||||
theConf = nwGUI.mainConf
|
||||
assert theConf.confPath == fncDir
|
||||
theConf.spellTool = nwConst.SP_INTERNAL
|
||||
|
||||
monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None)
|
||||
monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted)
|
||||
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")])
|
||||
|
||||
nwGUI.mainMenu.aPreferences.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000)
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDi
|
||||
# Get the dialog object
|
||||
monkeypatch.setattr(GuiProjectSettings, "exec_", lambda *a: None)
|
||||
monkeypatch.setattr(GuiProjectSettings, "result", lambda *a: QDialog.Accepted)
|
||||
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")])
|
||||
|
||||
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None, timeout=1000)
|
||||
|
||||
|
||||
@@ -229,7 +229,6 @@ def testGuiEditor_MetaData(qtbot, monkeypatch, nwGUI, nwMinimal):
|
||||
assert nwGUI.docEditor.docHandle() == sHandle
|
||||
assert nwGUI.docEditor.lastActive() > 0.0
|
||||
assert nwGUI.docEditor.isEmpty() is False
|
||||
assert nwGUI.docEditor.currentDictionary() is not None
|
||||
|
||||
# Cursor Position
|
||||
assert nwGUI.docEditor.setCursorPosition(None) is False
|
||||
|
||||
Reference in New Issue
Block a user