Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix matching of absolute paths in --include #3976

Merged
merged 9 commits into from Oct 27, 2023
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -19,6 +19,8 @@

- Add support for single line format skip with other comments on the same line (#3959)

- Fix a bug in the matching of absolute path names in `--include` (#3976)

### Packaging

<!-- Changes to how Black is packaged, such as dependency requirements -->
Expand Down
2 changes: 1 addition & 1 deletion src/black/files.py
Expand Up @@ -389,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

Expand Down
59 changes: 52 additions & 7 deletions tests/test_black.py
Expand Up @@ -2388,6 +2388,27 @@ 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_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]
Expand All @@ -2401,27 +2422,51 @@ 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)
report = black.Report()
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(
Expand All @@ -2437,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()
Expand Down