← 返回首页
Validate every fspath with tests · gitpython-developers/GitPython@12e15ba · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

Commit 12e15ba

Browse files
committed
Validate every fspath with tests
1 parent b5abe0f commit 12e15ba

15 files changed

Lines changed: 80 additions & 46 deletions

File tree

‎git/index/base.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ def raise_exc(e: Exception) -> NoReturn:
434434
# characters.
435435
if abs_path not in resolved_paths:
436436
for f in self._iter_expand_paths(glob.glob(abs_path)):
437-
yield os.fspath(f).replace(rs, "")
437+
yield str(f).replace(rs, "")
438438
continue
439439
# END glob handling
440440
try:
@@ -569,7 +569,7 @@ def resolve_blobs(self, iter_blobs: Iterator[Blob]) -> "IndexFile":
569569
for blob in iter_blobs:
570570
stage_null_key = (blob.path, 0)
571571
if stage_null_key in self.entries:
572-
raise ValueError("Path %r already exists at stage 0" % os.fspath(blob.path))
572+
raise ValueError("Path %r already exists at stage 0" % str(blob.path))
573573
# END assert blob is not stage 0 already
574574

575575
# Delete all possible stages.
@@ -652,15 +652,14 @@ def _to_relative_path(self, path: PathLike) -> PathLike:
652652
653653
:raise ValueError:
654654
"""
655-
path = os.fspath(path)
656655
if not osp.isabs(path):
657656
return path
658657
if self.repo.bare:
659658
raise InvalidGitRepositoryError("require non-bare repository")
660659
if not osp.normpath(path).startswith(os.fspath(self.repo.working_tree_dir)):
661660
raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
662661
result = os.path.relpath(path, self.repo.working_tree_dir)
663-
if path.endswith(os.sep) and not result.endswith(os.sep):
662+
if os.fspath(path).endswith(os.sep) and not result.endswith(os.sep):
664663
result += os.sep
665664
return result
666665

@@ -1364,7 +1363,7 @@ def make_exc() -> GitCommandError:
13641363
if not folder.endswith("/"):
13651364
folder += "/"
13661365
for entry in self.entries.values():
1367-
if os.fspath(entry.path).startswith(folder):
1366+
if entry.path.startswith(folder):
13681367
p = entry.path
13691368
self._write_path_to_stdin(proc, p, p, make_exc, fprogress, read_from_stdout=False)
13701369
checked_out_files.append(p)

‎git/index/fun.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def run_commit_hook(name: str, index: "IndexFile", *args: str) -> None:
8787
return
8888

8989
env = os.environ.copy()
90-
env["GIT_INDEX_FILE"] = safe_decode(index.path)
90+
env["GIT_INDEX_FILE"] = safe_decode(os.fspath(index.path))
9191
env["GIT_EDITOR"] = ":"
9292
cmd = [hp]
9393
try:
@@ -167,7 +167,7 @@ def write_cache(
167167
beginoffset = tell()
168168
write(entry.ctime_bytes) # ctime
169169
write(entry.mtime_bytes) # mtime
170-
path_str = os.fspath(entry.path)
170+
path_str = str(entry.path)
171171
path: bytes = force_bytes(path_str, encoding=defenc)
172172
plen = len(path) & CE_NAMEMASK # Path length
173173
assert plen == len(path), "Path %s too long to fit into index" % entry.path

‎git/index/typ.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ def __init__(self, paths: Sequence[PathLike]) -> None:
5858

5959
def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool:
6060
blob_pathlike: PathLike = stage_blob[1].path
61-
blob_path = Path(blob_pathlike)
61+
blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike)
6262
for pathlike in self.paths:
63-
path = Path(pathlike)
63+
path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike)
6464
# TODO: Change to use `PosixPath.is_relative_to` once Python 3.8 is no
6565
# longer supported.
6666
filter_parts = path.parts

‎git/index/util.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class TemporaryFileSwap:
3737
__slots__ = ("file_path", "tmp_file_path")
3838

3939
def __init__(self, file_path: PathLike) -> None:
40-
self.file_path = os.fspath(file_path)
41-
dirname, basename = osp.split(self.file_path)
40+
self.file_path = file_path
41+
dirname, basename = osp.split(file_path)
4242
fd, self.tmp_file_path = tempfile.mkstemp(prefix=basename, dir=dirname)
4343
os.close(fd)
4444
with contextlib.suppress(OSError): # It may be that the source does not exist.
@@ -106,7 +106,7 @@ def git_working_dir(func: Callable[..., _T]) -> Callable[..., _T]:
106106
@wraps(func)
107107
def set_git_working_dir(self: "IndexFile", *args: Any, **kwargs: Any) -> _T:
108108
cur_wd = os.getcwd()
109-
os.chdir(os.fspath(self.repo.working_tree_dir))
109+
os.chdir(self.repo.working_tree_dir)
110110
try:
111111
return func(self, *args, **kwargs)
112112
finally:

‎git/objects/submodule/base.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def _clone_repo(
352352
module_abspath_dir = osp.dirname(module_abspath)
353353
if not osp.isdir(module_abspath_dir):
354354
os.makedirs(module_abspath_dir)
355-
module_checkout_path = osp.join(os.fspath(repo.working_tree_dir), path)
355+
module_checkout_path = osp.join(repo.working_tree_dir, path)
356356

357357
if url.startswith("../"):
358358
remote_name = cast("RemoteReference", repo.active_branch.tracking_branch()).remote_name
@@ -1016,7 +1016,7 @@ def move(self, module_path: PathLike, configuration: bool = True, module: bool =
10161016
return self
10171017
# END handle no change
10181018

1019-
module_checkout_abspath = join_path_native(os.fspath(self.repo.working_tree_dir), module_checkout_path)
1019+
module_checkout_abspath = join_path_native(str(self.repo.working_tree_dir), module_checkout_path)
10201020
if osp.isfile(module_checkout_abspath):
10211021
raise ValueError("Cannot move repository onto a file: %s" % module_checkout_abspath)
10221022
# END handle target files
@@ -1229,7 +1229,7 @@ def remove(
12291229
wtd = mod.working_tree_dir
12301230
del mod # Release file-handles (Windows).
12311231
gc.collect()
1232-
rmtree(wtd)
1232+
rmtree(str(wtd))
12331233
# END delete tree if possible
12341234
# END handle force
12351235

@@ -1313,7 +1313,7 @@ def set_parent_commit(self, commit: Union[Commit_ish, str, None], check: bool =
13131313
# If check is False, we might see a parent-commit that doesn't even contain the
13141314
# submodule anymore. in that case, mark our sha as being NULL.
13151315
try:
1316-
self.binsha = pctree[os.fspath(self.path)].binsha
1316+
self.binsha = pctree[str(self.path)].binsha
13171317
except KeyError:
13181318
self.binsha = self.NULL_BIN_SHA
13191319

@@ -1395,7 +1395,7 @@ def rename(self, new_name: str) -> "Submodule":
13951395
destination_module_abspath = self._module_abspath(self.repo, self.path, new_name)
13961396
source_dir = mod.git_dir
13971397
# Let's be sure the submodule name is not so obviously tied to a directory.
1398-
if os.fspath(destination_module_abspath).startswith(os.fspath(mod.git_dir)):
1398+
if str(destination_module_abspath).startswith(str(mod.git_dir)):
13991399
tmp_dir = self._module_abspath(self.repo, self.path, str(uuid.uuid4()))
14001400
os.renames(source_dir, tmp_dir)
14011401
source_dir = tmp_dir

‎git/refs/head.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
__all__ = ["HEAD", "Head"]
1010

11-
import os
1211
from git.config import GitConfigParser, SectionConstraint
1312
from git.exc import GitCommandError
1413
from git.util import join_path
@@ -45,7 +44,6 @@ class HEAD(SymbolicReference):
4544
__slots__ = ()
4645

4746
def __init__(self, repo: "Repo", path: PathLike = _HEAD_NAME) -> None:
48-
path = os.fspath(path)
4947
if path != self._HEAD_NAME:
5048
raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
5149
super().__init__(repo, path)

‎git/refs/log.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
__all__ = ["RefLog", "RefLogEntry"]
55

66
from mmap import mmap
7-
import os
87
import os.path as osp
98
import re
109
import time as _time
@@ -168,7 +167,7 @@ def __init__(self, filepath: Union[PathLike, None] = None) -> None:
168167
"""Initialize this instance with an optional filepath, from which we will
169168
initialize our data. The path is also used to write changes back using the
170169
:meth:`write` method."""
171-
self._path = None if filepath is None else os.fspath(filepath)
170+
self._path = filepath
172171
if filepath is not None:
173172
self._read_from_file()
174173
# END handle filepath

‎git/refs/symbolic.py‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
__all__ = ["SymbolicReference"]
55

66
import os
7+
from pathlib import Path
78

89
from gitdb.exc import BadName, BadObject
910

@@ -76,10 +77,10 @@ class SymbolicReference:
7677

7778
def __init__(self, repo: "Repo", path: PathLike, check_path: bool = False) -> None:
7879
self.repo = repo
79-
self.path = os.fspath(path)
80+
self.path: PathLike = path
8081

8182
def __str__(self) -> str:
82-
return self.path
83+
return os.fspath(self.path)
8384

8485
def __repr__(self) -> str:
8586
return '<git.%s "%s">' % (self.__class__.__name__, self.path)
@@ -103,7 +104,7 @@ def name(self) -> str:
103104
In case of symbolic references, the shortest assumable name is the path
104105
itself.
105106
"""
106-
return self.path
107+
return os.fspath(self.path)
107108

108109
@property
109110
def abspath(self) -> PathLike:
@@ -212,7 +213,7 @@ def _check_ref_name_valid(ref_path: PathLike) -> None:
212213
raise ValueError(f"Invalid reference '{ref_path}': references cannot end with a forward slash (/)")
213214
elif previous == "@" and one_before_previous is None:
214215
raise ValueError(f"Invalid reference '{ref_path}': references cannot be '@'")
215-
elif any(component.endswith(".lock") for component in os.fspath(ref_path).split("/")):
216+
elif any(component.endswith(".lock") for component in Path(ref_path).parts):
216217
raise ValueError(
217218
f"Invalid reference '{ref_path}': references cannot have slash-separated components that end with"
218219
" '.lock'"
@@ -235,7 +236,7 @@ def _get_ref_info_helper(
235236
tokens: Union[None, List[str], Tuple[str, str]] = None
236237
repodir = _git_dir(repo, ref_path)
237238
try:
238-
with open(os.path.join(repodir, os.fspath(ref_path)), "rt", encoding="UTF-8") as fp:
239+
with open(os.path.join(repodir, ref_path), "rt", encoding="UTF-8") as fp:
239240
value = fp.read().rstrip()
240241
# Don't only split on spaces, but on whitespace, which allows to parse lines like:
241242
# 60b64ef992065e2600bfef6187a97f92398a9144 branch 'master' of git-server:/path/to/repo
@@ -706,7 +707,7 @@ def _create(
706707
if not force and os.path.isfile(abs_ref_path):
707708
target_data = str(target)
708709
if isinstance(target, SymbolicReference):
709-
target_data = target.path
710+
target_data = os.fspath(target.path)
710711
if not resolve:
711712
target_data = "ref: " + target_data
712713
with open(abs_ref_path, "rb") as fd:
@@ -930,4 +931,4 @@ def from_path(cls: Type[T_References], repo: "Repo", path: PathLike) -> T_Refere
930931

931932
def is_remote(self) -> bool:
932933
""":return: True if this symbolic reference points to a remote branch"""
933-
return self.path.startswith(self._remote_common_path_default + "/")
934+
return os.fspath(self.path).startswith(self._remote_common_path_default + "/")

‎git/repo/base.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ class Repo:
126126
working_dir: PathLike
127127
"""The working directory of the git command."""
128128

129-
_working_tree_dir: Optional[str] = None
129+
# stored as string for easier processing, but annotated as path for clearer intention
130+
_working_tree_dir: Optional[PathLike] = None
130131

131132
git_dir: PathLike
132133
"""The ``.git`` repository directory."""
@@ -215,13 +216,13 @@ def __init__(
215216
epath = path or os.getenv("GIT_DIR")
216217
if not epath:
217218
epath = os.getcwd()
219+
epath = os.fspath(epath)
218220
if Git.is_cygwin():
219221
# Given how the tests are written, this seems more likely to catch Cygwin
220222
# git used from Windows than Windows git used from Cygwin. Therefore
221223
# changing to Cygwin-style paths is the relevant operation.
222-
epath = cygpath(os.fspath(epath))
224+
epath = cygpath(epath)
223225

224-
epath = os.fspath(epath)
225226
if expand_vars and re.search(self.re_envvars, epath):
226227
warnings.warn(
227228
"The use of environment variables in paths is deprecated"
@@ -306,7 +307,7 @@ def __init__(
306307
self._working_tree_dir = None
307308
# END working dir handling
308309

309-
self.working_dir: str = self._working_tree_dir or self.common_dir
310+
self.working_dir: PathLike = self._working_tree_dir or self.common_dir
310311
self.git = self.GitCommandWrapperType(self.working_dir)
311312

312313
# Special handling, in special times.
@@ -366,7 +367,7 @@ def description(self, descr: str) -> None:
366367
fp.write((descr + "\n").encode(defenc))
367368

368369
@property
369-
def working_tree_dir(self) -> Optional[str]:
370+
def working_tree_dir(self) -> Optional[PathLike]:
370371
"""
371372
:return:
372373
The working tree directory of our git repository.
@@ -554,7 +555,7 @@ def tag(self, path: PathLike) -> TagReference:
554555

555556
@staticmethod
556557
def _to_full_tag_path(path: PathLike) -> str:
557-
path_str = os.fspath(path)
558+
path_str = str(path)
558559
if path_str.startswith(TagReference._common_path_default + "/"):
559560
return path_str
560561
if path_str.startswith(TagReference._common_default + "/"):
@@ -1355,6 +1356,7 @@ def _clone(
13551356
) -> "Repo":
13561357
odbt = kwargs.pop("odbt", odb_default_type)
13571358

1359+
# url may be a path and this has no effect if it is a string
13581360
url = os.fspath(url)
13591361
path = os.fspath(path)
13601362

‎git/repo/fun.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ def is_git_dir(d: PathLike) -> bool:
6262
clearly indicates that we don't support it. There is the unlikely danger to
6363
throw if we see directories which just look like a worktree dir, but are none.
6464
"""
65-
d = os.fspath(d)
6665
if osp.isdir(d):
6766
if (osp.isdir(osp.join(d, "objects")) or "GIT_OBJECT_DIRECTORY" in os.environ) and osp.isdir(
6867
osp.join(d, "refs")

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.