scmrepo 2.0.4__tar.gz → 2.1.1__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.

Potentially problematic release.


This version of scmrepo might be problematic. Click here for more details.

Files changed (69) hide show
  1. {scmrepo-2.0.4 → scmrepo-2.1.1}/.github/workflows/tests.yaml +1 -1
  2. {scmrepo-2.0.4 → scmrepo-2.1.1}/CONTRIBUTING.rst +1 -1
  3. {scmrepo-2.0.4/src/scmrepo.egg-info → scmrepo-2.1.1}/PKG-INFO +5 -5
  4. {scmrepo-2.0.4 → scmrepo-2.1.1}/noxfile.py +1 -1
  5. {scmrepo-2.0.4 → scmrepo-2.1.1}/pyproject.toml +4 -4
  6. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/asyn.py +3 -3
  7. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/fs.py +4 -4
  8. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/__init__.py +7 -11
  9. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/base.py +4 -3
  10. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/dulwich/__init__.py +17 -22
  11. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/dulwich/asyncssh_vendor.py +6 -10
  12. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/dulwich/client.py +5 -4
  13. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/gitpython.py +7 -11
  14. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/pygit2/__init__.py +22 -28
  15. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/pygit2/callbacks.py +11 -6
  16. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/pygit2/filter.py +2 -2
  17. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/config.py +4 -4
  18. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/credentials.py +9 -12
  19. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/client.py +30 -38
  20. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/fetch.py +9 -8
  21. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/object.py +2 -2
  22. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/pointer.py +2 -2
  23. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/progress.py +2 -2
  24. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/storage.py +2 -1
  25. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/objects.py +3 -2
  26. {scmrepo-2.0.4 → scmrepo-2.1.1/src/scmrepo.egg-info}/PKG-INFO +5 -5
  27. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo.egg-info/requires.txt +2 -2
  28. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/conftest.py +5 -4
  29. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_dulwich.py +5 -5
  30. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_git.py +5 -5
  31. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_scmrepo.py +1 -2
  32. {scmrepo-2.0.4 → scmrepo-2.1.1}/.coveragerc +0 -0
  33. {scmrepo-2.0.4 → scmrepo-2.1.1}/.cruft.json +0 -0
  34. {scmrepo-2.0.4 → scmrepo-2.1.1}/.gitattributes +0 -0
  35. {scmrepo-2.0.4 → scmrepo-2.1.1}/.github/dependabot.yml +0 -0
  36. {scmrepo-2.0.4 → scmrepo-2.1.1}/.github/workflows/release.yaml +0 -0
  37. {scmrepo-2.0.4 → scmrepo-2.1.1}/.github/workflows/update-template.yaml +0 -0
  38. {scmrepo-2.0.4 → scmrepo-2.1.1}/.gitignore +0 -0
  39. {scmrepo-2.0.4 → scmrepo-2.1.1}/.pre-commit-config.yaml +0 -0
  40. {scmrepo-2.0.4 → scmrepo-2.1.1}/CODE_OF_CONDUCT.rst +0 -0
  41. {scmrepo-2.0.4 → scmrepo-2.1.1}/LICENSE +0 -0
  42. {scmrepo-2.0.4 → scmrepo-2.1.1}/README.rst +0 -0
  43. {scmrepo-2.0.4 → scmrepo-2.1.1}/setup.cfg +0 -0
  44. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/__init__.py +0 -0
  45. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/base.py +0 -0
  46. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/exceptions.py +0 -0
  47. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/backend/__init__.py +0 -0
  48. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/__init__.py +0 -0
  49. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/exceptions.py +0 -0
  50. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/lfs/smudge.py +0 -0
  51. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/git/stash.py +0 -0
  52. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/noscm.py +0 -0
  53. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/progress.py +0 -0
  54. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/py.typed +0 -0
  55. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo/utils.py +0 -0
  56. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo.egg-info/SOURCES.txt +0 -0
  57. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo.egg-info/dependency_links.txt +0 -0
  58. {scmrepo-2.0.4 → scmrepo-2.1.1}/src/scmrepo.egg-info/top_level.txt +0 -0
  59. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/__init__.py +0 -0
  60. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/docker-compose.yml +0 -0
  61. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/git-init/git.sh +0 -0
  62. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_credentials.py +0 -0
  63. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_fs.py +0 -0
  64. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_lfs.py +0 -0
  65. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_noscm.py +0 -0
  66. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_pygit2.py +0 -0
  67. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/test_stash.py +0 -0
  68. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/user.key +0 -0
  69. {scmrepo-2.0.4 → scmrepo-2.1.1}/tests/user.key.pub +0 -0
@@ -21,7 +21,7 @@ jobs:
21
21
  fail-fast: false
22
22
  matrix:
23
23
  os: [ubuntu-20.04, windows-latest, macos-latest]
24
- pyv: ['3.8', '3.9', '3.10', '3.11']
24
+ pyv: ['3.9', '3.10', '3.11', '3.12']
25
25
 
26
26
  steps:
27
27
  - name: Check out the repository
@@ -41,7 +41,7 @@ Request features on the `Issue Tracker`_.
41
41
  How to set up your development environment
42
42
  ------------------------------------------
43
43
 
44
- You need Python 3.8+ and the following tools:
44
+ You need Python 3.9+ and the following tools:
45
45
 
46
46
  - Nox_
47
47
 
@@ -1,23 +1,23 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scmrepo
3
- Version: 2.0.4
3
+ Version: 2.1.1
4
4
  Summary: scmrepo
5
5
  Author-email: Iterative <support@dvc.org>
6
6
  License: Apache-2.0
7
7
  Project-URL: Issues, https://github.com/iterative/scmrepo/issues
8
8
  Project-URL: Source, https://github.com/iterative/scmrepo
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.8
11
10
  Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Development Status :: 4 - Beta
15
- Requires-Python: >=3.8
15
+ Requires-Python: >=3.9
16
16
  Description-Content-Type: text/x-rst
17
17
  License-File: LICENSE
18
18
  Requires-Dist: gitpython>3
19
19
  Requires-Dist: dulwich>=0.21.6
20
- Requires-Dist: pygit2>=1.13.3
20
+ Requires-Dist: pygit2>=1.14.0
21
21
  Requires-Dist: pygtrie>=2.3.2
22
22
  Requires-Dist: fsspec>=2021.7.0
23
23
  Requires-Dist: pathspec>=0.9.0
@@ -34,7 +34,7 @@ Requires-Dist: pytest-mock==3.8.2; extra == "tests"
34
34
  Requires-Dist: mypy==0.971; extra == "tests"
35
35
  Requires-Dist: pytest-test-utils==0.0.8; extra == "tests"
36
36
  Requires-Dist: pytest-asyncio==0.18.3; extra == "tests"
37
- Requires-Dist: pytest-docker==0.12.0; (python_version < "3.10" and implementation_name != "pypy") and extra == "tests"
37
+ Requires-Dist: pytest-docker==2.2.0; (python_version < "3.10" and implementation_name != "pypy") and extra == "tests"
38
38
  Requires-Dist: mock==5.1.0; extra == "tests"
39
39
  Requires-Dist: paramiko==3.3.1; extra == "tests"
40
40
  Requires-Dist: types-certifi==2021.10.8.3; extra == "tests"
@@ -9,7 +9,7 @@ nox.options.sessions = "lint", "tests"
9
9
  locations = "src", "tests"
10
10
 
11
11
 
12
- @nox.session(python=["3.8", "3.9", "3.10", "3.11"])
12
+ @nox.session(python=["3.9", "3.10", "3.11", "3.12"])
13
13
  def tests(session: nox.Session) -> None:
14
14
  session.install(".[tests]")
15
15
  session.run(
@@ -12,18 +12,18 @@ license = {text = "Apache-2.0"}
12
12
  authors = [{ name = "Iterative", email = "support@dvc.org" }]
13
13
  classifiers = [
14
14
  "Programming Language :: Python :: 3",
15
- "Programming Language :: Python :: 3.8",
16
15
  "Programming Language :: Python :: 3.9",
17
16
  "Programming Language :: Python :: 3.10",
18
17
  "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
19
  "Development Status :: 4 - Beta",
20
20
  ]
21
- requires-python = ">=3.8"
21
+ requires-python = ">=3.9"
22
22
  dynamic = ["version"]
23
23
  dependencies = [
24
24
  "gitpython>3",
25
25
  "dulwich>=0.21.6",
26
- "pygit2>=1.13.3",
26
+ "pygit2>=1.14.0",
27
27
  "pygtrie>=2.3.2",
28
28
  "fsspec>=2021.7.0",
29
29
  "pathspec>=0.9.0",
@@ -48,7 +48,7 @@ tests = [
48
48
  "pytest-test-utils==0.0.8",
49
49
  "pytest-asyncio==0.18.3",
50
50
  # https://github.com/docker/docker-py/issues/2902
51
- "pytest-docker==0.12.0; python_version < '3.10' and implementation_name != 'pypy'",
51
+ "pytest-docker==2.2.0; python_version < '3.10' and implementation_name != 'pypy'",
52
52
  "mock==5.1.0",
53
53
  "paramiko==3.3.1",
54
54
  "types-certifi==2021.10.8.3",
@@ -2,7 +2,7 @@
2
2
  import asyncio
3
3
  import os
4
4
  import threading
5
- from typing import Any, List, Optional
5
+ from typing import Any, Optional
6
6
 
7
7
  from fsspec.asyn import ( # noqa: F401, pylint:disable=unused-import
8
8
  _selector_policy,
@@ -11,9 +11,9 @@ from fsspec.asyn import ( # noqa: F401, pylint:disable=unused-import
11
11
  )
12
12
 
13
13
  # dedicated async IO thread
14
- iothread: List[Optional[threading.Thread]] = [None]
14
+ iothread: list[Optional[threading.Thread]] = [None]
15
15
  # global DVC event loop
16
- default_loop: List[Optional[asyncio.AbstractEventLoop]] = [None]
16
+ default_loop: list[Optional[asyncio.AbstractEventLoop]] = [None]
17
17
  lock = threading.Lock()
18
18
 
19
19
 
@@ -1,7 +1,7 @@
1
1
  import errno
2
2
  import os
3
3
  import posixpath
4
- from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Dict, Optional, Tuple
4
+ from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Optional
5
5
 
6
6
  from fsspec.callbacks import _DEFAULT_CALLBACK
7
7
  from fsspec.spec import AbstractFileSystem
@@ -169,7 +169,7 @@ class GitFileSystem(AbstractFileSystem):
169
169
  def as_posix(cls, path):
170
170
  return path
171
171
 
172
- def _get_key(self, path: str) -> Tuple[str, ...]:
172
+ def _get_key(self, path: str) -> tuple[str, ...]:
173
173
  path = self.abspath(path)
174
174
  if path == self.root_marker:
175
175
  return ()
@@ -184,7 +184,7 @@ class GitFileSystem(AbstractFileSystem):
184
184
  mode: str = "rb",
185
185
  block_size: Optional[int] = None,
186
186
  autocommit: bool = True,
187
- cache_options: Optional[Dict] = None,
187
+ cache_options: Optional[dict] = None,
188
188
  raw: bool = False,
189
189
  **kwargs: Any,
190
190
  ) -> BinaryIO:
@@ -204,7 +204,7 @@ class GitFileSystem(AbstractFileSystem):
204
204
  errno.EISDIR, os.strerror(errno.EISDIR), path
205
205
  ) from exc
206
206
 
207
- def info(self, path: str, **kwargs: Any) -> Dict[str, Any]:
207
+ def info(self, path: str, **kwargs: Any) -> dict[str, Any]:
208
208
  key = self._get_key(path)
209
209
  try:
210
210
  # NOTE: to avoid wasting time computing object size, trie.info
@@ -5,18 +5,14 @@ import os
5
5
  import re
6
6
  import typing
7
7
  from collections import OrderedDict
8
- from collections.abc import Mapping
8
+ from collections.abc import Iterable, Mapping
9
9
  from contextlib import contextmanager
10
10
  from functools import partialmethod
11
11
  from typing import (
12
12
  TYPE_CHECKING,
13
13
  Callable,
14
14
  ClassVar,
15
- Dict,
16
- Iterable,
17
15
  Optional,
18
- Tuple,
19
- Type,
20
16
  Union,
21
17
  )
22
18
 
@@ -44,14 +40,14 @@ if TYPE_CHECKING:
44
40
 
45
41
  logger = logging.getLogger(__name__)
46
42
 
47
- BackendCls = Type[BaseGitBackend]
43
+ BackendCls = type[BaseGitBackend]
48
44
 
49
45
 
50
46
  _LOW_PRIO_BACKENDS = ("gitpython",)
51
47
 
52
48
 
53
49
  class GitBackends(Mapping):
54
- DEFAULT: ClassVar[Dict[str, BackendCls]] = {
50
+ DEFAULT: ClassVar[dict[str, BackendCls]] = {
55
51
  "dulwich": DulwichBackend,
56
52
  "pygit2": Pygit2Backend,
57
53
  "gitpython": GitPythonBackend,
@@ -72,7 +68,7 @@ class GitBackends(Mapping):
72
68
  selected = selected or list(self.DEFAULT)
73
69
  self.backends = OrderedDict((key, self.DEFAULT[key]) for key in selected)
74
70
 
75
- self.initialized: Dict[str, BaseGitBackend] = {}
71
+ self.initialized: dict[str, BaseGitBackend] = {}
76
72
 
77
73
  self.args = args
78
74
  self.kwargs = kwargs
@@ -169,7 +165,7 @@ class Git(Base):
169
165
  return rev and cls.RE_HEXSHA.search(rev)
170
166
 
171
167
  @classmethod
172
- def split_ref_pattern(cls, ref: str) -> Tuple[str, str]:
168
+ def split_ref_pattern(cls, ref: str) -> tuple[str, str]:
173
169
  name = cls.BAD_REF_CHARS_RE.split(ref, maxsplit=1)[0]
174
170
  return name, ref[len(name) :]
175
171
 
@@ -492,8 +488,8 @@ class Git(Base):
492
488
  base: Optional[str] = None,
493
489
  match: Optional[str] = None,
494
490
  exclude: Optional[str] = None,
495
- ) -> Dict[str, Optional[str]]:
496
- results: Dict[str, Optional[str]] = {}
491
+ ) -> dict[str, Optional[str]]:
492
+ results: dict[str, Optional[str]] = {}
497
493
  remained_revs = set()
498
494
  if base == "refs/heads":
499
495
  current_rev = self.get_rev()
@@ -1,7 +1,8 @@
1
1
  import os
2
2
  from abc import ABC, abstractmethod
3
+ from collections.abc import Iterable, Mapping
3
4
  from enum import Enum
4
- from typing import TYPE_CHECKING, Callable, Iterable, Mapping, Optional, Tuple, Union
5
+ from typing import TYPE_CHECKING, Callable, Optional, Union
5
6
 
6
7
  from scmrepo.exceptions import SCMError
7
8
  from scmrepo.git.objects import GitObject
@@ -281,7 +282,7 @@ class BaseGitBackend(ABC):
281
282
  ref: str,
282
283
  message: Optional[str] = None,
283
284
  include_untracked: bool = False,
284
- ) -> Tuple[Optional[str], bool]:
285
+ ) -> tuple[Optional[str], bool]:
285
286
  """Push a commit onto the specified stash.
286
287
 
287
288
  Returns a tuple of the form (rev, need_reset) where need_reset
@@ -347,7 +348,7 @@ class BaseGitBackend(ABC):
347
348
  @abstractmethod
348
349
  def status(
349
350
  self, ignored: bool = False, untracked_files: str = "all"
350
- ) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
351
+ ) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
351
352
  """Return tuple of (staged_files, unstaged_files, untracked_files).
352
353
 
353
354
  staged_files will be a dict mapping status (add, delete, modify) to a
@@ -4,6 +4,7 @@ import logging
4
4
  import os
5
5
  import re
6
6
  import stat
7
+ from collections.abc import Iterable, Iterator, Mapping
7
8
  from contextlib import closing
8
9
  from functools import partial
9
10
  from io import BytesIO, StringIO
@@ -11,13 +12,7 @@ from typing import (
11
12
  TYPE_CHECKING,
12
13
  Any,
13
14
  Callable,
14
- Dict,
15
- Iterable,
16
- Iterator,
17
- List,
18
- Mapping,
19
15
  Optional,
20
- Tuple,
21
16
  Union,
22
17
  )
23
18
 
@@ -151,18 +146,18 @@ class DulwichConfig(Config):
151
146
  return self._config.encoding
152
147
  return self._config.backends[0].encoding
153
148
 
154
- def get(self, section: Tuple[str, ...], name: str) -> str:
149
+ def get(self, section: tuple[str, ...], name: str) -> str:
155
150
  """Return the specified setting as a string."""
156
151
  return self._config.get(section, name).decode(self.encoding)
157
152
 
158
- def get_bool(self, section: Tuple[str, ...], name: str) -> bool:
153
+ def get_bool(self, section: tuple[str, ...], name: str) -> bool:
159
154
  """Return the specified setting as a boolean."""
160
155
  value = self._config.get_boolean(section, name)
161
156
  if value is None:
162
157
  raise ValueError("setting is not a valid boolean")
163
158
  return value
164
159
 
165
- def get_multivar(self, section: Tuple[str, ...], name: str) -> Iterator[str]:
160
+ def get_multivar(self, section: tuple[str, ...], name: str) -> Iterator[str]:
166
161
  """Iterate over string values in the specified multivar setting."""
167
162
  for value in self._config.get_multivar(section, name):
168
163
  yield value.decode(self.encoding)
@@ -199,17 +194,17 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
199
194
  except NotGitRepository as exc:
200
195
  raise SCMError(f"{root_dir} is not a git repository") from exc
201
196
 
202
- self._submodules: Dict[str, str] = self._find_submodules()
197
+ self._submodules: dict[str, str] = self._find_submodules()
203
198
  self._stashes: dict = {}
204
199
 
205
- def _find_submodules(self) -> Dict[str, str]:
200
+ def _find_submodules(self) -> dict[str, str]:
206
201
  """Return dict mapping submodule names to submodule paths.
207
202
 
208
203
  Submodule paths will be relative to Git repo root.
209
204
  """
210
205
  from dulwich.config import ConfigFile, parse_submodules
211
206
 
212
- submodules: Dict[str, str] = {}
207
+ submodules: dict[str, str] = {}
213
208
  config_path = os.path.join(self.root_dir, ".gitmodules")
214
209
  if os.path.isfile(config_path):
215
210
  config = ConfigFile.from_path(config_path)
@@ -332,7 +327,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
332
327
  self.repo.stage(list(self.repo.open_index()))
333
328
  return
334
329
 
335
- files: List[bytes] = [
330
+ files: list[bytes] = [
336
331
  os.fsencode(fpath) for fpath in self._expand_paths(paths, force=force)
337
332
  ]
338
333
  if update:
@@ -348,7 +343,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
348
343
  else:
349
344
  self.repo.stage(files)
350
345
 
351
- def _expand_paths(self, paths: List[str], force: bool = False) -> Iterator[str]:
346
+ def _expand_paths(self, paths: list[str], force: bool = False) -> Iterator[str]:
352
347
  for path in paths:
353
348
  if not os.path.isabs(path) and self._submodules:
354
349
  # NOTE: If path is inside a submodule, Dulwich expects the
@@ -459,7 +454,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
459
454
  return any(p == rel or p.startswith(rel_dir) for p in self.repo.open_index())
460
455
 
461
456
  def is_dirty(self, untracked_files: bool = False) -> bool:
462
- kwargs: Dict[str, Any] = {} if untracked_files else {"untracked_files": "no"}
457
+ kwargs: dict[str, Any] = {} if untracked_files else {"untracked_files": "no"}
463
458
  return any(self.status(**kwargs))
464
459
 
465
460
  def active_branch(self) -> str:
@@ -707,9 +702,9 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
707
702
  fetch_refs = []
708
703
 
709
704
  def determine_wants(
710
- remote_refs: Dict[bytes, bytes],
705
+ remote_refs: dict[bytes, bytes],
711
706
  depth: Optional[int] = None, # pylint: disable=unused-argument
712
- ) -> List[bytes]:
707
+ ) -> list[bytes]:
713
708
  fetch_refs.extend(
714
709
  parse_reftuples(
715
710
  DictRefsContainer(remote_refs),
@@ -782,7 +777,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
782
777
  ref: str,
783
778
  message: Optional[str] = None,
784
779
  include_untracked: bool = False,
785
- ) -> Tuple[Optional[str], bool]:
780
+ ) -> tuple[Optional[str], bool]:
786
781
  from dulwich.repo import InvalidUserIdentity
787
782
 
788
783
  from scmrepo.git import Stash
@@ -836,8 +831,8 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
836
831
  ) -> Mapping[str, Optional[str]]:
837
832
  if not base:
838
833
  base = "refs/tags"
839
- rev_mapping: Dict[str, Optional[str]] = {}
840
- results: Dict[str, Optional[str]] = {}
834
+ rev_mapping: dict[str, Optional[str]] = {}
835
+ results: dict[str, Optional[str]] = {}
841
836
  for ref in self.iter_refs(base=base):
842
837
  if (match and not fnmatch.fnmatch(ref, match)) or (
843
838
  exclude and fnmatch.fnmatch(ref, exclude)
@@ -877,7 +872,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
877
872
 
878
873
  def status(
879
874
  self, ignored: bool = False, untracked_files: str = "all"
880
- ) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
875
+ ) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
881
876
  from dulwich.porcelain import Error
882
877
  from dulwich.porcelain import status as git_status
883
878
 
@@ -978,7 +973,7 @@ class DulwichBackend(BaseGitBackend): # pylint:disable=abstract-method
978
973
  _IDENTITY_RE = re.compile(r"(?P<name>.+)\s+<(?P<email>.+)>")
979
974
 
980
975
 
981
- def _parse_identity(identity: str) -> Tuple[str, str]:
976
+ def _parse_identity(identity: str) -> tuple[str, str]:
982
977
  m = _IDENTITY_RE.match(identity)
983
978
  if not m:
984
979
  raise SCMError("Could not parse tagger identity '{identity}'")
@@ -1,15 +1,11 @@
1
1
  """asyncssh SSH vendor for Dulwich."""
2
2
  import asyncio
3
3
  import os
4
+ from collections.abc import Coroutine, Iterator, Sequence
4
5
  from typing import (
5
6
  TYPE_CHECKING,
6
7
  Callable,
7
- Coroutine,
8
- Dict,
9
- Iterator,
10
- List,
11
8
  Optional,
12
- Sequence,
13
9
  cast,
14
10
  )
15
11
 
@@ -47,7 +43,7 @@ class _StderrWrapper:
47
43
  self.stderr = stderr
48
44
  self.loop = loop
49
45
 
50
- async def _readlines(self) -> List[bytes]:
46
+ async def _readlines(self) -> list[bytes]:
51
47
  lines = []
52
48
  while True:
53
49
  line = await self.stderr.readline()
@@ -140,12 +136,12 @@ def _process_public_key_ok_gh(self, _pkttype, _pktid, packet):
140
136
 
141
137
  class InteractiveSSHClient(SSHClient):
142
138
  _conn: Optional["SSHClientConnection"] = None
143
- _keys_to_try: Optional[List["FilePath"]] = None
144
- _passphrases: Dict[str, str]
139
+ _keys_to_try: Optional[list["FilePath"]] = None
140
+ _passphrases: dict[str, str]
145
141
 
146
142
  def __init__(self, *args, **kwargs):
147
143
  super(*args, **kwargs)
148
- _passphrases: Dict[str, str] = {}
144
+ _passphrases: dict[str, str] = {}
149
145
 
150
146
  def connection_made(self, conn: "SSHClientConnection") -> None:
151
147
  self._conn = conn
@@ -267,7 +263,7 @@ class AsyncSSHVendor(BaseAsyncObject, SSHVendor):
267
263
  async def _run_command(
268
264
  self,
269
265
  host: str,
270
- command: List[str],
266
+ command: list[str],
271
267
  username: Optional[str] = None,
272
268
  port: Optional[int] = None,
273
269
  password: Optional[str] = None,
@@ -1,4 +1,5 @@
1
- from typing import Dict, Iterator, List, Optional, Union
1
+ from collections.abc import Iterator
2
+ from typing import Optional, Union
2
3
 
3
4
  from dulwich.client import HTTPUnauthorized, Urllib3HttpGitClient
4
5
 
@@ -26,10 +27,10 @@ class GitCredentialsHTTPClient(Urllib3HttpGitClient): # pylint: disable=abstrac
26
27
  def _http_request(
27
28
  self,
28
29
  url: str,
29
- headers: Optional[Dict[str, str]] = None,
30
+ headers: Optional[dict[str, str]] = None,
30
31
  data: Optional[Union[bytes, Iterator[bytes]]] = None,
31
32
  ):
32
- cached_chunks: List[bytes] = []
33
+ cached_chunks: list[bytes] = []
33
34
 
34
35
  def _cached_data() -> Iterator[bytes]:
35
36
  assert data is not None
@@ -64,7 +65,7 @@ class GitCredentialsHTTPClient(Urllib3HttpGitClient): # pylint: disable=abstrac
64
65
  self._store_credentials.approve()
65
66
  return result
66
67
 
67
- def _get_auth(self) -> Dict[str, str]:
68
+ def _get_auth(self) -> dict[str, str]:
68
69
  from urllib3.util import make_headers
69
70
 
70
71
  try:
@@ -4,17 +4,13 @@ import logging
4
4
  import os
5
5
  import re
6
6
  import sys
7
+ from collections.abc import Iterable, Mapping
7
8
  from functools import partial, wraps
8
9
  from typing import (
9
10
  TYPE_CHECKING,
10
11
  Any,
11
12
  Callable,
12
- Dict,
13
- Iterable,
14
- List,
15
- Mapping,
16
13
  Optional,
17
- Tuple,
18
14
  Union,
19
15
  )
20
16
 
@@ -63,7 +59,7 @@ def is_binary() -> bool:
63
59
  return getattr(sys, "frozen", False)
64
60
 
65
61
 
66
- def fix_env(env: Optional[Dict[str, str]] = None) -> Dict[str, str]:
62
+ def fix_env(env: Optional[dict[str, str]] = None) -> dict[str, str]:
67
63
  if env is None:
68
64
  environ = os.environ.copy()
69
65
  else:
@@ -257,7 +253,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
257
253
  if update or not force:
258
254
  # NOTE: git-python index.add() defines force parameter but
259
255
  # ignores it (index.add() behavior is always force=True)
260
- kwargs: Dict[str, Any] = {}
256
+ kwargs: dict[str, Any] = {}
261
257
  if update:
262
258
  kwargs["update"] = True
263
259
  if isinstance(paths, str):
@@ -573,7 +569,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
573
569
  ref: str,
574
570
  message: Optional[str] = None,
575
571
  include_untracked: bool = False,
576
- ) -> Tuple[Optional[str], bool]:
572
+ ) -> tuple[Optional[str], bool]:
577
573
  from scmrepo.git import Stash
578
574
 
579
575
  if not self.is_dirty(untracked_files=include_untracked):
@@ -651,7 +647,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
651
647
 
652
648
  def reset(self, hard: bool = False, paths: Optional[Iterable[str]] = None):
653
649
  if paths:
654
- paths_list: Optional[List[str]] = [
650
+ paths_list: Optional[list[str]] = [
655
651
  relpath(path, self.root_dir) for path in paths
656
652
  ]
657
653
  if os.name == "nt":
@@ -684,7 +680,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
684
680
  self.repo.git.checkout(*args)
685
681
  else:
686
682
  if paths:
687
- paths_list: Optional[List[str]] = [
683
+ paths_list: Optional[list[str]] = [
688
684
  relpath(path, self.root_dir) for path in paths
689
685
  ]
690
686
  if os.name == "nt":
@@ -698,7 +694,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
698
694
 
699
695
  def status(
700
696
  self, ignored: bool = False, untracked_files: str = "all"
701
- ) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
697
+ ) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
702
698
  raise NotImplementedError
703
699
 
704
700
  def merge(