GitPython 3.1.45__tar.gz → 3.1.46__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. {gitpython-3.1.45 → gitpython-3.1.46/GitPython.egg-info}/PKG-INFO +2 -2
  2. {gitpython-3.1.45 → gitpython-3.1.46}/GitPython.egg-info/requires.txt +3 -1
  3. {gitpython-3.1.45/GitPython.egg-info → gitpython-3.1.46}/PKG-INFO +2 -2
  4. gitpython-3.1.46/VERSION +1 -0
  5. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/changes.rst +20 -14
  6. {gitpython-3.1.45 → gitpython-3.1.46}/git/__init__.py +1 -1
  7. {gitpython-3.1.45 → gitpython-3.1.46}/git/config.py +9 -7
  8. {gitpython-3.1.45 → gitpython-3.1.46}/git/diff.py +3 -2
  9. {gitpython-3.1.45 → gitpython-3.1.46}/git/index/base.py +6 -6
  10. {gitpython-3.1.45 → gitpython-3.1.46}/git/index/fun.py +12 -6
  11. {gitpython-3.1.45 → gitpython-3.1.46}/git/index/typ.py +16 -3
  12. {gitpython-3.1.45 → gitpython-3.1.46}/git/index/util.py +2 -2
  13. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/blob.py +2 -1
  14. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/commit.py +1 -1
  15. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/submodule/base.py +4 -4
  16. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/tree.py +4 -2
  17. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/head.py +1 -5
  18. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/log.py +1 -1
  19. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/reference.py +2 -1
  20. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/symbolic.py +16 -15
  21. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/tag.py +4 -4
  22. {gitpython-3.1.45 → gitpython-3.1.46}/git/repo/base.py +13 -18
  23. {gitpython-3.1.45 → gitpython-3.1.46}/git/repo/fun.py +1 -1
  24. {gitpython-3.1.45 → gitpython-3.1.46}/git/types.py +2 -2
  25. {gitpython-3.1.45 → gitpython-3.1.46}/git/util.py +16 -16
  26. {gitpython-3.1.45 → gitpython-3.1.46}/pyproject.toml +0 -1
  27. {gitpython-3.1.45 → gitpython-3.1.46}/test-requirements.txt +1 -1
  28. gitpython-3.1.45/VERSION +0 -1
  29. {gitpython-3.1.45 → gitpython-3.1.46}/AUTHORS +0 -0
  30. {gitpython-3.1.45 → gitpython-3.1.46}/CHANGES +0 -0
  31. {gitpython-3.1.45 → gitpython-3.1.46}/CONTRIBUTING.md +0 -0
  32. {gitpython-3.1.45 → gitpython-3.1.46}/GitPython.egg-info/SOURCES.txt +0 -0
  33. {gitpython-3.1.45 → gitpython-3.1.46}/GitPython.egg-info/dependency_links.txt +0 -0
  34. {gitpython-3.1.45 → gitpython-3.1.46}/GitPython.egg-info/not-zip-safe +0 -0
  35. {gitpython-3.1.45 → gitpython-3.1.46}/GitPython.egg-info/top_level.txt +0 -0
  36. {gitpython-3.1.45 → gitpython-3.1.46}/LICENSE +0 -0
  37. {gitpython-3.1.45 → gitpython-3.1.46}/MANIFEST.in +0 -0
  38. {gitpython-3.1.45 → gitpython-3.1.46}/README.md +0 -0
  39. {gitpython-3.1.45 → gitpython-3.1.46}/doc/.gitignore +0 -0
  40. {gitpython-3.1.45 → gitpython-3.1.46}/doc/Makefile +0 -0
  41. {gitpython-3.1.45 → gitpython-3.1.46}/doc/requirements.txt +0 -0
  42. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/conf.py +0 -0
  43. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/index.rst +0 -0
  44. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/intro.rst +0 -0
  45. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/quickstart.rst +0 -0
  46. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/reference.rst +0 -0
  47. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/roadmap.rst +0 -0
  48. {gitpython-3.1.45 → gitpython-3.1.46}/doc/source/tutorial.rst +0 -0
  49. {gitpython-3.1.45 → gitpython-3.1.46}/git/cmd.py +0 -0
  50. {gitpython-3.1.45 → gitpython-3.1.46}/git/compat.py +0 -0
  51. {gitpython-3.1.45 → gitpython-3.1.46}/git/db.py +0 -0
  52. {gitpython-3.1.45 → gitpython-3.1.46}/git/exc.py +0 -0
  53. {gitpython-3.1.45 → gitpython-3.1.46}/git/index/__init__.py +0 -0
  54. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/__init__.py +0 -0
  55. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/base.py +0 -0
  56. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/fun.py +0 -0
  57. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/submodule/__init__.py +0 -0
  58. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/submodule/root.py +0 -0
  59. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/submodule/util.py +0 -0
  60. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/tag.py +0 -0
  61. {gitpython-3.1.45 → gitpython-3.1.46}/git/objects/util.py +0 -0
  62. {gitpython-3.1.45 → gitpython-3.1.46}/git/py.typed +0 -0
  63. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/__init__.py +0 -0
  64. {gitpython-3.1.45 → gitpython-3.1.46}/git/refs/remote.py +0 -0
  65. {gitpython-3.1.45 → gitpython-3.1.46}/git/remote.py +0 -0
  66. {gitpython-3.1.45 → gitpython-3.1.46}/git/repo/__init__.py +0 -0
  67. {gitpython-3.1.45 → gitpython-3.1.46}/requirements.txt +0 -0
  68. {gitpython-3.1.45 → gitpython-3.1.46}/setup.cfg +0 -0
  69. {gitpython-3.1.45 → gitpython-3.1.46}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GitPython
3
- Version: 3.1.45
3
+ Version: 3.1.46
4
4
  Summary: GitPython is a Python library used to interact with Git repositories
5
5
  Home-page: https://github.com/gitpython-developers/GitPython
6
6
  Author: Sebastian Thiel, Michael Trier
@@ -32,7 +32,7 @@ Provides-Extra: test
32
32
  Requires-Dist: coverage[toml]; extra == "test"
33
33
  Requires-Dist: ddt!=1.4.3,>=1.1.1; extra == "test"
34
34
  Requires-Dist: mock; python_version < "3.8" and extra == "test"
35
- Requires-Dist: mypy; extra == "test"
35
+ Requires-Dist: mypy==1.18.2; python_version >= "3.9" and extra == "test"
36
36
  Requires-Dist: pre-commit; extra == "test"
37
37
  Requires-Dist: pytest>=7.3.1; extra == "test"
38
38
  Requires-Dist: pytest-cov; extra == "test"
@@ -11,7 +11,6 @@ sphinx-autodoc-typehints
11
11
  [test]
12
12
  coverage[toml]
13
13
  ddt!=1.4.3,>=1.1.1
14
- mypy
15
14
  pre-commit
16
15
  pytest>=7.3.1
17
16
  pytest-cov
@@ -24,3 +23,6 @@ typing-extensions
24
23
 
25
24
  [test:python_version < "3.8"]
26
25
  mock
26
+
27
+ [test:python_version >= "3.9"]
28
+ mypy==1.18.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GitPython
3
- Version: 3.1.45
3
+ Version: 3.1.46
4
4
  Summary: GitPython is a Python library used to interact with Git repositories
5
5
  Home-page: https://github.com/gitpython-developers/GitPython
6
6
  Author: Sebastian Thiel, Michael Trier
@@ -32,7 +32,7 @@ Provides-Extra: test
32
32
  Requires-Dist: coverage[toml]; extra == "test"
33
33
  Requires-Dist: ddt!=1.4.3,>=1.1.1; extra == "test"
34
34
  Requires-Dist: mock; python_version < "3.8" and extra == "test"
35
- Requires-Dist: mypy; extra == "test"
35
+ Requires-Dist: mypy==1.18.2; python_version >= "3.9" and extra == "test"
36
36
  Requires-Dist: pre-commit; extra == "test"
37
37
  Requires-Dist: pytest>=7.3.1; extra == "test"
38
38
  Requires-Dist: pytest-cov; extra == "test"
@@ -0,0 +1 @@
1
+ 3.1.46
@@ -2,6 +2,12 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ 3.1.46
6
+ ======
7
+
8
+ See the following for all changes.
9
+ https://github.com/gitpython-developers/GitPython/releases/tag/3.1.46
10
+
5
11
  3.1.45
6
12
  ======
7
13
 
@@ -111,7 +117,7 @@ https://github.com/gitpython-developers/gitpython/milestone/61?closed=1
111
117
  but a necessary fix for https://github.com/gitpython-developers/GitPython/issues/1515.
112
118
  Please take a look at the PR for more information and how to bypass these protections
113
119
  in case they cause breakage: https://github.com/gitpython-developers/GitPython/pull/1521.
114
-
120
+
115
121
 
116
122
  See the following for all changes.
117
123
  https://github.com/gitpython-developers/gitpython/milestone/60?closed=1
@@ -176,38 +182,38 @@ https://github.com/gitpython-developers/gitpython/milestone/53?closed=1
176
182
  * General:
177
183
 
178
184
  - Remove python 3.6 support
179
-
185
+
180
186
  - Remove distutils ahead of deprecation in standard library.
181
-
187
+
182
188
  - Update sphinx to 4.1.12 and use autodoc-typehints.
183
-
189
+
184
190
  - Include README as long_description on PyPI
185
-
191
+
186
192
  - Test against earliest and latest minor version available on Github Actions (e.g. 3.9.0 and 3.9.7)
187
-
193
+
188
194
 
189
195
  * Typing:
190
196
 
191
197
  - Add types to ALL functions.
192
-
198
+
193
199
  - Ensure py.typed is collected.
194
-
200
+
195
201
  - Increase mypy strictness with disallow_untyped_defs, warn_redundant_casts, warn_unreachable.
196
-
202
+
197
203
  - Use typing.NamedTuple and typing.OrderedDict now 3.6 dropped.
198
-
204
+
199
205
  - Make Protocol classes ABCs at runtime due to new behaviour/bug in 3.9.7 & 3.10.0-rc1
200
-
206
+
201
207
  - Remove use of typing.TypeGuard until later release, to allow dependent libs time to update.
202
-
208
+
203
209
  - Tracking issue: https://github.com/gitpython-developers/GitPython/issues/1095
204
210
 
205
211
  * Runtime improvements:
206
212
 
207
213
  - Add clone_multi_options support to submodule.add()
208
-
214
+
209
215
  - Delay calling get_user_id() unless essential, to support sand-boxed environments.
210
-
216
+
211
217
  - Add timeout to handle_process_output(), in case thread.join() hangs.
212
218
 
213
219
  See the following for details:
@@ -86,7 +86,7 @@ __all__ = [
86
86
  "to_hex_sha",
87
87
  ]
88
88
 
89
- __version__ = '3.1.45'
89
+ __version__ = '3.1.46'
90
90
 
91
91
  from typing import Any, List, Optional, Sequence, TYPE_CHECKING, Tuple, Union
92
92
 
@@ -66,7 +66,7 @@ _logger = logging.getLogger(__name__)
66
66
  CONFIG_LEVELS: ConfigLevels_Tup = ("system", "user", "global", "repository")
67
67
  """The configuration level of a configuration file."""
68
68
 
69
- CONDITIONAL_INCLUDE_REGEXP = re.compile(r"(?<=includeIf )\"(gitdir|gitdir/i|onbranch):(.+)\"")
69
+ CONDITIONAL_INCLUDE_REGEXP = re.compile(r"(?<=includeIf )\"(gitdir|gitdir/i|onbranch|hasconfig:remote\.\*\.url):(.+)\"")
70
70
  """Section pattern to detect conditional includes.
71
71
 
72
72
  See: https://git-scm.com/docs/git-config#_conditional_includes
@@ -574,11 +574,11 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
574
574
  if keyword.endswith("/i"):
575
575
  value = re.sub(
576
576
  r"[a-zA-Z]",
577
- lambda m: "[{}{}]".format(m.group().lower(), m.group().upper()),
577
+ lambda m: f"[{m.group().lower()!r}{m.group().upper()!r}]",
578
578
  value,
579
579
  )
580
580
  if self._repo.git_dir:
581
- if fnmatch.fnmatchcase(str(self._repo.git_dir), value):
581
+ if fnmatch.fnmatchcase(os.fspath(self._repo.git_dir), value):
582
582
  paths += self.items(section)
583
583
 
584
584
  elif keyword == "onbranch":
@@ -590,7 +590,11 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
590
590
 
591
591
  if fnmatch.fnmatchcase(branch_name, value):
592
592
  paths += self.items(section)
593
-
593
+ elif keyword == "hasconfig:remote.*.url":
594
+ for remote in self._repo.remotes:
595
+ if fnmatch.fnmatchcase(remote.url, value):
596
+ paths += self.items(section)
597
+ break
594
598
  return paths
595
599
 
596
600
  def read(self) -> None: # type: ignore[override]
@@ -629,8 +633,6 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
629
633
  file_path = cast(IO[bytes], file_path)
630
634
  self._read(file_path, file_path.name)
631
635
  else:
632
- # Assume a path if it is not a file-object.
633
- file_path = cast(PathLike, file_path)
634
636
  try:
635
637
  with open(file_path, "rb") as fp:
636
638
  file_ok = True
@@ -764,7 +766,7 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
764
766
  if self.read_only:
765
767
  raise IOError("Cannot execute non-constant method %s.%s" % (self, method_name))
766
768
 
767
- def add_section(self, section: str) -> None:
769
+ def add_section(self, section: "cp._SectionName") -> None:
768
770
  """Assures added options will stay in order."""
769
771
  return super().add_section(section)
770
772
 
@@ -23,13 +23,14 @@ from typing import (
23
23
  List,
24
24
  Match,
25
25
  Optional,
26
+ Sequence,
26
27
  Tuple,
27
28
  TYPE_CHECKING,
28
29
  TypeVar,
29
30
  Union,
30
31
  cast,
31
32
  )
32
- from git.types import Literal, PathLike
33
+ from git.types import PathLike, Literal
33
34
 
34
35
  if TYPE_CHECKING:
35
36
  from subprocess import Popen
@@ -289,7 +290,7 @@ class DiffIndex(List[T_Diff]):
289
290
  The class improves the diff handling convenience.
290
291
  """
291
292
 
292
- change_type = ("A", "C", "D", "R", "M", "T")
293
+ change_type: Sequence[Literal["A", "C", "D", "R", "M", "T"]] = ("A", "C", "D", "R", "M", "T") # noqa: F821
293
294
  """Change type invariant identifying possible ways a blob can have changed:
294
295
 
295
296
  * ``A`` = Added
@@ -407,7 +407,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
407
407
  r = str(self.repo.working_tree_dir)
408
408
  rs = r + os.sep
409
409
  for path in paths:
410
- abs_path = str(path)
410
+ abs_path = os.fspath(path)
411
411
  if not osp.isabs(abs_path):
412
412
  abs_path = osp.join(r, path)
413
413
  # END make absolute path
@@ -656,10 +656,10 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
656
656
  return path
657
657
  if self.repo.bare:
658
658
  raise InvalidGitRepositoryError("require non-bare repository")
659
- if not osp.normpath(str(path)).startswith(str(self.repo.working_tree_dir)):
659
+ if not osp.normpath(path).startswith(str(self.repo.working_tree_dir)):
660
660
  raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
661
661
  result = os.path.relpath(path, self.repo.working_tree_dir)
662
- if str(path).endswith(os.sep) and not result.endswith(os.sep):
662
+ if os.fspath(path).endswith(os.sep) and not result.endswith(os.sep):
663
663
  result += os.sep
664
664
  return result
665
665
 
@@ -1036,7 +1036,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
1036
1036
  args.append("--")
1037
1037
 
1038
1038
  # Preprocess paths.
1039
- paths = self._items_to_rela_paths(items)
1039
+ paths = list(map(os.fspath, self._items_to_rela_paths(items))) # type: ignore[arg-type]
1040
1040
  removed_paths = self.repo.git.rm(args, paths, **kwargs).splitlines()
1041
1041
 
1042
1042
  # Process output to gain proper paths.
@@ -1359,11 +1359,11 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
1359
1359
  try:
1360
1360
  self.entries[(co_path, 0)]
1361
1361
  except KeyError:
1362
- folder = str(co_path)
1362
+ folder = co_path
1363
1363
  if not folder.endswith("/"):
1364
1364
  folder += "/"
1365
1365
  for entry in self.entries.values():
1366
- if str(entry.path).startswith(folder):
1366
+ if os.fspath(entry.path).startswith(folder):
1367
1367
  p = entry.path
1368
1368
  self._write_path_to_stdin(proc, p, p, make_exc, fprogress, read_from_stdout=False)
1369
1369
  checked_out_files.append(p)
@@ -36,7 +36,7 @@ from git.objects.fun import (
36
36
  )
37
37
  from git.util import IndexFileSHA1Writer, finalize_process
38
38
 
39
- from .typ import BaseIndexEntry, IndexEntry, CE_NAMEMASK, CE_STAGESHIFT
39
+ from .typ import CE_EXTENDED, BaseIndexEntry, IndexEntry, CE_NAMEMASK, CE_STAGESHIFT
40
40
  from .util import pack, unpack
41
41
 
42
42
  # typing -----------------------------------------------------------------------------
@@ -87,7 +87,7 @@ def run_commit_hook(name: str, index: "IndexFile", *args: str) -> None:
87
87
  return
88
88
 
89
89
  env = os.environ.copy()
90
- env["GIT_INDEX_FILE"] = safe_decode(str(index.path))
90
+ env["GIT_INDEX_FILE"] = safe_decode(os.fspath(index.path))
91
91
  env["GIT_EDITOR"] = ":"
92
92
  cmd = [hp]
93
93
  try:
@@ -158,7 +158,7 @@ def write_cache(
158
158
  write = stream_sha.write
159
159
 
160
160
  # Header
161
- version = 2
161
+ version = 3 if any(entry.extended_flags for entry in entries) else 2
162
162
  write(b"DIRC")
163
163
  write(pack(">LL", version, len(entries)))
164
164
 
@@ -172,6 +172,8 @@ def write_cache(
172
172
  plen = len(path) & CE_NAMEMASK # Path length
173
173
  assert plen == len(path), "Path %s too long to fit into index" % entry.path
174
174
  flags = plen | (entry.flags & CE_NAMEMASK_INV) # Clear possible previous values.
175
+ if entry.extended_flags:
176
+ flags |= CE_EXTENDED
175
177
  write(
176
178
  pack(
177
179
  ">LLLLLL20sH",
@@ -185,6 +187,8 @@ def write_cache(
185
187
  flags,
186
188
  )
187
189
  )
190
+ if entry.extended_flags:
191
+ write(pack(">H", entry.extended_flags))
188
192
  write(path)
189
193
  real_size = (tell() - beginoffset + 8) & ~7
190
194
  write(b"\0" * ((beginoffset + real_size) - tell()))
@@ -206,8 +210,7 @@ def read_header(stream: IO[bytes]) -> Tuple[int, int]:
206
210
  unpacked = cast(Tuple[int, int], unpack(">LL", stream.read(4 * 2)))
207
211
  version, num_entries = unpacked
208
212
 
209
- # TODO: Handle version 3: extended data, see read-cache.c.
210
- assert version in (1, 2), "Unsupported git index version %i, only 1 and 2 are supported" % version
213
+ assert version in (1, 2, 3), "Unsupported git index version %i, only 1, 2, and 3 are supported" % version
211
214
  return version, num_entries
212
215
 
213
216
 
@@ -260,12 +263,15 @@ def read_cache(
260
263
  ctime = unpack(">8s", read(8))[0]
261
264
  mtime = unpack(">8s", read(8))[0]
262
265
  (dev, ino, mode, uid, gid, size, sha, flags) = unpack(">LLLLLL20sH", read(20 + 4 * 6 + 2))
266
+ extended_flags = 0
267
+ if flags & CE_EXTENDED:
268
+ extended_flags = unpack(">H", read(2))[0]
263
269
  path_size = flags & CE_NAMEMASK
264
270
  path = read(path_size).decode(defenc)
265
271
 
266
272
  real_size = (tell() - beginoffset + 8) & ~7
267
273
  read((beginoffset + real_size) - tell())
268
- entry = IndexEntry((mode, sha, flags, path, ctime, mtime, dev, ino, uid, gid, size))
274
+ entry = IndexEntry((mode, sha, flags, path, ctime, mtime, dev, ino, uid, gid, size, extended_flags))
269
275
  # entry_key would be the method to use, but we save the effort.
270
276
  entries[(path, entry.stage)] = entry
271
277
  count += 1
@@ -32,6 +32,9 @@ CE_EXTENDED = 0x4000
32
32
  CE_VALID = 0x8000
33
33
  CE_STAGESHIFT = 12
34
34
 
35
+ CE_EXT_SKIP_WORKTREE = 0x4000
36
+ CE_EXT_INTENT_TO_ADD = 0x2000
37
+
35
38
  # } END invariants
36
39
 
37
40
 
@@ -87,6 +90,8 @@ class BaseIndexEntryHelper(NamedTuple):
87
90
  uid: int = 0
88
91
  gid: int = 0
89
92
  size: int = 0
93
+ # version 3 extended flags, only when (flags & CE_EXTENDED) is set
94
+ extended_flags: int = 0
90
95
 
91
96
 
92
97
  class BaseIndexEntry(BaseIndexEntryHelper):
@@ -102,7 +107,7 @@ class BaseIndexEntry(BaseIndexEntryHelper):
102
107
  cls,
103
108
  inp_tuple: Union[
104
109
  Tuple[int, bytes, int, PathLike],
105
- Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int],
110
+ Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int, int],
106
111
  ],
107
112
  ) -> "BaseIndexEntry":
108
113
  """Override ``__new__`` to allow construction from a tuple for backwards
@@ -134,6 +139,14 @@ class BaseIndexEntry(BaseIndexEntryHelper):
134
139
  """
135
140
  return (self.flags & CE_STAGEMASK) >> CE_STAGESHIFT
136
141
 
142
+ @property
143
+ def skip_worktree(self) -> bool:
144
+ return (self.extended_flags & CE_EXT_SKIP_WORKTREE) > 0
145
+
146
+ @property
147
+ def intent_to_add(self) -> bool:
148
+ return (self.extended_flags & CE_EXT_INTENT_TO_ADD) > 0
149
+
137
150
  @classmethod
138
151
  def from_blob(cls, blob: Blob, stage: int = 0) -> "BaseIndexEntry":
139
152
  """:return: Fully equipped BaseIndexEntry at the given stage"""
@@ -179,7 +192,7 @@ class IndexEntry(BaseIndexEntry):
179
192
  Instance of type :class:`BaseIndexEntry`.
180
193
  """
181
194
  time = pack(">LL", 0, 0)
182
- return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0))
195
+ return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0)) # type: ignore[arg-type]
183
196
 
184
197
  @classmethod
185
198
  def from_blob(cls, blob: Blob, stage: int = 0) -> "IndexEntry":
@@ -198,5 +211,5 @@ class IndexEntry(BaseIndexEntry):
198
211
  0,
199
212
  0,
200
213
  blob.size,
201
- )
214
+ ) # type: ignore[arg-type]
202
215
  )
@@ -15,7 +15,7 @@ from types import TracebackType
15
15
 
16
16
  # typing ----------------------------------------------------------------------
17
17
 
18
- from typing import Any, Callable, TYPE_CHECKING, Optional, Type
18
+ from typing import Any, Callable, TYPE_CHECKING, Optional, Type, cast
19
19
 
20
20
  from git.types import Literal, PathLike, _T
21
21
 
@@ -106,7 +106,7 @@ def git_working_dir(func: Callable[..., _T]) -> Callable[..., _T]:
106
106
  @wraps(func)
107
107
  def set_git_working_dir(self: "IndexFile", *args: Any, **kwargs: Any) -> _T:
108
108
  cur_wd = os.getcwd()
109
- os.chdir(str(self.repo.working_tree_dir))
109
+ os.chdir(cast(PathLike, self.repo.working_tree_dir))
110
110
  try:
111
111
  return func(self, *args, **kwargs)
112
112
  finally:
@@ -6,6 +6,7 @@
6
6
  __all__ = ["Blob"]
7
7
 
8
8
  from mimetypes import guess_type
9
+ import os
9
10
  import sys
10
11
 
11
12
  if sys.version_info >= (3, 8):
@@ -44,5 +45,5 @@ class Blob(base.IndexObject):
44
45
  """
45
46
  guesses = None
46
47
  if self.path:
47
- guesses = guess_type(str(self.path))
48
+ guesses = guess_type(os.fspath(self.path))
48
49
  return guesses and guesses[0] or self.DEFAULT_MIME_TYPE
@@ -900,7 +900,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
900
900
  if self.message:
901
901
  results = re.findall(
902
902
  r"^Co-authored-by: (.*) <(.*?)>$",
903
- self.message,
903
+ str(self.message),
904
904
  re.MULTILINE,
905
905
  )
906
906
  for author in results:
@@ -66,7 +66,7 @@ from git.types import Commit_ish, PathLike, TBD
66
66
  if TYPE_CHECKING:
67
67
  from git.index import IndexFile
68
68
  from git.objects.commit import Commit
69
- from git.refs import Head
69
+ from git.refs import Head, RemoteReference
70
70
  from git.repo import Repo
71
71
 
72
72
  # -----------------------------------------------------------------------------
@@ -352,10 +352,10 @@ class Submodule(IndexObject, TraversableIterableObj):
352
352
  module_abspath_dir = osp.dirname(module_abspath)
353
353
  if not osp.isdir(module_abspath_dir):
354
354
  os.makedirs(module_abspath_dir)
355
- module_checkout_path = osp.join(str(repo.working_tree_dir), path)
355
+ module_checkout_path = osp.join(repo.working_tree_dir, path) # type: ignore[arg-type]
356
356
 
357
357
  if url.startswith("../"):
358
- remote_name = repo.active_branch.tracking_branch().remote_name
358
+ remote_name = cast("RemoteReference", repo.active_branch.tracking_branch()).remote_name
359
359
  repo_remote_url = repo.remote(remote_name).url
360
360
  url = os.path.join(repo_remote_url, url)
361
361
 
@@ -541,7 +541,7 @@ class Submodule(IndexObject, TraversableIterableObj):
541
541
  if sm.exists():
542
542
  # Reretrieve submodule from tree.
543
543
  try:
544
- sm = repo.head.commit.tree[str(path)]
544
+ sm = repo.head.commit.tree[os.fspath(path)]
545
545
  sm._name = name
546
546
  return sm
547
547
  except KeyError:
@@ -5,6 +5,7 @@
5
5
 
6
6
  __all__ = ["TreeModifier", "Tree"]
7
7
 
8
+ import os
8
9
  import sys
9
10
 
10
11
  import git.diff as git_diff
@@ -230,7 +231,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
230
231
  raise TypeError("Unknown mode %o found in tree data for path '%s'" % (mode, path)) from e
231
232
  # END for each item
232
233
 
233
- def join(self, file: str) -> IndexObjUnion:
234
+ def join(self, file: PathLike) -> IndexObjUnion:
234
235
  """Find the named object in this tree's contents.
235
236
 
236
237
  :return:
@@ -241,6 +242,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
241
242
  If the given file or tree does not exist in this tree.
242
243
  """
243
244
  msg = "Blob or Tree named %r not found"
245
+ file = os.fspath(file)
244
246
  if "/" in file:
245
247
  tree = self
246
248
  item = self
@@ -269,7 +271,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
269
271
  raise KeyError(msg % file)
270
272
  # END handle long paths
271
273
 
272
- def __truediv__(self, file: str) -> IndexObjUnion:
274
+ def __truediv__(self, file: PathLike) -> IndexObjUnion:
273
275
  """The ``/`` operator is another syntax for joining.
274
276
 
275
277
  See :meth:`join` for details.
@@ -22,7 +22,6 @@ from typing import Any, Sequence, TYPE_CHECKING, Union
22
22
  from git.types import Commit_ish, PathLike
23
23
 
24
24
  if TYPE_CHECKING:
25
- from git.objects import Commit
26
25
  from git.refs import RemoteReference
27
26
  from git.repo import Repo
28
27
 
@@ -44,9 +43,6 @@ class HEAD(SymbolicReference):
44
43
 
45
44
  __slots__ = ()
46
45
 
47
- # TODO: This can be removed once SymbolicReference.commit has static type hints.
48
- commit: "Commit"
49
-
50
46
  def __init__(self, repo: "Repo", path: PathLike = _HEAD_NAME) -> None:
51
47
  if path != self._HEAD_NAME:
52
48
  raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
@@ -149,7 +145,7 @@ class Head(Reference):
149
145
  k_config_remote_ref = "merge" # Branch to merge from remote.
150
146
 
151
147
  @classmethod
152
- def delete(cls, repo: "Repo", *heads: "Union[Head, str]", force: bool = False, **kwargs: Any) -> None:
148
+ def delete(cls, repo: "Repo", *heads: "Union[Head, str]", force: bool = False, **kwargs: Any) -> None: # type: ignore[override]
153
149
  """Delete the given heads.
154
150
 
155
151
  :param force:
@@ -145,7 +145,7 @@ class RefLogEntry(Tuple[str, str, Actor, Tuple[int, int], str]):
145
145
  actor = Actor._from_string(info[82 : email_end + 1])
146
146
  time, tz_offset = parse_date(info[email_end + 2 :]) # skipcq: PYL-W0621
147
147
 
148
- return RefLogEntry((oldhexsha, newhexsha, actor, (time, tz_offset), msg))
148
+ return RefLogEntry((oldhexsha, newhexsha, actor, (time, tz_offset), msg)) # type: ignore [arg-type]
149
149
 
150
150
 
151
151
  class RefLog(List[RefLogEntry], Serializable):
@@ -3,6 +3,7 @@
3
3
 
4
4
  __all__ = ["Reference"]
5
5
 
6
+ import os
6
7
  from git.util import IterableObj, LazyMixin
7
8
 
8
9
  from .symbolic import SymbolicReference, T_References
@@ -65,7 +66,7 @@ class Reference(SymbolicReference, LazyMixin, IterableObj):
65
66
  If ``False``, you can provide any path.
66
67
  Otherwise the path must start with the default path prefix of this type.
67
68
  """
68
- if check_path and not str(path).startswith(self._common_path_default + "/"):
69
+ if check_path and not os.fspath(path).startswith(self._common_path_default + "/"):
69
70
  raise ValueError(f"Cannot instantiate {self.__class__.__name__!r} from path {path}")
70
71
  self.path: str # SymbolicReference converts to string at the moment.
71
72
  super().__init__(repo, path)
@@ -4,6 +4,7 @@
4
4
  __all__ = ["SymbolicReference"]
5
5
 
6
6
  import os
7
+ from pathlib import Path
7
8
 
8
9
  from gitdb.exc import BadName, BadObject
9
10
 
@@ -40,6 +41,7 @@ if TYPE_CHECKING:
40
41
  from git.config import GitConfigParser
41
42
  from git.objects.commit import Actor
42
43
  from git.refs.log import RefLogEntry
44
+ from git.refs.reference import Reference
43
45
  from git.repo import Repo
44
46
 
45
47
 
@@ -75,10 +77,10 @@ class SymbolicReference:
75
77
 
76
78
  def __init__(self, repo: "Repo", path: PathLike, check_path: bool = False) -> None:
77
79
  self.repo = repo
78
- self.path = path
80
+ self.path: PathLike = path
79
81
 
80
82
  def __str__(self) -> str:
81
- return str(self.path)
83
+ return os.fspath(self.path)
82
84
 
83
85
  def __repr__(self) -> str:
84
86
  return '<git.%s "%s">' % (self.__class__.__name__, self.path)
@@ -102,7 +104,7 @@ class SymbolicReference:
102
104
  In case of symbolic references, the shortest assumable name is the path
103
105
  itself.
104
106
  """
105
- return str(self.path)
107
+ return os.fspath(self.path)
106
108
 
107
109
  @property
108
110
  def abspath(self) -> PathLike:
@@ -177,7 +179,7 @@ class SymbolicReference:
177
179
  """
178
180
  previous: Union[str, None] = None
179
181
  one_before_previous: Union[str, None] = None
180
- for c in str(ref_path):
182
+ for c in os.fspath(ref_path):
181
183
  if c in " ~^:?*[\\":
182
184
  raise ValueError(
183
185
  f"Invalid reference '{ref_path}': references cannot contain spaces, tildes (~), carets (^),"
@@ -211,7 +213,7 @@ class SymbolicReference:
211
213
  raise ValueError(f"Invalid reference '{ref_path}': references cannot end with a forward slash (/)")
212
214
  elif previous == "@" and one_before_previous is None:
213
215
  raise ValueError(f"Invalid reference '{ref_path}': references cannot be '@'")
214
- elif any(component.endswith(".lock") for component in str(ref_path).split("/")):
216
+ elif any(component.endswith(".lock") for component in Path(ref_path).parts):
215
217
  raise ValueError(
216
218
  f"Invalid reference '{ref_path}': references cannot have slash-separated components that end with"
217
219
  " '.lock'"
@@ -234,7 +236,7 @@ class SymbolicReference:
234
236
  tokens: Union[None, List[str], Tuple[str, str]] = None
235
237
  repodir = _git_dir(repo, ref_path)
236
238
  try:
237
- with open(os.path.join(repodir, str(ref_path)), "rt", encoding="UTF-8") as fp:
239
+ with open(os.path.join(repodir, ref_path), "rt", encoding="UTF-8") as fp: # type: ignore[arg-type]
238
240
  value = fp.read().rstrip()
239
241
  # Don't only split on spaces, but on whitespace, which allows to parse lines like:
240
242
  # 60b64ef992065e2600bfef6187a97f92398a9144 branch 'master' of git-server:/path/to/repo
@@ -404,7 +406,7 @@ class SymbolicReference:
404
406
  def object(self, object: Union[AnyGitObject, "SymbolicReference", str]) -> "SymbolicReference":
405
407
  return self.set_object(object)
406
408
 
407
- def _get_reference(self) -> "SymbolicReference":
409
+ def _get_reference(self) -> "Reference":
408
410
  """
409
411
  :return:
410
412
  :class:`~git.refs.reference.Reference` object we point to
@@ -416,7 +418,7 @@ class SymbolicReference:
416
418
  sha, target_ref_path = self._get_ref_info(self.repo, self.path)
417
419
  if target_ref_path is None:
418
420
  raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, sha))
419
- return self.from_path(self.repo, target_ref_path)
421
+ return cast("Reference", self.from_path(self.repo, target_ref_path))
420
422
 
421
423
  def set_reference(
422
424
  self,
@@ -502,7 +504,7 @@ class SymbolicReference:
502
504
 
503
505
  # Aliased reference
504
506
  @property
505
- def reference(self) -> "SymbolicReference":
507
+ def reference(self) -> "Reference":
506
508
  return self._get_reference()
507
509
 
508
510
  @reference.setter
@@ -613,7 +615,7 @@ class SymbolicReference:
613
615
  full_ref_path = path
614
616
  if not cls._common_path_default:
615
617
  return full_ref_path
616
- if not str(path).startswith(cls._common_path_default + "/"):
618
+ if not os.fspath(path).startswith(cls._common_path_default + "/"):
617
619
  full_ref_path = "%s/%s" % (cls._common_path_default, path)
618
620
  return full_ref_path
619
621
 
@@ -705,7 +707,7 @@ class SymbolicReference:
705
707
  if not force and os.path.isfile(abs_ref_path):
706
708
  target_data = str(target)
707
709
  if isinstance(target, SymbolicReference):
708
- target_data = str(target.path)
710
+ target_data = os.fspath(target.path)
709
711
  if not resolve:
710
712
  target_data = "ref: " + target_data
711
713
  with open(abs_ref_path, "rb") as fd:
@@ -841,7 +843,7 @@ class SymbolicReference:
841
843
 
842
844
  # Read packed refs.
843
845
  for _sha, rela_path in cls._iter_packed_refs(repo):
844
- if rela_path.startswith(str(common_path)):
846
+ if rela_path.startswith(os.fspath(common_path)):
845
847
  rela_paths.add(rela_path)
846
848
  # END relative path matches common path
847
849
  # END packed refs reading
@@ -915,8 +917,7 @@ class SymbolicReference:
915
917
  SymbolicReference,
916
918
  ):
917
919
  try:
918
- instance: T_References
919
- instance = ref_type(repo, path)
920
+ instance = cast(T_References, ref_type(repo, path))
920
921
  if instance.__class__ is SymbolicReference and instance.is_detached:
921
922
  raise ValueError("SymbolicRef was detached, we drop it")
922
923
  else:
@@ -930,4 +931,4 @@ class SymbolicReference:
930
931
 
931
932
  def is_remote(self) -> bool:
932
933
  """:return: True if this symbolic reference points to a remote branch"""
933
- return str(self.path).startswith(self._remote_common_path_default + "/")
934
+ return os.fspath(self.path).startswith(self._remote_common_path_default + "/")
@@ -45,8 +45,8 @@ class TagReference(Reference):
45
45
  _common_default = "tags"
46
46
  _common_path_default = Reference._common_path_default + "/" + _common_default
47
47
 
48
- @property
49
- def commit(self) -> "Commit": # type: ignore[override] # LazyMixin has unrelated commit method
48
+ @property # type: ignore[misc]
49
+ def commit(self) -> "Commit": # LazyMixin has unrelated commit method
50
50
  """:return: Commit object the tag ref points to
51
51
 
52
52
  :raise ValueError:
@@ -80,8 +80,8 @@ class TagReference(Reference):
80
80
  return None
81
81
 
82
82
  # Make object read-only. It should be reasonably hard to adjust an existing tag.
83
- @property
84
- def object(self) -> AnyGitObject: # type: ignore[override]
83
+ @property # type: ignore[misc]
84
+ def object(self) -> AnyGitObject:
85
85
  return Reference._get_object(self)
86
86
 
87
87
  @classmethod
@@ -126,6 +126,7 @@ class Repo:
126
126
  working_dir: PathLike
127
127
  """The working directory of the git command."""
128
128
 
129
+ # stored as string for easier processing, but annotated as path for clearer intention
129
130
  _working_tree_dir: Optional[PathLike] = None
130
131
 
131
132
  git_dir: PathLike
@@ -215,15 +216,13 @@ class Repo:
215
216
  epath = path or os.getenv("GIT_DIR")
216
217
  if not epath:
217
218
  epath = os.getcwd()
219
+ epath = os.fspath(epath)
218
220
  if Git.is_cygwin():
219
221
  # Given how the tests are written, this seems more likely to catch Cygwin
220
222
  # git used from Windows than Windows git used from Cygwin. Therefore
221
223
  # changing to Cygwin-style paths is the relevant operation.
222
- epath = cygpath(str(epath))
224
+ epath = cygpath(epath)
223
225
 
224
- epath = epath or path or os.getcwd()
225
- if not isinstance(epath, str):
226
- epath = str(epath)
227
226
  if expand_vars and re.search(self.re_envvars, epath):
228
227
  warnings.warn(
229
228
  "The use of environment variables in paths is deprecated"
@@ -520,7 +519,7 @@ class Repo:
520
519
  """
521
520
  return RootModule(self).traverse(*args, **kwargs)
522
521
 
523
- def submodule_update(self, *args: Any, **kwargs: Any) -> Iterator[Submodule]:
522
+ def submodule_update(self, *args: Any, **kwargs: Any) -> RootModule:
524
523
  """Update the submodules, keeping the repository consistent as it will
525
524
  take the previous state into consideration.
526
525
 
@@ -684,11 +683,7 @@ class Repo:
684
683
  git_dir: Optional[PathLike] = None,
685
684
  ) -> GitConfigParser:
686
685
  if config_level is None:
687
- files = [
688
- self._get_config_path(cast(Lit_config_levels, f), git_dir)
689
- for f in self.config_level
690
- if cast(Lit_config_levels, f)
691
- ]
686
+ files = [self._get_config_path(f, git_dir) for f in self.config_level if f]
692
687
  else:
693
688
  files = [self._get_config_path(config_level, git_dir)]
694
689
  return GitConfigParser(files, read_only=True, repo=self)
@@ -961,7 +956,7 @@ class Repo:
961
956
  if not submodules:
962
957
  default_args.append("--ignore-submodules")
963
958
  if path:
964
- default_args.extend(["--", str(path)])
959
+ default_args.extend(["--", os.fspath(path)])
965
960
  if index:
966
961
  # diff index against HEAD.
967
962
  if osp.isfile(self.index.path) and len(self.git.diff("--cached", *default_args)):
@@ -1361,9 +1356,9 @@ class Repo:
1361
1356
  ) -> "Repo":
1362
1357
  odbt = kwargs.pop("odbt", odb_default_type)
1363
1358
 
1364
- # When pathlib.Path or other class-based path is passed
1365
- if not isinstance(path, str):
1366
- path = str(path)
1359
+ # url may be a path and this has no effect if it is a string
1360
+ url = os.fspath(url)
1361
+ path = os.fspath(path)
1367
1362
 
1368
1363
  ## A bug win cygwin's Git, when `--bare` or `--separate-git-dir`
1369
1364
  # it prepends the cwd or(?) the `url` into the `path, so::
@@ -1380,7 +1375,7 @@ class Repo:
1380
1375
  multi = shlex.split(" ".join(multi_options))
1381
1376
 
1382
1377
  if not allow_unsafe_protocols:
1383
- Git.check_unsafe_protocols(str(url))
1378
+ Git.check_unsafe_protocols(url)
1384
1379
  if not allow_unsafe_options:
1385
1380
  Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=cls.unsafe_git_clone_options)
1386
1381
  if not allow_unsafe_options and multi_options:
@@ -1389,7 +1384,7 @@ class Repo:
1389
1384
  proc = git.clone(
1390
1385
  multi,
1391
1386
  "--",
1392
- Git.polish_url(str(url)),
1387
+ Git.polish_url(url),
1393
1388
  clone_path,
1394
1389
  with_extended_output=True,
1395
1390
  as_process=True,
@@ -1484,7 +1479,7 @@ class Repo:
1484
1479
  self.common_dir,
1485
1480
  path,
1486
1481
  type(self.odb),
1487
- progress,
1482
+ progress, # type: ignore[arg-type]
1488
1483
  multi_options,
1489
1484
  allow_unsafe_protocols=allow_unsafe_protocols,
1490
1485
  allow_unsafe_options=allow_unsafe_options,
@@ -1545,7 +1540,7 @@ class Repo:
1545
1540
  url,
1546
1541
  to_path,
1547
1542
  GitCmdObjectDB,
1548
- progress,
1543
+ progress, # type: ignore[arg-type]
1549
1544
  multi_options,
1550
1545
  allow_unsafe_protocols=allow_unsafe_protocols,
1551
1546
  allow_unsafe_options=allow_unsafe_options,
@@ -286,7 +286,7 @@ def rev_parse(repo: "Repo", rev: str) -> AnyGitObject:
286
286
  # END handle refname
287
287
  else:
288
288
  if ref is not None:
289
- obj = cast("Commit", ref.commit)
289
+ obj = ref.commit
290
290
  # END handle ref
291
291
  # END initialize obj on first token
292
292
 
@@ -13,7 +13,6 @@ from typing import (
13
13
  Sequence as Sequence,
14
14
  Tuple,
15
15
  TYPE_CHECKING,
16
- Type,
17
16
  TypeVar,
18
17
  Union,
19
18
  )
@@ -130,7 +129,8 @@ See :manpage:`gitglossary(7)` on "object type":
130
129
  https://git-scm.com/docs/gitglossary#def_object_type
131
130
  """
132
131
 
133
- Lit_commit_ish: Type[Literal["commit", "tag"]]
132
+ if TYPE_CHECKING:
133
+ Lit_commit_ish = Literal["commit", "tag"]
134
134
  """Deprecated. Type of literal strings identifying typically-commitish git object types.
135
135
 
136
136
  Prior to a bugfix, this type had been defined more broadly. Any usage is in practice
@@ -36,7 +36,7 @@ import getpass
36
36
  import logging
37
37
  import os
38
38
  import os.path as osp
39
- import pathlib
39
+ from pathlib import Path
40
40
  import platform
41
41
  import re
42
42
  import shutil
@@ -272,9 +272,9 @@ def stream_copy(source: BinaryIO, destination: BinaryIO, chunk_size: int = 512 *
272
272
  def join_path(a: PathLike, *p: PathLike) -> PathLike:
273
273
  R"""Join path tokens together similar to osp.join, but always use ``/`` instead of
274
274
  possibly ``\`` on Windows."""
275
- path = str(a)
275
+ path = os.fspath(a)
276
276
  for b in p:
277
- b = str(b)
277
+ b = os.fspath(b)
278
278
  if not b:
279
279
  continue
280
280
  if b.startswith("/"):
@@ -290,18 +290,18 @@ def join_path(a: PathLike, *p: PathLike) -> PathLike:
290
290
  if sys.platform == "win32":
291
291
 
292
292
  def to_native_path_windows(path: PathLike) -> PathLike:
293
- path = str(path)
293
+ path = os.fspath(path)
294
294
  return path.replace("/", "\\")
295
295
 
296
296
  def to_native_path_linux(path: PathLike) -> str:
297
- path = str(path)
297
+ path = os.fspath(path)
298
298
  return path.replace("\\", "/")
299
299
 
300
300
  to_native_path = to_native_path_windows
301
301
  else:
302
302
  # No need for any work on Linux.
303
303
  def to_native_path_linux(path: PathLike) -> str:
304
- return str(path)
304
+ return os.fspath(path)
305
305
 
306
306
  to_native_path = to_native_path_linux
307
307
 
@@ -372,7 +372,7 @@ def py_where(program: str, path: Optional[PathLike] = None) -> List[str]:
372
372
  progs = []
373
373
  if not path:
374
374
  path = os.environ["PATH"]
375
- for folder in str(path).split(os.pathsep):
375
+ for folder in os.fspath(path).split(os.pathsep):
376
376
  folder = folder.strip('"')
377
377
  if folder:
378
378
  exe_path = osp.join(folder, program)
@@ -397,7 +397,7 @@ def _cygexpath(drive: Optional[str], path: str) -> str:
397
397
  p = cygpath(p)
398
398
  elif drive:
399
399
  p = "/proc/cygdrive/%s/%s" % (drive.lower(), p)
400
- p_str = str(p) # ensure it is a str and not AnyPath
400
+ p_str = os.fspath(p) # ensure it is a str and not AnyPath
401
401
  return p_str.replace("\\", "/")
402
402
 
403
403
 
@@ -418,7 +418,7 @@ _cygpath_parsers: Tuple[Tuple[Pattern[str], Callable, bool], ...] = (
418
418
 
419
419
  def cygpath(path: str) -> str:
420
420
  """Use :meth:`git.cmd.Git.polish_url` instead, that works on any environment."""
421
- path = str(path) # Ensure is str and not AnyPath.
421
+ path = os.fspath(path) # Ensure is str and not AnyPath.
422
422
  # Fix to use Paths when 3.5 dropped. Or to be just str if only for URLs?
423
423
  if not path.startswith(("/cygdrive", "//", "/proc/cygdrive")):
424
424
  for regex, parser, recurse in _cygpath_parsers:
@@ -438,7 +438,7 @@ _decygpath_regex = re.compile(r"(?:/proc)?/cygdrive/(\w)(/.*)?")
438
438
 
439
439
 
440
440
  def decygpath(path: PathLike) -> str:
441
- path = str(path)
441
+ path = os.fspath(path)
442
442
  m = _decygpath_regex.match(path)
443
443
  if m:
444
444
  drive, rest_path = m.groups()
@@ -465,7 +465,7 @@ def _is_cygwin_git(git_executable: str) -> bool:
465
465
  # Just a name given, not a real path.
466
466
  uname_cmd = osp.join(git_dir, "uname")
467
467
 
468
- if not (pathlib.Path(uname_cmd).is_file() and os.access(uname_cmd, os.X_OK)):
468
+ if not (Path(uname_cmd).is_file() and os.access(uname_cmd, os.X_OK)):
469
469
  _logger.debug(f"Failed checking if running in CYGWIN: {uname_cmd} is not an executable")
470
470
  _is_cygwin_cache[git_executable] = is_cygwin
471
471
  return is_cygwin
@@ -523,7 +523,7 @@ def expand_path(p: PathLike, expand_vars: bool = ...) -> str:
523
523
 
524
524
 
525
525
  def expand_path(p: Union[None, PathLike], expand_vars: bool = True) -> Optional[PathLike]:
526
- if isinstance(p, pathlib.Path):
526
+ if isinstance(p, Path):
527
527
  return p.resolve()
528
528
  try:
529
529
  p = osp.expanduser(p) # type: ignore[arg-type]
@@ -1143,7 +1143,7 @@ class BlockingLockFile(LockFile):
1143
1143
  # END endless loop
1144
1144
 
1145
1145
 
1146
- class IterableList(List[T_IterableObj]):
1146
+ class IterableList(List[T_IterableObj]): # type: ignore[type-var]
1147
1147
  """List of iterable objects allowing to query an object by id or by named index::
1148
1148
 
1149
1149
  heads = repo.heads
@@ -1214,14 +1214,14 @@ class IterableList(List[T_IterableObj]):
1214
1214
  raise ValueError("Index should be an int or str")
1215
1215
  else:
1216
1216
  try:
1217
- return getattr(self, index)
1217
+ return getattr(self, cast(str, index))
1218
1218
  except AttributeError as e:
1219
- raise IndexError("No item found with id %r" % (self._prefix + index)) from e
1219
+ raise IndexError(f"No item found with id {self._prefix}{index}") from e
1220
1220
  # END handle getattr
1221
1221
 
1222
1222
  def __delitem__(self, index: Union[SupportsIndex, int, slice, str]) -> None:
1223
1223
  delindex = cast(int, index)
1224
- if not isinstance(index, int):
1224
+ if isinstance(index, str):
1225
1225
  delindex = -1
1226
1226
  name = self._prefix + index
1227
1227
  for i, item in enumerate(self):
@@ -19,7 +19,6 @@ testpaths = "test" # Space separated list of paths from root e.g test tests doc
19
19
  # filterwarnings ignore::WarningType # ignores those warnings
20
20
 
21
21
  [tool.mypy]
22
- python_version = "3.8"
23
22
  files = ["git/", "test/deprecation/"]
24
23
  disallow_untyped_defs = true
25
24
  no_implicit_optional = true
@@ -1,7 +1,7 @@
1
1
  coverage[toml]
2
2
  ddt >= 1.1.1, != 1.4.3
3
3
  mock ; python_version < "3.8"
4
- mypy
4
+ mypy==1.18.2 ; python_version >= "3.9" # pin mypy version to avoid new errors
5
5
  pre-commit
6
6
  pytest >= 7.3.1
7
7
  pytest-cov
gitpython-3.1.45/VERSION DELETED
@@ -1 +0,0 @@
1
- 3.1.45
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes