Coverage for src/mkdocs_spellcheck/plugin.py: 0.00%

51 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-05-05 19:29 +0200

1"""MkDocs SpellCheck package. 

2 

3A spell checker plugin for MkDocs. 

4""" 

5 

6from __future__ import annotations 

7 

8from fnmatch import fnmatch 

9from pathlib import Path 

10from typing import TYPE_CHECKING, Any 

11 

12from mkdocs.config.config_options import Type as MkType 

13from mkdocs.plugins import BasePlugin 

14 

15from mkdocs_spellcheck.loggers import get_plugin_logger 

16from mkdocs_spellcheck.words import get_words 

17 

18if TYPE_CHECKING: 

19 from mkdocs.config.defaults import MkDocsConfig 

20 from mkdocs.structure.pages import Page 

21 

22 from mkdocs_spellcheck.backends import Backend 

23 

24logger = get_plugin_logger(__name__) 

25 

26 

27def load_backend(name: str) -> type[Backend]: 

28 """Load the specified backend. 

29 

30 This function imports the specified backend and returns its class. 

31 It is important not to import the backends at the top level, as 

32 they may not be installed. 

33 

34 Arguments: 

35 name: The name of the backend to load. 

36 

37 Returns: 

38 The backend class. 

39 """ 

40 if name == "symspellpy": 

41 from mkdocs_spellcheck.backends import symspellpy 

42 

43 return symspellpy.SymspellpyBackend 

44 

45 if name == "codespell": 

46 from mkdocs_spellcheck.backends import codespell 

47 

48 return codespell.CodespellBackend 

49 

50 raise ValueError(f"Unknown backend: {name}") 

51 

52 

53class SpellCheckPlugin(BasePlugin): 

54 """A `mkdocs` plugin. 

55 

56 This plugin defines the following event hooks: 

57 

58 - `on_config` 

59 - `on_page_content` 

60 

61 Check the [Developing Plugins](https://www.mkdocs.org/user-guide/plugins/#developing-plugins) page of `mkdocs` 

62 for more information about its plugin system. 

63 """ 

64 

65 config_scheme: tuple[tuple[str, MkType], ...] = ( 

66 ("strict_only", MkType(bool, default=False)), 

67 ("backends", MkType(list, default=["symspellpy"])), 

68 ("known_words", MkType((str, list), default=[])), 

69 ("skip_files", MkType(list, default=[])), 

70 ("min_length", MkType(int, default=2)), 

71 ("max_capital", MkType(int, default=1)), 

72 ("ignore_code", MkType(bool, default=True)), 

73 ("allow_unicode", MkType(bool, default=False)), 

74 ) 

75 

76 def __init__(self) -> None: # noqa: D107 

77 self.known_words: set[str] = set() 

78 super().__init__() 

79 

80 def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: 

81 """Load words to ignore. 

82 

83 Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config). 

84 

85 Arguments: 

86 config: The MkDocs config object. 

87 

88 Returns: 

89 The modified config. 

90 """ 

91 self.strict_only = self.config["strict_only"] 

92 self.backends_config = self.config["backends"] 

93 self.skip_files = self.config["skip_files"] 

94 self.min_length = self.config["min_length"] 

95 self.max_capital = self.config["max_capital"] 

96 self.ignore_code = self.config["ignore_code"] 

97 self.allow_unicode = self.config["allow_unicode"] 

98 self.run = config["strict"] or not self.strict_only 

99 

100 if not self.run: 

101 return config 

102 

103 known_words = self.config["known_words"] 

104 if isinstance(known_words, str): 

105 self.known_words |= set(Path(config["docs_dir"], known_words).read_text().splitlines()) 

106 else: 

107 self.known_words |= set(known_words) 

108 

109 self.backends = {} 

110 for backend_conf in self.backends_config: 

111 if isinstance(backend_conf, str): 

112 backend_name = backend_conf 

113 backend_config = {} 

114 else: 

115 backend_name, backend_config = next(iter(backend_conf.items())) 

116 self.backends[backend_name] = load_backend(backend_name)( 

117 known_words=self.known_words, 

118 config=backend_config, 

119 ) 

120 

121 return config 

122 

123 def on_page_content(self, html: str, page: Page, **kwargs: Any) -> None: # noqa: ARG002 

124 """Spell check everything. 

125 

126 Hook for the [`on_page_content` event](https://www.mkdocs.org/user-guide/plugins/#on_page_content). 

127 

128 Arguments: 

129 html: The HTML text. 

130 page: The page instance. 

131 **kwargs: Additional arguments passed by MkDocs. 

132 """ 

133 if self.run and not any(fnmatch(page.file.src_path, pattern) for pattern in self.skip_files): 

134 words = get_words( 

135 html, 

136 known_words=self.known_words, 

137 min_length=self.min_length, 

138 max_capital=self.max_capital, 

139 ignore_code=self.ignore_code, 

140 allow_unicode=self.allow_unicode, 

141 ) 

142 for word in words: 

143 for backend in self.backends.values(): 

144 backend.check(page, word)