Fix handling of Windows junctions in normalize_path_maybe_ignore (#2904)
Fixes #2569
This commit is contained in:
parent
fd6e92aa46
commit
24ffc54a53
@ -53,6 +53,8 @@
|
||||
- Black can now parse starred expressions in the target of `for` and `async for`
|
||||
statements, e.g `for item in *items_1, *items_2: pass` (#2879).
|
||||
|
||||
- Fix handling of directory junctions on Windows (#2904)
|
||||
|
||||
### Performance
|
||||
|
||||
<!-- Changes that improve Black's performance. -->
|
||||
|
@ -151,23 +151,22 @@ def normalize_path_maybe_ignore(
|
||||
"""
|
||||
try:
|
||||
abspath = path if path.is_absolute() else Path.cwd() / path
|
||||
normalized_path = abspath.resolve().relative_to(root).as_posix()
|
||||
except OSError as e:
|
||||
if report:
|
||||
report.path_ignored(path, f"cannot be read because {e}")
|
||||
return None
|
||||
|
||||
except ValueError:
|
||||
if path.is_symlink():
|
||||
normalized_path = abspath.resolve()
|
||||
try:
|
||||
root_relative_path = normalized_path.relative_to(root).as_posix()
|
||||
except ValueError:
|
||||
if report:
|
||||
report.path_ignored(
|
||||
path, f"is a symbolic link that points outside {root}"
|
||||
)
|
||||
return None
|
||||
|
||||
raise
|
||||
except OSError as e:
|
||||
if report:
|
||||
report.path_ignored(path, f"cannot be read because {e}")
|
||||
return None
|
||||
|
||||
return normalized_path
|
||||
return root_relative_path
|
||||
|
||||
|
||||
def path_is_excluded(
|
||||
|
@ -1418,6 +1418,25 @@ def test_bpo_33660_workaround(self) -> None:
|
||||
normalized_path = black.normalize_path_maybe_ignore(path, root, report)
|
||||
self.assertEqual(normalized_path, "workspace/project")
|
||||
|
||||
def test_normalize_path_ignore_windows_junctions_outside_of_root(self) -> None:
|
||||
if system() != "Windows":
|
||||
return
|
||||
|
||||
with TemporaryDirectory() as workspace:
|
||||
root = Path(workspace)
|
||||
junction_dir = root / "junction"
|
||||
junction_target_outside_of_root = root / ".."
|
||||
os.system(f"mklink /J {junction_dir} {junction_target_outside_of_root}")
|
||||
|
||||
report = black.Report(verbose=True)
|
||||
normalized_path = black.normalize_path_maybe_ignore(
|
||||
junction_dir, root, report
|
||||
)
|
||||
# Manually delete for Python < 3.8
|
||||
os.system(f"rmdir {junction_dir}")
|
||||
|
||||
self.assertEqual(normalized_path, None)
|
||||
|
||||
def test_newline_comment_interaction(self) -> None:
|
||||
source = "class A:\\\r\n# type: ignore\n pass\n"
|
||||
output = black.format_str(source, mode=DEFAULT_MODE)
|
||||
@ -1994,7 +2013,6 @@ def test_symlink_out_of_root_directory(self) -> None:
|
||||
path.iterdir.return_value = [child]
|
||||
child.resolve.return_value = Path("/a/b/c")
|
||||
child.as_posix.return_value = "/a/b/c"
|
||||
child.is_symlink.return_value = True
|
||||
try:
|
||||
list(
|
||||
black.gen_python_files(
|
||||
@ -2014,31 +2032,6 @@ def test_symlink_out_of_root_directory(self) -> None:
|
||||
pytest.fail(f"`get_python_files_in_dir()` failed: {ve}")
|
||||
path.iterdir.assert_called_once()
|
||||
child.resolve.assert_called_once()
|
||||
child.is_symlink.assert_called_once()
|
||||
# `child` should behave like a strange file which resolved path is clearly
|
||||
# outside of the `root` directory.
|
||||
child.is_symlink.return_value = False
|
||||
with pytest.raises(ValueError):
|
||||
list(
|
||||
black.gen_python_files(
|
||||
path.iterdir(),
|
||||
root,
|
||||
include,
|
||||
exclude,
|
||||
None,
|
||||
None,
|
||||
report,
|
||||
gitignore,
|
||||
verbose=False,
|
||||
quiet=False,
|
||||
)
|
||||
)
|
||||
path.iterdir.assert_called()
|
||||
assert path.iterdir.call_count == 2
|
||||
child.resolve.assert_called()
|
||||
assert child.resolve.call_count == 2
|
||||
child.is_symlink.assert_called()
|
||||
assert child.is_symlink.call_count == 2
|
||||
|
||||
@patch("black.find_project_root", lambda *args: (THIS_DIR.resolve(), None))
|
||||
def test_get_sources_with_stdin(self) -> None:
|
||||
|
Loading…
Reference in New Issue
Block a user