1818#
1919# ==========================================================================*/
2020
21- """spell check the comments in code."""
21+ """Spell check comments in source code files.
22+
23+ This module provides functionality to extract and spell check comments from various
24+ programming languages including C++, Python, Java, Ruby, and plain text files.
25+
26+ Key Features:
27+ - Multi-language support via MIME type detection
28+ - CamelCase word splitting for better spell checking
29+ - URL detection and removal from comments
30+ - Prefix handling for common library conventions (ITK, VTK, SITK)
31+ - Custom dictionary support
32+ - BibTeX citation integration
33+ - Inline spell-check enable/disable directives
34+ - Configurable exclude patterns and file skipping
35+
36+ The spell checker can process individual files or recursively scan directories,
37+ reporting misspellings with their file locations, line numbers, and suggestions.
38+
39+ Example:
40+ Basic usage from command line:
41+ $ comment-spell-check --suffix .py --suffix .cpp src/
42+
43+ With custom dictionary:
44+ $ comment-spell-check --dict my_words.txt src/module.py
45+
46+ See Also:
47+ - parseargs module for command-line argument parsing
48+ - bibtex_loader for BibTeX integration
49+ - create_checker for dictionary management
50+ """
2251
2352import sys
2453import os
2958import logging
3059from pathlib import Path
3160from importlib .metadata import version , PackageNotFoundError
61+ from argparse import Namespace
62+ from typing import Optional
3263
3364from comment_parser import comment_parser
3465
6798CONTRACTIONS = ["'d" , "'s" , "'th" ]
6899
69100
70- def split_camel_case (word ) :
101+ def split_camel_case (word : str ) -> list [ str ] :
71102 """Split a camel case string into individual words."""
72103
73104 result = []
@@ -87,13 +118,13 @@ def split_camel_case(word):
87118 return result
88119
89120
90- def get_mime_type (filepath ) :
121+ def get_mime_type (filepath : str ) -> str :
91122 """Map ``filepath`` extension to file type."""
92123 parts = os .path .splitext (filepath )
93124 return SUFFIX2MIME .get (parts [1 ], "text/plain" )
94125
95126
96- def load_text_file (filename ) :
127+ def load_text_file (filename : str ) -> list [ comment_parser . common . Comment ] :
97128 """Parse plain text file as list of ``comment_parser.common.Comment``.
98129
99130 For a regular text file, we don't need to parse it for comments. We
@@ -111,13 +142,13 @@ def load_text_file(filename):
111142 return output
112143
113144
114- def remove_accents (input_str ) :
145+ def remove_accents (input_str : str ) -> str :
115146 """Removes accents from a string using Unicode normalization."""
116147 nfkd_form = unicodedata .normalize ("NFKD" , input_str )
117148 return "" .join ([c for c in nfkd_form if not unicodedata .combining (c )])
118149
119150
120- def filter_string (input_str : str ):
151+ def filter_string (input_str : str ) -> list [ str ] :
121152 """Filter out unwanted characters from the input string.
122153 That includes removing single quote that are not part of a
123154 contraction."""
@@ -153,7 +184,7 @@ def filter_string(input_str: str):
153184 return w2
154185
155186
156- def spell_check_words (spell_checker : SpellChecker , words : list [str ]):
187+ def spell_check_words (spell_checker : SpellChecker , words : list [str ]) -> bool :
157188 """Check each word and report False if at least one has an spelling
158189 error."""
159190 for word in words :
@@ -177,7 +208,7 @@ def find_misspellings(spell: SpellChecker, line: str) -> list[str]:
177208 return mistakes
178209
179210
180- def remove_contractions (word : str ):
211+ def remove_contractions (word : str ) -> str :
181212 """Remove contractions from the word."""
182213
183214 logger = logging .getLogger ("comment_spell_check" )
@@ -188,7 +219,7 @@ def remove_contractions(word: str):
188219 return word
189220
190221
191- def remove_prefix (word : str , prefixes : list [str ]):
222+ def remove_prefix (word : str , prefixes : list [str ]) -> str :
192223 """Remove the prefix from the word."""
193224 for prefix in prefixes :
194225 if word .startswith (prefix ):
@@ -199,7 +230,7 @@ def remove_prefix(word: str, prefixes: list[str]):
199230def spell_check_comment (
200231 spell : SpellChecker ,
201232 c : comment_parser .common .Comment ,
202- prefixes : list [str ] = None ,
233+ prefixes : Optional [ list [str ] ] = None ,
203234) -> list [str ]:
204235 """Check comment and return list of identified issues if any."""
205236
@@ -245,8 +276,8 @@ def spell_check_file(
245276 filename : str ,
246277 spell_checker : SpellChecker ,
247278 mime_type : str = "" ,
248- prefixes = None ,
249- ):
279+ prefixes : Optional [ list [ str ]] = None ,
280+ ) -> tuple [ list [ list ], int ] :
250281 """Check spelling in ``filename``."""
251282
252283 if len (mime_type ) == 0 :
@@ -301,7 +332,7 @@ def spell_check_file(
301332 return bad_words , line_count
302333
303334
304- def exclude_check (name : str , exclude_list : list [str ] = None ):
335+ def exclude_check (name : str , exclude_list : Optional [ list [str ]] = None ) -> bool :
305336 """Return True if ``name`` matches any of the regular expressions listed in
306337 ``exclude_list``."""
307338 if exclude_list is None :
@@ -313,7 +344,7 @@ def exclude_check(name: str, exclude_list: list[str] = None):
313344 return False
314345
315346
316- def skip_check (name : str , skip_list : list [str ] = None ):
347+ def skip_check (name : str , skip_list : Optional [ list [str ]] = None ) -> bool :
317348 """Return True if ``name`` matches any of the glob pattern listed in
318349 ``skip_list``."""
319350 if skip_list is None :
@@ -324,7 +355,7 @@ def skip_check(name: str, skip_list: list[str] = None):
324355 return False
325356
326357
327- def build_dictionary_list (args ) :
358+ def build_dictionary_list (args : Namespace ) -> list [ Path ] :
328359 """build a list of dictionaries to use for spell checking."""
329360 dict_list = []
330361 initial_dct = Path (__file__ ).parent / "additional_dictionary.txt"
@@ -343,7 +374,7 @@ def build_dictionary_list(args):
343374 return dict_list
344375
345376
346- def add_bibtex_words (spell : SpellChecker , bibtex_files : list [str ]):
377+ def add_bibtex_words (spell : SpellChecker , bibtex_files : list [str ]) -> None :
347378 """Add words from bibtex files to the spell checker."""
348379
349380 if list is None :
@@ -356,7 +387,7 @@ def add_bibtex_words(spell: SpellChecker, bibtex_files: list[str]):
356387 bibtex_loader .add_bibtex (spell , bibtex_file )
357388
358389
359- def output_results (args , bad_words ) :
390+ def output_results (args : Namespace , bad_words : list [ list ]) -> None :
360391 """Output the results of the spell check."""
361392
362393 print ("\n Bad words\n " if not args .miss else "" , end = "" )
@@ -385,7 +416,7 @@ def output_results(args, bad_words):
385416 print (f"\n { len (bad_words )} misspellings found" )
386417
387418
388- def setup_logger (args ) :
419+ def setup_logger (args : Namespace ) -> logging . Logger :
389420 """Sets up a logger that outputs to the console."""
390421
391422 level = logging .INFO
@@ -421,7 +452,7 @@ def setup_logger(args):
421452 return logger
422453
423454
424- def comment_spell_check (args ) :
455+ def comment_spell_check (args : Namespace ) -> None :
425456 """comment_spell_check main function."""
426457 logger = setup_logger (args )
427458
@@ -503,7 +534,7 @@ def comment_spell_check(args):
503534 sys .exit (len (bad_words ))
504535
505536
506- def main ():
537+ def main () -> None :
507538 """Parse the command line arguments and call the spell checking function."""
508539 args = parseargs .parse_args ()
509540 comment_spell_check (args )
0 commit comments