Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 743258f

Browse files
committed
fix: handle ValueError from relpath on Windows cross-drive paths
When the config file (or other paths) is on a different Windows drive than the git repository, os.path.relpath raises a ValueError because it cannot compute a relative path between paths on different drives. This change wraps all relpath calls in _adjust_args_and_chdir with ValueError suppression, keeping the absolute path when relpath fails. Fixes #2530
1 parent f5678bf commit 743258f

2 files changed

Lines changed: 37 additions & 6 deletions

File tree

pre_commit/main.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import argparse
4+
import contextlib
45
import logging
56
import os
67
import sys
@@ -172,6 +173,14 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
172173
)
173174

174175

176+
def _try_relpath(path: str) -> str:
177+
# on windows, different drives raises ValueError
178+
try:
179+
return os.path.relpath(path)
180+
except ValueError:
181+
return path
182+
183+
175184
def _adjust_args_and_chdir(args: argparse.Namespace) -> None:
176185
# `--config` was specified relative to the non-root working directory
177186
if os.path.exists(args.config):
@@ -188,15 +197,23 @@ def _adjust_args_and_chdir(args: argparse.Namespace) -> None:
188197
toplevel = git.get_root()
189198
os.chdir(toplevel)
190199

191-
args.config = os.path.relpath(args.config)
200+
with contextlib.suppress(ValueError):
201+
# on windows, different drives raises ValueError
202+
args.config = os.path.relpath(args.config)
192203
if args.command in {'run', 'try-repo'}:
193-
args.files = [os.path.relpath(filename) for filename in args.files]
204+
args.files = [
205+
_try_relpath(filename) for filename in args.files
206+
]
194207
if args.commit_msg_filename is not None:
195-
args.commit_msg_filename = os.path.relpath(
196-
args.commit_msg_filename,
197-
)
208+
with contextlib.suppress(ValueError):
209+
# on windows, different drives raises ValueError
210+
args.commit_msg_filename = os.path.relpath(
211+
args.commit_msg_filename,
212+
)
198213
if args.command == 'try-repo' and os.path.exists(args.repo):
199-
args.repo = os.path.relpath(args.repo)
214+
with contextlib.suppress(ValueError):
215+
# on windows, different drives raises ValueError
216+
args.repo = os.path.relpath(args.repo)
200217

201218

202219
def main(argv: Sequence[str] | None = None) -> int:

tests/main_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ def test_adjust_args_and_chdir_non_relative_config(in_git_dir):
7878
assert args.config == C.CONFIG_FILE
7979

8080

81+
def test_adjust_args_and_chdir_relpath_valueerror_cross_drive(in_git_dir):
82+
# regression test for https://github.com/pre-commit/pre-commit/issues/2530
83+
# on windows, different drives raises ValueError from relpath
84+
with in_git_dir.join('foo').ensure_dir().as_cwd():
85+
# use an absolute config path (simulates config on different drive)
86+
args = _args(config=str(in_git_dir.join(C.CONFIG_FILE)))
87+
with mock.patch.object(os.path, 'relpath', side_effect=ValueError):
88+
# should not raise, should keep absolute path
89+
main._adjust_args_and_chdir(args)
90+
assert os.getcwd() == in_git_dir
91+
# config should still be an absolute path (not relative)
92+
assert os.path.isabs(args.config)
93+
94+
8195
def test_adjust_args_try_repo_repo_relative(in_git_dir):
8296
with in_git_dir.join('foo').ensure_dir().as_cwd():
8397
args = _args(command='try-repo', repo='../foo', files=[])

0 commit comments

Comments
 (0)