Skip to content

Commit 8325e23

Browse files
Options accepting a file should accept lists of files
The rationale is that these options readily accept multiple files from the command line, because they can be specified multiple times. However, duplicate option keys are invalid in an INI config file. Our alternative here is to accept multiple comma-separated values for each option key, in addition to mulitple occurrences of the same option key.
1 parent 76c7b07 commit 8325e23

File tree

2 files changed

+45
-30
lines changed

2 files changed

+45
-30
lines changed

codespell_lib/_codespell.py

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,9 @@ def parse_options(
395395
"-D",
396396
"--dictionary",
397397
action="append",
398-
help="custom dictionary file that contains spelling "
399-
"corrections. If this flag is not specified or "
400-
'equals "-" then the default dictionary is used. '
401-
"This option can be specified multiple times.",
398+
help="comma-separated list of custom dictionary files that "
399+
"contain spelling corrections. If this flag is not specified "
400+
'or equals "-" then the default dictionary is used.',
402401
)
403402
builtin_opts = "\n- ".join(
404403
[""] + [f"{d[0]!r} {d[1]}" for d in _builtin_dictionaries]
@@ -428,26 +427,26 @@ def parse_options(
428427
"-I",
429428
"--ignore-words",
430429
action="append",
431-
metavar="FILE",
432-
help="file that contains words that will be ignored "
433-
"by codespell. File must contain 1 word per line."
434-
" Words are case sensitive based on how they are "
435-
"written in the dictionary file",
430+
metavar="FILES",
431+
help="comma-separated list of files that contain "
432+
"words to be ignored by codespell. Files must contain "
433+
"1 word per line. Words are case sensitive based on "
434+
"how they are written in the dictionary file.",
436435
)
437436
parser.add_argument(
438437
"-L",
439438
"--ignore-words-list",
440439
action="append",
441440
metavar="WORDS",
442-
help="comma separated list of words to be ignored "
441+
help="comma-separated list of words to be ignored "
443442
"by codespell. Words are case sensitive based on "
444-
"how they are written in the dictionary file",
443+
"how they are written in the dictionary file.",
445444
)
446445
parser.add_argument(
447446
"--uri-ignore-words-list",
448447
action="append",
449448
metavar="WORDS",
450-
help="comma separated list of words to be ignored "
449+
help="comma-separated list of words to be ignored "
451450
"by codespell in URIs and emails only. Words are "
452451
"case sensitive based on how they are written in "
453452
'the dictionary file. If set to "*", all '
@@ -499,11 +498,13 @@ def parse_options(
499498
parser.add_argument(
500499
"-x",
501500
"--exclude-file",
501+
action="append",
502502
type=str,
503-
metavar="FILE",
504-
help="ignore whole lines that match those "
505-
"in the file FILE. The lines in FILE "
506-
"should match the to-be-excluded lines exactly",
503+
metavar="FILES",
504+
help="ignore whole lines that match those in "
505+
"the comma-separated list of files EXCLUDE. "
506+
"The lines in these files should match the "
507+
"to-be-excluded lines exactly",
507508
)
508509

509510
parser.add_argument(
@@ -1097,6 +1098,18 @@ def parse_file(
10971098
return bad_count
10981099

10991100

1101+
def flatten_comma_separated_arguments(
1102+
arguments: List[str],
1103+
) -> List[str]:
1104+
"""
1105+
>>> flatten_comma_separated_arguments(["a,b,c", "d", "e"])
1106+
['a', 'b', 'c', 'd', 'e']
1107+
>>> flatten_comma_separated_arguments([])
1108+
[]
1109+
"""
1110+
return [item for argument in arguments for item in argument.split(",")]
1111+
1112+
11001113
def _script_main() -> int:
11011114
"""Wrap to main() for setuptools."""
11021115
return main(*sys.argv[1:])
@@ -1148,20 +1161,20 @@ def main(*args: str) -> int:
11481161
else:
11491162
ignore_word_regex = None
11501163

1151-
ignore_words_files = options.ignore_words or []
11521164
ignore_words, ignore_words_cased = parse_ignore_words_option(
11531165
options.ignore_words_list
11541166
)
1155-
1156-
for ignore_words_file in ignore_words_files:
1157-
if not os.path.isfile(ignore_words_file):
1158-
print(
1159-
f"ERROR: cannot find ignore-words file: {ignore_words_file}",
1160-
file=sys.stderr,
1161-
)
1162-
parser.print_help()
1163-
return EX_USAGE
1164-
build_ignore_words(ignore_words_file, ignore_words, ignore_words_cased)
1167+
if options.ignore_words:
1168+
ignore_words_files = flatten_comma_separated_arguments(options.ignore_words)
1169+
for ignore_words_file in ignore_words_files:
1170+
if not os.path.isfile(ignore_words_file):
1171+
print(
1172+
f"ERROR: cannot find ignore-words file: {ignore_words_file}",
1173+
file=sys.stderr,
1174+
)
1175+
parser.print_help()
1176+
return EX_USAGE
1177+
build_ignore_words(ignore_words_file, ignore_words, ignore_words_cased)
11651178

11661179
uri_regex = options.uri_regex or uri_regex_def
11671180
try:
@@ -1178,7 +1191,7 @@ def main(*args: str) -> int:
11781191
itertools.chain(*parse_ignore_words_option(options.uri_ignore_words_list))
11791192
)
11801193

1181-
dictionaries = options.dictionary or ["-"]
1194+
dictionaries = flatten_comma_separated_arguments(options.dictionary or ["-"])
11821195

11831196
use_dictionaries = []
11841197
for dictionary in dictionaries:
@@ -1243,7 +1256,9 @@ def main(*args: str) -> int:
12431256

12441257
exclude_lines: Set[str] = set()
12451258
if options.exclude_file:
1246-
build_exclude_hashes(options.exclude_file, exclude_lines)
1259+
exclude_files = flatten_comma_separated_arguments(options.exclude_file)
1260+
for exclude_file in exclude_files:
1261+
build_exclude_hashes(exclude_file, exclude_lines)
12471262

12481263
file_opener = FileOpener(options.hard_encoding_detection, options.quiet_level)
12491264

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,6 @@ max-complexity = 45
161161
[tool.ruff.lint.pylint]
162162
allow-magic-value-types = ["bytes", "int", "str",]
163163
max-args = 13
164-
max-branches = 49
164+
max-branches = 51
165165
max-returns = 11
166166
max-statements = 113

0 commit comments

Comments
 (0)