From de5723e931e217f677af9c88afa8872871ca83c5 Mon Sep 17 00:00:00 2001 From: Giacomo Tagliabue Date: Tue, 3 Mar 2020 10:38:29 -0500 Subject: [PATCH] add --force-exclude option --- black.py | 53 +++++++++++++++++++------- docs/reference/reference_functions.rst | 2 +- tests/test_black.py | 24 ++++++------ 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/black.py b/black.py index b7cacf77678..1e55e7d2ca2 100644 --- a/black.py +++ b/black.py @@ -360,6 +360,14 @@ def target_version_option_callback( ), show_default=True, ) +@click.option( + "--force-exclude", + type=str, + help=( + "Like --exclude, but in these case files and directories will be excluded " + "even when they are passed explicitly as arguments" + ), +) @click.option( "-q", "--quiet", @@ -412,6 +420,7 @@ def main( verbose: bool, include: str, exclude: str, + force_exclude: Optional[str], src: Tuple[str, ...], config: Optional[str], ) -> None: @@ -453,6 +462,13 @@ def main( except re.error: err(f"Invalid regular expression for exclude given: {exclude!r}") ctx.exit(2) + try: + force_exclude_regex = ( + re_compile_maybe_verbose(force_exclude) if force_exclude else None + ) + except re.error: + err(f"Invalid regular expression for exclude given: {exclude!r}") + ctx.exit(2) report = Report(check=check, diff=diff, quiet=quiet, verbose=verbose) root = find_project_root(src) sources: Set[Path] = set() @@ -461,15 +477,26 @@ def main( p = Path(s) if p.is_dir(): sources.update( - gen_python_files_in_dir( - p, root, include_regex, exclude_regex, report, get_gitignore(root) + gen_python_files( + p.iterdir(), + root, + include_regex, + exclude_regex, + report, + get_gitignore(root), ) ) - elif p.is_file() or s == "-": - # if a file was explicitly given, we don't care about its extension + elif s == "-": sources.add(p) + elif p.is_file(): + sources.update( + gen_python_files( + [p], root, None, force_exclude_regex, report, get_gitignore(root) + ) + ) else: err(f"invalid path: {s}") + if len(sources) == 0: if verbose or not quiet: out("No Python files are present to be formatted. Nothing to do 😴") @@ -3527,11 +3554,11 @@ def get_gitignore(root: Path) -> PathSpec: return PathSpec.from_lines("gitwildmatch", lines) -def gen_python_files_in_dir( - path: Path, +def gen_python_files( + paths: Iterable[Path], root: Path, - include: Pattern[str], - exclude: Pattern[str], + include: Optional[Pattern[str]], + exclude: Optional[Pattern[str]], report: "Report", gitignore: PathSpec, ) -> Iterator[Path]: @@ -3543,7 +3570,7 @@ def gen_python_files_in_dir( `report` is where output about exclusions goes. """ assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}" - for child in path.iterdir(): + for child in paths: # First ignore files matching .gitignore if gitignore.match_file(child.as_posix()): report.path_ignored(child, f"matches the .gitignore file content") @@ -3568,18 +3595,18 @@ def gen_python_files_in_dir( if child.is_dir(): normalized_path += "/" - exclude_match = exclude.search(normalized_path) + exclude_match = exclude.search(normalized_path) if exclude else None if exclude_match and exclude_match.group(0): report.path_ignored(child, f"matches the --exclude regular expression") continue if child.is_dir(): - yield from gen_python_files_in_dir( - child, root, include, exclude, report, gitignore + yield from gen_python_files( + child.iterdir(), root, include, exclude, report, gitignore, ) elif child.is_file(): - include_match = include.search(normalized_path) + include_match = include.search(normalized_path) if include else True if include_match: yield child diff --git a/docs/reference/reference_functions.rst b/docs/reference/reference_functions.rst index 459e4980ae7..d9607d0ad56 100644 --- a/docs/reference/reference_functions.rst +++ b/docs/reference/reference_functions.rst @@ -61,7 +61,7 @@ File operations .. autofunction:: black.find_project_root -.. autofunction:: black.gen_python_files_in_dir +.. autofunction:: black.gen_python_files .. autofunction:: black.read_pyproject_toml diff --git a/tests/test_black.py b/tests/test_black.py index acbaade0a50..52164809c35 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1442,8 +1442,8 @@ def test_include_exclude(self) -> None: ] this_abs = THIS_DIR.resolve() sources.extend( - black.gen_python_files_in_dir( - path, this_abs, include, exclude, report, gitignore + black.gen_python_files( + path.iterdir(), this_abs, include, exclude, report, gitignore ) ) self.assertEqual(sorted(expected), sorted(sources)) @@ -1463,8 +1463,8 @@ def test_gitignore_exclude(self) -> None: ] this_abs = THIS_DIR.resolve() sources.extend( - black.gen_python_files_in_dir( - path, this_abs, include, exclude, report, gitignore + black.gen_python_files( + path.iterdir(), this_abs, include, exclude, report, gitignore ) ) self.assertEqual(sorted(expected), sorted(sources)) @@ -1488,8 +1488,8 @@ def test_empty_include(self) -> None: ] this_abs = THIS_DIR.resolve() sources.extend( - black.gen_python_files_in_dir( - path, + black.gen_python_files( + path.iterdir(), this_abs, empty, re.compile(black.DEFAULT_EXCLUDES), @@ -1515,8 +1515,8 @@ def test_empty_exclude(self) -> None: ] this_abs = THIS_DIR.resolve() sources.extend( - black.gen_python_files_in_dir( - path, + black.gen_python_files( + path.iterdir(), this_abs, re.compile(black.DEFAULT_INCLUDES), empty, @@ -1575,8 +1575,8 @@ def test_symlink_out_of_root_directory(self) -> None: child.is_symlink.return_value = True try: list( - black.gen_python_files_in_dir( - path, root, include, exclude, report, gitignore + black.gen_python_files( + path.iterdir(), root, include, exclude, report, gitignore ) ) except ValueError as ve: @@ -1589,8 +1589,8 @@ def test_symlink_out_of_root_directory(self) -> None: child.is_symlink.return_value = False with self.assertRaises(ValueError): list( - black.gen_python_files_in_dir( - path, root, include, exclude, report, gitignore + black.gen_python_files( + path.iterdir(), root, include, exclude, report, gitignore ) ) path.iterdir.assert_called()