From 6fc33683f17ecbb689add9c722ba96be0428d78c Mon Sep 17 00:00:00 2001 From: Jan Jachnik Date: Wed, 27 Apr 2022 14:02:06 +0100 Subject: [PATCH 1/4] Added option to manually specifiy project root --- src/black/__init__.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 3a1ce24f059..5419328e305 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -354,6 +354,17 @@ def validate_regex( "editors that rely on using stdin." ), ) +@click.option( + "--project-root", + type=click.Path( + exists=True, file_okay=False, dir_okay=True, readable=True, allow_dash=True + ), + help=( + "Manually specifiy the project root. This will prevent black from searching " + "for the project root itself. Useful to prevent black from picking up git " + "submodules as the project root which can affect the exclude behaviour." + ), +) @click.option( "-W", "--workers", @@ -435,6 +446,7 @@ def main( # noqa: C901 extend_exclude: Optional[Pattern[str]], force_exclude: Optional[Pattern[str]], stdin_filename: Optional[str], + project_root: Optional[str], workers: int, src: Tuple[str, ...], config: Optional[str], @@ -452,7 +464,11 @@ def main( # noqa: C901 out(main.get_usage(ctx) + "\n\nOne of 'SRC' or 'code' is required.") ctx.exit(1) - root, method = find_project_root(src) if code is None else (None, None) + if project_root: + project_root_abs = Path(project_root).resolve() + root, method = (project_root_abs, "manually-specified project root") if code is None else (None, None) + else: + root, method = find_project_root(src) if code is None else (None, None) ctx.obj["root"] = root if verbose: From 73021886b547a3950a5b57ec97bec502d9c95217 Mon Sep 17 00:00:00 2001 From: Jan Jachnik Date: Thu, 23 Jun 2022 11:06:54 +0100 Subject: [PATCH 2/4] Run black formatter --- src/black/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 5f6971fe565..5ad7cc99e9c 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -469,7 +469,11 @@ def main( # noqa: C901 if project_root: project_root_abs = Path(project_root).resolve() - root, method = (project_root_abs, "manually-specified project root") if code is None else (None, None) + root, method = ( + (project_root_abs, "manually-specified project root") + if code is None + else (None, None) + ) else: root, method = find_project_root(src) if code is None else (None, None) ctx.obj["root"] = root From 77216032f346dc984b96093df1e0d39f932521cc Mon Sep 17 00:00:00 2001 From: Jan Jachnik Date: Thu, 23 Jun 2022 11:11:00 +0100 Subject: [PATCH 3/4] Added git submodule exclude tests --- tests/data/git_submodule_exclude_tests/a.py | 0 .../excluded_submodule/a.py | 0 tests/test_black.py | 14 ++++++++++++++ 3 files changed, 14 insertions(+) create mode 100644 tests/data/git_submodule_exclude_tests/a.py create mode 100644 tests/data/git_submodule_exclude_tests/excluded_submodule/a.py diff --git a/tests/data/git_submodule_exclude_tests/a.py b/tests/data/git_submodule_exclude_tests/a.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/git_submodule_exclude_tests/excluded_submodule/a.py b/tests/data/git_submodule_exclude_tests/excluded_submodule/a.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/test_black.py b/tests/test_black.py index 02a707e8996..5b626e5b708 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2017,6 +2017,20 @@ def test_extend_exclude(self) -> None: src, expected, exclude=r"\.pyi$", extend_exclude=r"\.definitely_exclude" ) + def test_git_submodule_exclude_full_path(self) -> None: + path = DATA_DIR / "git_submodule_exclude_tests" / "excluded_submodule" / "a.py" + src = [path] + expected: List[str] = [] + assert_collected_sources(src, expected, force_exclude=r"excluded_submodule") + + def test_git_submodule_exclude_base_path(self) -> None: + path = DATA_DIR / "git_submodule_exclude_tests" + src = [path] + expected = [ + Path(path / "a.py"), + ] + assert_collected_sources(src, expected, force_exclude=r"excluded_submodule") + @pytest.mark.incompatible_with_mypyc def test_symlink_out_of_root_directory(self) -> None: path = MagicMock() From a5488c30fa5e2ca02ffbf4330f52260d43f0bb49 Mon Sep 17 00:00:00 2001 From: Jan Jachnik Date: Thu, 23 Jun 2022 11:12:26 +0100 Subject: [PATCH 4/4] Call black.find_project_root() within include/exclude tests This makes the behaviour of the tests better mimic real-world usage. Now the git submodule full path test fails, reproducing the bug seen in real-world usage. --- tests/test_black.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_black.py b/tests/test_black.py index 5b626e5b708..3ebd735ed2d 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1853,8 +1853,11 @@ def assert_collected_sources( None if extend_exclude is None else compile_pattern(extend_exclude) ) gs_force_exclude = None if force_exclude is None else compile_pattern(force_exclude) + if not ctx: + ctx = FakeContext() + ctx.obj["root"], _ = black.find_project_root(gs_src) collected = black.get_sources( - ctx=ctx or FakeContext(), + ctx=ctx, src=gs_src, quiet=False, verbose=False,