From ffd3d06ad1d8acb3bf54b3fff6090d17e41616dd Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 19:38:13 +0200 Subject: [PATCH 1/8] Add testcase for `include` with absolute path --- tests/test_black.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_black.py b/tests/test_black.py index 537ca80d432..ee7d2e89fea 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2388,6 +2388,16 @@ def test_empty_include(self) -> None: # Setting exclude explicitly to an empty string to block .gitignore usage. assert_collected_sources(src, expected, include="", exclude="") + def test_include_absolute_path(self) -> None: + path = DATA_DIR / "include_exclude_tests" + src = [path] + expected = [ + Path(path / "b/dont_exclude/a.pie"), + ] + assert_collected_sources( + src, expected, root=path, include=r"^/b/dont_exclude/a\.pie$", exclude="" + ) + def test_extend_exclude(self) -> None: path = DATA_DIR / "include_exclude_tests" src = [path] From 9dfe18662c4da47f90694a5eee466a59008901c4 Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 19:35:27 +0200 Subject: [PATCH 2/8] Fix path normalization for `include` with absolute path --- src/black/files.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/black/files.py b/src/black/files.py index 362898dc0fd..a4233876bdb 100644 --- a/src/black/files.py +++ b/src/black/files.py @@ -361,6 +361,10 @@ def gen_python_files( if normalized_path is None: continue + normalized_path = "/" + normalized_path + if child.is_dir(): + normalized_path += "/" + if child.is_dir(): # If gitignore is None, gitignore usage is disabled, while a Falsey # gitignore is when the directory doesn't have a .gitignore file. From d3ea993a27f51847c01c66a101b94975d66bf9d6 Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 19:53:53 +0200 Subject: [PATCH 3/8] Add testcase for `exclude` with absolute path --- tests/test_black.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_black.py b/tests/test_black.py index ee7d2e89fea..355fa5f2faf 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2398,6 +2398,17 @@ def test_include_absolute_path(self) -> None: src, expected, root=path, include=r"^/b/dont_exclude/a\.pie$", exclude="" ) + def test_exclude_absolute_path(self) -> None: + path = DATA_DIR / "include_exclude_tests" + src = [path] + expected = [ + Path(path / "b/dont_exclude/a.py"), + Path(path / "b/.definitely_exclude/a.py"), + ] + assert_collected_sources( + src, expected, root=path, include=r"\.py$", exclude=r"^/b/exclude/a\.py$" + ) + def test_extend_exclude(self) -> None: path = DATA_DIR / "include_exclude_tests" src = [path] From fc658f6aa3b8d295a839679d782651a4a8417b0e Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 20:21:11 +0200 Subject: [PATCH 4/8] Add change to CHANGES --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index c4ae056b1b9..03ba07821e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ +- Fix a bug in the matching of absolute path names in `--include` (#3975) + ### Packaging From 6e265d92014e2309be74d0d90c90bbe714636cd4 Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 20:28:05 +0200 Subject: [PATCH 5/8] Fix pull request number in CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 03ba07821e8..7fc56365b02 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,7 +18,7 @@ -- Fix a bug in the matching of absolute path names in `--include` (#3975) +- Fix a bug in the matching of absolute path names in `--include` (#3976) ### Packaging From c1fc2e3df60af80d6f2a89a1f7de22ccd05fbda5 Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Tue, 24 Oct 2023 20:33:59 +0200 Subject: [PATCH 6/8] Fix formatting --- tests/test_black.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_black.py b/tests/test_black.py index 355fa5f2faf..0e6b0e70bc7 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2395,7 +2395,7 @@ def test_include_absolute_path(self) -> None: Path(path / "b/dont_exclude/a.pie"), ] assert_collected_sources( - src, expected, root=path, include=r"^/b/dont_exclude/a\.pie$", exclude="" + src, expected, root=path, include=r"^/b/dont_exclude/a\.pie$", exclude="" ) def test_exclude_absolute_path(self) -> None: @@ -2406,7 +2406,7 @@ def test_exclude_absolute_path(self) -> None: Path(path / "b/.definitely_exclude/a.py"), ] assert_collected_sources( - src, expected, root=path, include=r"\.py$", exclude=r"^/b/exclude/a\.py$" + src, expected, root=path, include=r"\.py$", exclude=r"^/b/exclude/a\.py$" ) def test_extend_exclude(self) -> None: From 11e6f55392a77fbba17393c399b24028dbdbb220 Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Fri, 27 Oct 2023 00:45:00 +0200 Subject: [PATCH 7/8] Add more cases to symlink inclusion test --- tests/test_black.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/tests/test_black.py b/tests/test_black.py index 0e6b0e70bc7..56c20243020 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2422,7 +2422,6 @@ def test_extend_exclude(self) -> None: @pytest.mark.incompatible_with_mypyc def test_symlinks(self) -> None: - path = MagicMock() root = THIS_DIR.resolve() include = re.compile(black.DEFAULT_INCLUDES) exclude = re.compile(black.DEFAULT_EXCLUDES) @@ -2430,19 +2429,44 @@ def test_symlinks(self) -> None: gitignore = PathSpec.from_lines("gitwildmatch", []) regular = MagicMock() - outside_root_symlink = MagicMock() - ignored_symlink = MagicMock() - - path.iterdir.return_value = [regular, outside_root_symlink, ignored_symlink] - regular.absolute.return_value = root / "regular.py" regular.resolve.return_value = root / "regular.py" regular.is_dir.return_value = False + regular.is_file.return_value = True + outside_root_symlink = MagicMock() outside_root_symlink.absolute.return_value = root / "symlink.py" outside_root_symlink.resolve.return_value = Path("/nowhere") + outside_root_symlink.is_dir.return_value = False + outside_root_symlink.is_file.return_value = True + ignored_symlink = MagicMock() ignored_symlink.absolute.return_value = root / ".mypy_cache" / "symlink.py" + ignored_symlink.is_dir.return_value = False + ignored_symlink.is_file.return_value = True + + # A symlink that has an excluded name, but points to an included name + symlink_excluded_name = MagicMock() + symlink_excluded_name.absolute.return_value = root / "excluded_name" + symlink_excluded_name.resolve.return_value = root / "included_name.py" + symlink_excluded_name.is_dir.return_value = False + symlink_excluded_name.is_file.return_value = True + + # A symlink that has an included name, but points to an excluded name + symlink_included_name = MagicMock() + symlink_included_name.absolute.return_value = root / "included_name.py" + symlink_included_name.resolve.return_value = root / "excluded_name" + symlink_included_name.is_dir.return_value = False + symlink_included_name.is_file.return_value = True + + path = MagicMock() + path.iterdir.return_value = [ + regular, + outside_root_symlink, + ignored_symlink, + symlink_excluded_name, + symlink_included_name, + ] files = list( black.gen_python_files( @@ -2458,7 +2482,7 @@ def test_symlinks(self) -> None: quiet=False, ) ) - assert files == [regular] + assert files == [regular, symlink_included_name] path.iterdir.assert_called_once() outside_root_symlink.resolve.assert_called_once() From 639b819efbebca95111050b1717146860e207c8d Mon Sep 17 00:00:00 2001 From: Stephan Hohe Date: Fri, 27 Oct 2023 00:36:39 +0200 Subject: [PATCH 8/8] Match include against path with unresolved symlinks --- src/black/files.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/black/files.py b/src/black/files.py index a4233876bdb..1eed7eda828 100644 --- a/src/black/files.py +++ b/src/black/files.py @@ -361,10 +361,6 @@ def gen_python_files( if normalized_path is None: continue - normalized_path = "/" + normalized_path - if child.is_dir(): - normalized_path += "/" - if child.is_dir(): # If gitignore is None, gitignore usage is disabled, while a Falsey # gitignore is when the directory doesn't have a .gitignore file. @@ -393,7 +389,7 @@ def gen_python_files( warn=verbose or not quiet ): continue - include_match = include.search(normalized_path) if include else True + include_match = include.search(root_relative_path) if include else True if include_match: yield child