diff --git a/codespell_lib/_codespell.py b/codespell_lib/_codespell.py index 2db9692242..1904f7c852 100644 --- a/codespell_lib/_codespell.py +++ b/codespell_lib/_codespell.py @@ -160,18 +160,10 @@ class QuietLevels: class GlobMatch: - def __init__(self, pattern: Optional[str]) -> None: - self.pattern_list: Optional[List[str]] - if pattern: - # Pattern might be a list of comma-delimited strings - self.pattern_list = ",".join(pattern).split(",") - else: - self.pattern_list = None + def __init__(self, pattern: List[str]) -> None: + self.pattern_list: List[str] = pattern def match(self, filename: str) -> bool: - if self.pattern_list is None: - return False - return any(fnmatch.fnmatch(filename, p) for p in self.pattern_list) @@ -1109,6 +1101,20 @@ def parse_file( return bad_count +def flatten_clean_comma_separated_arguments( + arguments: Iterable[str], +) -> List[str]: + """ + >>> flatten_clean_comma_separated_arguments(["a, b ,\n c, d,", "e"]) + ['a', 'b', 'c', 'd', 'e'] + >>> flatten_clean_comma_separated_arguments([]) + [] + """ + return [ + item.strip() for argument in arguments for item in argument.split(",") if item + ] + + def _script_main() -> int: """Wrap to main() for setuptools.""" return main(*sys.argv[1:]) @@ -1256,7 +1262,9 @@ def main(*args: str) -> int: file_opener = FileOpener(options.hard_encoding_detection, options.quiet_level) - glob_match = GlobMatch(options.skip) + glob_match = GlobMatch( + flatten_clean_comma_separated_arguments(options.skip) if options.skip else [] + ) try: glob_match.match("/random/path") # does not need a real path except re.error: diff --git a/codespell_lib/tests/test_basic.py b/codespell_lib/tests/test_basic.py index 645bb49583..89a9b549d2 100644 --- a/codespell_lib/tests/test_basic.py +++ b/codespell_lib/tests/test_basic.py @@ -573,6 +573,8 @@ def test_ignore( (subdir / "bad.txt").write_text("abandonned") assert cs.main(tmp_path) == 2 assert cs.main("--skip=bad*", tmp_path) == 0 + assert cs.main("--skip=whatever.txt,bad*,whatelse.txt", tmp_path) == 0 + assert cs.main("--skip=whatever.txt,\n bad* ,", tmp_path) == 0 assert cs.main("--skip=*ignoredir*", tmp_path) == 1 assert cs.main("--skip=ignoredir", tmp_path) == 1 assert cs.main("--skip=*ignoredir/bad*", tmp_path) == 1 @@ -1213,7 +1215,7 @@ def test_ill_formed_ini_config_file( assert "ill-formed config file" in stderr -@pytest.mark.parametrize("kind", ["cfg", "toml", "toml_list"]) +@pytest.mark.parametrize("kind", ["cfg", "cfg_multiline", "toml", "toml_list"]) def test_config_toml( tmp_path: Path, capsys: pytest.CaptureFixture[str], @@ -1235,44 +1237,47 @@ def test_config_toml( assert "bad.txt" in stdout assert "abandonned.txt" in stdout - if kind == "cfg": + if kind.startswith("cfg"): conffile = tmp_path / "setup.cfg" args = ("--config", conffile) - conffile.write_text( - """\ + if kind == "cfg": + text = """\ [codespell] skip = bad.txt, whatever.txt count = """ - ) - elif kind == "toml": - assert kind == "toml" + else: + assert kind == "cfg_multiline" + text = """\ +[codespell] +skip = whatever.txt, + bad.txt , + , + +count = +""" + conffile.write_text(text) + else: if sys.version_info < (3, 11): pytest.importorskip("tomli") tomlfile = tmp_path / "pyproject.toml" args = ("--toml", tomlfile) - tomlfile.write_text( - """\ + if kind == "toml": + text = """\ [tool.codespell] skip = 'bad.txt,whatever.txt' check-filenames = false count = true """ - ) - else: - assert kind == "toml_list" - if sys.version_info < (3, 11): - pytest.importorskip("tomli") - tomlfile = tmp_path / "pyproject.toml" - args = ("--toml", tomlfile) - tomlfile.write_text( - """\ + else: + assert kind == "toml_list" + text = """\ [tool.codespell] skip = ['bad.txt', 'whatever.txt'] check-filenames = false count = true """ - ) + tomlfile.write_text(text) # Should pass when skipping bad.txt or abandonned.txt result = cs.main(d, *args, std=True)