scmrepo 2.0.4__py3-none-any.whl → 2.1.1__py3-none-any.whl

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.

scmrepo/asyn.py CHANGED
@@ -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
 
scmrepo/fs.py CHANGED
@@ -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
scmrepo/git/__init__.py CHANGED
@@ -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(
@@ -2,19 +2,13 @@ import locale
2
2
  import logging
3
3
  import os
4
4
  import stat
5
+ from collections.abc import Generator, Iterable, Iterator, Mapping
5
6
  from contextlib import contextmanager
6
7
  from io import BytesIO, StringIO, TextIOWrapper
7
8
  from typing import (
8
9
  TYPE_CHECKING,
9
10
  Callable,
10
- Dict,
11
- Generator,
12
- Iterable,
13
- Iterator,
14
- List,
15
- Mapping,
16
11
  Optional,
17
- Tuple,
18
12
  Union,
19
13
  )
20
14
  from urllib.parse import urlparse
@@ -39,7 +33,7 @@ logger = logging.getLogger(__name__)
39
33
  if TYPE_CHECKING:
40
34
  from pygit2 import Commit, Oid, Signature
41
35
  from pygit2.config import Config as _Pygit2Config
42
- from pygit2.remote import Remote
36
+ from pygit2.remotes import Remote
43
37
  from pygit2.repository import Repository
44
38
 
45
39
  from scmrepo.progress import GitProgressEvent
@@ -54,7 +48,7 @@ class Pygit2Object(GitObject):
54
48
  self,
55
49
  mode: str = "r",
56
50
  encoding: Optional[str] = None,
57
- key: Optional[Tuple[str, ...]] = None,
51
+ key: Optional[tuple[str, ...]] = None,
58
52
  raw: bool = True,
59
53
  rev: Optional[str] = None,
60
54
  **kwargs,
@@ -124,13 +118,13 @@ class Pygit2Config(Config):
124
118
  def __init__(self, config: "_Pygit2Config"):
125
119
  self._config = config
126
120
 
127
- def _key(self, section: Tuple[str, ...], name: str) -> str:
121
+ def _key(self, section: tuple[str, ...], name: str) -> str:
128
122
  return ".".join((*section, name))
129
123
 
130
- def get(self, section: Tuple[str, ...], name: str) -> str:
124
+ def get(self, section: tuple[str, ...], name: str) -> str:
131
125
  return self._config[self._key(section, name)]
132
126
 
133
- def get_bool(self, section: Tuple[str, ...], name: str) -> bool:
127
+ def get_bool(self, section: tuple[str, ...], name: str) -> bool:
134
128
  from pygit2 import GitError
135
129
 
136
130
  try:
@@ -138,7 +132,7 @@ class Pygit2Config(Config):
138
132
  except GitError as exc:
139
133
  raise ValueError("invalid boolean config entry") from exc
140
134
 
141
- def get_multivar(self, section: Tuple[str, ...], name: str) -> Iterator[str]:
135
+ def get_multivar(self, section: tuple[str, ...], name: str) -> Iterator[str]:
142
136
  from pygit2 import GitError
143
137
 
144
138
  try:
@@ -652,13 +646,13 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
652
646
  except KeyError as exc:
653
647
  raise SCMError(f"'{url}' is not a valid Git remote or URL") from exc
654
648
 
655
- parsed = urlparse(url)
656
- if parsed.scheme in ("git", "git+ssh", "ssh") or url.startswith("git@"):
657
- raise NotImplementedError
658
649
  if os.name == "nt" and url.startswith("file://"):
659
650
  url = url[len("file://") :]
660
-
661
- yield self.repo.remotes.create_anonymous(url)
651
+ remote = self.repo.remotes.create_anonymous(url)
652
+ parsed = urlparse(remote.url)
653
+ if parsed.scheme in ("git", "git+ssh", "ssh") or remote.url.startswith("git@"):
654
+ raise NotImplementedError
655
+ yield remote
662
656
 
663
657
  def fetch_refspecs(
664
658
  self,
@@ -681,7 +675,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
681
675
  # when a ref was rejected so we have to determine whether no callback
682
676
  # means up to date or rejected
683
677
  def _default_status(
684
- src: str, dst: str, remote_refs: Dict[str, "Oid"]
678
+ src: str, dst: str, remote_refs: dict[str, "Oid"]
685
679
  ) -> SyncStatus:
686
680
  try:
687
681
  if remote_refs[src] != self.repo.references[dst].target:
@@ -698,7 +692,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
698
692
  SCMError(f"Git failed to fetch ref from '{url}'"),
699
693
  ):
700
694
  with RemoteCallbacks(progress=progress) as cb:
701
- remote_refs: Dict[str, "Oid"] = (
695
+ remote_refs: dict[str, "Oid"] = (
702
696
  {
703
697
  head["name"]: head["oid"]
704
698
  for head in remote.ls_remotes(callbacks=cb)
@@ -712,7 +706,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
712
706
  message="fetch",
713
707
  )
714
708
 
715
- result: Dict[str, "SyncStatus"] = {}
709
+ result: dict[str, "SyncStatus"] = {}
716
710
  for refspec in refspecs:
717
711
  lh, rh = refspec.split(":")
718
712
  if lh.endswith("*"):
@@ -735,7 +729,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
735
729
  def _refspecs_list(
736
730
  refspecs: Union[str, Iterable[str]],
737
731
  force: bool = False,
738
- ) -> List[str]:
732
+ ) -> list[str]:
739
733
  if isinstance(refspecs, str):
740
734
  if force and not refspecs.startswith("+"):
741
735
  refspecs = f"+{refspecs}"
@@ -755,7 +749,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
755
749
  ref: str,
756
750
  message: Optional[str] = None,
757
751
  include_untracked: bool = False,
758
- ) -> Tuple[Optional[str], bool]:
752
+ ) -> tuple[Optional[str], bool]:
759
753
  from scmrepo.git import Stash
760
754
 
761
755
  try:
@@ -880,7 +874,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
880
874
 
881
875
  index = self.repo.index
882
876
  if paths:
883
- path_list: Optional[List[str]] = [
877
+ path_list: Optional[list[str]] = [
884
878
  relpath(path, self.root_dir) for path in paths
885
879
  ]
886
880
  if os.name == "nt":
@@ -911,7 +905,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
911
905
 
912
906
  def status(
913
907
  self, ignored: bool = False, untracked_files: str = "all"
914
- ) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
908
+ ) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
915
909
  from pygit2 import (
916
910
  GIT_STATUS_IGNORED,
917
911
  GIT_STATUS_INDEX_DELETED,
@@ -925,13 +919,13 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
925
919
  GIT_STATUS_WT_UNREADABLE,
926
920
  )
927
921
 
928
- staged: Mapping[str, List[str]] = {
922
+ staged: Mapping[str, list[str]] = {
929
923
  "add": [],
930
924
  "delete": [],
931
925
  "modify": [],
932
926
  }
933
- unstaged: List[str] = []
934
- untracked: List[str] = []
927
+ unstaged: list[str] = []
928
+ untracked: list[str] = []
935
929
 
936
930
  states = {
937
931
  GIT_STATUS_WT_NEW: untracked,
@@ -1,6 +1,6 @@
1
1
  from contextlib import AbstractContextManager
2
2
  from types import TracebackType
3
- from typing import TYPE_CHECKING, Callable, Dict, Optional, Type, Union
3
+ from typing import TYPE_CHECKING, Callable, Optional, Union
4
4
 
5
5
  from pygit2 import RemoteCallbacks as _RemoteCallbacks
6
6
 
@@ -11,6 +11,7 @@ from scmrepo.progress import GitProgressReporter
11
11
  if TYPE_CHECKING:
12
12
  from pygit2 import Oid
13
13
  from pygit2.credentials import Keypair, Username, UserPass
14
+ from pygit2.enums import CredentialType
14
15
 
15
16
  from scmrepo.progress import GitProgressEvent
16
17
 
@@ -29,11 +30,11 @@ class RemoteCallbacks(_RemoteCallbacks, AbstractContextManager):
29
30
  self.progress = GitProgressReporter(progress) if progress else None
30
31
  self._store_credentials: Optional["Credential"] = None
31
32
  self._tried_credentials = False
32
- self.result: Dict[str, SyncStatus] = {}
33
+ self.result: dict[str, SyncStatus] = {}
33
34
 
34
35
  def __exit__(
35
36
  self,
36
- exc_type: Optional[Type[BaseException]],
37
+ exc_type: Optional[type[BaseException]],
37
38
  exc_value: Optional[BaseException],
38
39
  traceback: Optional[TracebackType],
39
40
  ):
@@ -45,16 +46,20 @@ class RemoteCallbacks(_RemoteCallbacks, AbstractContextManager):
45
46
  self.progress(string)
46
47
 
47
48
  def credentials(
48
- self, url: str, username_from_url: Optional[str], allowed_types: int
49
+ self,
50
+ url: str,
51
+ username_from_url: Optional[str],
52
+ allowed_types: "CredentialType",
49
53
  ) -> "_Pygit2Credential":
50
54
  from pygit2 import GitError, Passthrough
51
- from pygit2.credentials import GIT_CREDENTIAL_USERPASS_PLAINTEXT, UserPass
55
+ from pygit2.credentials import UserPass
56
+ from pygit2.enums import CredentialType
52
57
 
53
58
  if self._tried_credentials:
54
59
  raise GitError(f"authentication failed for '{url}'")
55
60
  self._tried_credentials = True
56
61
 
57
- if allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT:
62
+ if allowed_types & CredentialType.USERPASS_PLAINTEXT:
58
63
  try:
59
64
  if self._store_credentials:
60
65
  creds = self._store_credentials
@@ -1,6 +1,6 @@
1
1
  import io
2
2
  import logging
3
- from typing import TYPE_CHECKING, Callable, List, Optional
3
+ from typing import TYPE_CHECKING, Callable, Optional
4
4
 
5
5
  from pygit2 import GIT_FILTER_CLEAN, Filter, Passthrough
6
6
 
@@ -17,7 +17,7 @@ class LFSFilter(Filter):
17
17
  self._smudge_buf: Optional[io.BytesIO] = None
18
18
  self._smudge_root: Optional[str] = None
19
19
 
20
- def check(self, src: "FilterSource", attr_values: List[str]):
20
+ def check(self, src: "FilterSource", attr_values: list[str]):
21
21
  if attr_values[0] == "lfs" and src.mode != GIT_FILTER_CLEAN:
22
22
  self._smudge_buf = io.BytesIO()
23
23
  self._smudge_root = src.repo.workdir or src.repo.path
scmrepo/git/config.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """git config convenience wrapper."""
2
2
  import logging
3
3
  from abc import ABC, abstractmethod
4
- from typing import Iterator, Tuple
4
+ from collections.abc import Iterator
5
5
 
6
6
  logger = logging.getLogger(__name__)
7
7
 
@@ -10,7 +10,7 @@ class Config(ABC):
10
10
  """Read-only Git config."""
11
11
 
12
12
  @abstractmethod
13
- def get(self, section: Tuple[str, ...], name: str) -> str:
13
+ def get(self, section: tuple[str, ...], name: str) -> str:
14
14
  """Return the specified setting as a string.
15
15
 
16
16
  Raises:
@@ -18,7 +18,7 @@ class Config(ABC):
18
18
  """
19
19
 
20
20
  @abstractmethod
21
- def get_bool(self, section: Tuple[str, ...], name: str) -> bool:
21
+ def get_bool(self, section: tuple[str, ...], name: str) -> bool:
22
22
  """Return the specified setting as a boolean.
23
23
 
24
24
  Raises:
@@ -27,7 +27,7 @@ class Config(ABC):
27
27
  """
28
28
 
29
29
  @abstractmethod
30
- def get_multivar(self, section: Tuple[str, ...], name: str) -> Iterator[str]:
30
+ def get_multivar(self, section: tuple[str, ...], name: str) -> Iterator[str]:
31
31
  """Iterate over string values in the specified multivar setting.
32
32
 
33
33
  Raises:
@@ -34,18 +34,13 @@ import shutil
34
34
  import subprocess # nosec B404
35
35
  import sys
36
36
  from abc import ABC, abstractmethod
37
+ from collections.abc import Iterator, Mapping
37
38
  from typing import (
38
39
  TYPE_CHECKING,
39
40
  Any,
40
41
  Callable,
41
- Dict,
42
- Iterable,
43
- Iterator,
44
- List,
45
- Mapping,
46
42
  NamedTuple,
47
43
  Optional,
48
- Tuple,
49
44
  Union,
50
45
  )
51
46
  from urllib.parse import urlparse, urlunparse
@@ -57,11 +52,13 @@ from funcy import cached_property
57
52
  from scmrepo.exceptions import SCMError
58
53
 
59
54
  if TYPE_CHECKING:
55
+ from collections.abc import Iterable
56
+
60
57
  from dulwich.config import ConfigDict
61
58
 
62
59
  logger = logging.getLogger(__name__)
63
60
 
64
- SectionLike = Union[bytes, str, Tuple[Union[bytes, str], ...]]
61
+ SectionLike = Union[bytes, str, tuple[Union[bytes, str], ...]]
65
62
 
66
63
 
67
64
  class CredentialNotFoundError(SCMError):
@@ -110,14 +107,14 @@ class GitCredentialHelper(CredentialHelper):
110
107
  def __init__(self, command: str, use_http_path: bool = False):
111
108
  super().__init__()
112
109
  self._command = command
113
- self._run_kwargs: Dict[str, Any] = {}
110
+ self._run_kwargs: dict[str, Any] = {}
114
111
  if self._command[0] == "!":
115
112
  # On Windows this will only work in git-bash and/or WSL2
116
113
  self._run_kwargs["shell"] = True
117
114
  self._encoding = locale.getpreferredencoding()
118
115
  self.use_http_path = use_http_path
119
116
 
120
- def _prepare_command(self, action: Optional[str] = None) -> Union[str, List[str]]:
117
+ def _prepare_command(self, action: Optional[str] = None) -> Union[str, list[str]]:
121
118
  if self._command[0] == "!":
122
119
  return self._command[1:] + (f" {action}" if action else "")
123
120
 
@@ -242,7 +239,7 @@ class GitCredentialHelper(CredentialHelper):
242
239
  @staticmethod
243
240
  def get_matching_commands(
244
241
  base_url: str, config: Optional[Union["ConfigDict", "StackedConfig"]] = None
245
- ) -> Iterator[Tuple[str, bool]]:
242
+ ) -> Iterator[tuple[str, bool]]:
246
243
  config = config or StackedConfig.default()
247
244
  if isinstance(config, StackedConfig):
248
245
  backends: Iterable["ConfigDict"] = config.backends
@@ -326,7 +323,7 @@ class MemoryCredentialHelper(CredentialHelper):
326
323
 
327
324
  def __init__(self):
328
325
  super().__init__()
329
- self._credentials: Dict["_CredentialKey", "Credential"] = {}
326
+ self._credentials: dict["_CredentialKey", "Credential"] = {}
330
327
 
331
328
  def __getitem__(self, key: object) -> "Credential":
332
329
  if isinstance(key, _CredentialKey):
@@ -572,7 +569,7 @@ class Credential(Mapping[str, str]):
572
569
  return urlunparse((self.protocol or "", netloc, path, "", "", ""))
573
570
 
574
571
  @cached_property
575
- def helpers(self) -> List["CredentialHelper"]:
572
+ def helpers(self) -> list["CredentialHelper"]:
576
573
  url = self.url
577
574
  return [
578
575
  GitCredentialHelper(command, use_http_path=use_http_path)
scmrepo/git/lfs/client.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
+ from collections.abc import Iterable
2
3
  from contextlib import AbstractContextManager
3
- from functools import wraps
4
- from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterable, Optional
4
+ from typing import TYPE_CHECKING, Any, Optional
5
5
 
6
6
  import aiohttp
7
7
  from dvc_http import HTTPFileSystem
@@ -31,29 +31,6 @@ class _LFSFileSystem(HTTPFileSystem):
31
31
  return {}
32
32
 
33
33
 
34
- def _authed(f: Callable[..., Awaitable]):
35
- """Set credentials and retry the given coroutine if needed."""
36
-
37
- # pylint: disable=protected-access
38
- @wraps(f) # type: ignore[arg-type]
39
- async def wrapper(self, *args, **kwargs):
40
- try:
41
- return await f(self, *args, **kwargs)
42
- except aiohttp.ClientResponseError as exc:
43
- if exc.status != 401:
44
- raise
45
- session = await self._set_session()
46
- if session.auth:
47
- raise
48
- auth = self._get_auth()
49
- if auth is None:
50
- raise
51
- self._session._auth = auth
52
- return await f(self, *args, **kwargs)
53
-
54
- return wrapper
55
-
56
-
57
34
  class LFSClient(AbstractContextManager):
58
35
  """Naive read-only LFS HTTP client."""
59
36
 
@@ -63,7 +40,7 @@ class LFSClient(AbstractContextManager):
63
40
  self,
64
41
  url: str,
65
42
  git_url: Optional[str] = None,
66
- headers: Optional[Dict[str, str]] = None,
43
+ headers: Optional[dict[str, str]] = None,
67
44
  ):
68
45
  """
69
46
  Args:
@@ -71,7 +48,7 @@ class LFSClient(AbstractContextManager):
71
48
  """
72
49
  self.url = url
73
50
  self.git_url = git_url
74
- self.headers: Dict[str, str] = headers or {}
51
+ self.headers: dict[str, str] = headers or {}
75
52
 
76
53
  def __exit__(self, *args, **kwargs):
77
54
  self.close()
@@ -111,17 +88,16 @@ class LFSClient(AbstractContextManager):
111
88
  async def _set_session(self) -> aiohttp.ClientSession:
112
89
  return await self.fs.fs.set_session()
113
90
 
114
- @_authed
115
91
  async def _batch_request(
116
92
  self,
117
93
  objects: Iterable[Pointer],
118
94
  upload: bool = False,
119
95
  ref: Optional[str] = None,
120
96
  hash_algo: str = "sha256",
121
- ) -> Dict[str, Any]:
97
+ ) -> dict[str, Any]:
122
98
  """Send LFS API /objects/batch request."""
123
99
  url = f"{self.url}/objects/batch"
124
- body: Dict[str, Any] = {
100
+ body: dict[str, Any] = {
125
101
  "operation": "upload" if upload else "download",
126
102
  "transfers": ["basic"],
127
103
  "objects": [{"oid": obj.oid, "size": obj.size} for obj in objects],
@@ -133,14 +109,30 @@ class LFSClient(AbstractContextManager):
133
109
  headers = dict(self.headers)
134
110
  headers["Accept"] = self.JSON_CONTENT_TYPE
135
111
  headers["Content-Type"] = self.JSON_CONTENT_TYPE
136
- async with session.post(
137
- url,
138
- headers=headers,
139
- json=body,
140
- ) as resp:
141
- return await resp.json()
142
-
143
- @_authed
112
+ try:
113
+ async with session.post(
114
+ url,
115
+ headers=headers,
116
+ json=body,
117
+ raise_for_status=True,
118
+ ) as resp:
119
+ data = await resp.json()
120
+ except aiohttp.ClientResponseError as exc:
121
+ if exc.status != 401:
122
+ raise
123
+ auth = self._get_auth()
124
+ if auth is None:
125
+ raise
126
+ async with session.post(
127
+ url,
128
+ auth=auth,
129
+ headers=headers,
130
+ json=body,
131
+ raise_for_status=True,
132
+ ) as resp:
133
+ data = await resp.json()
134
+ return data
135
+
144
136
  async def _download(
145
137
  self,
146
138
  storage: "LFSStorage",
scmrepo/git/lfs/fetch.py CHANGED
@@ -1,7 +1,8 @@
1
1
  import fnmatch
2
2
  import io
3
3
  import os
4
- from typing import TYPE_CHECKING, Callable, Iterable, Iterator, List, Optional, Set
4
+ from collections.abc import Iterable, Iterator
5
+ from typing import TYPE_CHECKING, Callable, Optional
5
6
 
6
7
  from scmrepo.exceptions import InvalidRemote, SCMError
7
8
 
@@ -15,16 +16,16 @@ if TYPE_CHECKING:
15
16
 
16
17
  def fetch(
17
18
  scm: "Git",
18
- revs: Optional[List[str]] = None,
19
+ revs: Optional[list[str]] = None,
19
20
  remote: Optional[str] = None,
20
- include: Optional[List[str]] = None,
21
- exclude: Optional[List[str]] = None,
21
+ include: Optional[list[str]] = None,
22
+ exclude: Optional[list[str]] = None,
22
23
  progress: Optional[Callable[["GitProgressEvent"], None]] = None,
23
24
  ):
24
25
  # NOTE: This currently does not support fetching objects from the worktree
25
26
  if not revs:
26
27
  revs = ["HEAD"]
27
- objects: Set[Pointer] = set()
28
+ objects: set[Pointer] = set()
28
29
  for rev in revs:
29
30
  objects.update(
30
31
  pointer
@@ -100,8 +101,8 @@ def get_fetch_url(scm: "Git", remote: Optional[str] = None): # noqa: C901,PLR09
100
101
  def _collect_objects(
101
102
  scm: "Git",
102
103
  rev: str,
103
- include: Optional[List[str]],
104
- exclude: Optional[List[str]],
104
+ include: Optional[list[str]],
105
+ exclude: Optional[list[str]],
105
106
  ) -> Iterator[Pointer]:
106
107
  fs = scm.get_fs(rev)
107
108
  for path in _filter_paths(fs.find("/"), include, exclude):
@@ -118,7 +119,7 @@ def _collect_objects(
118
119
 
119
120
 
120
121
  def _filter_paths(
121
- paths: Iterable[str], include: Optional[List[str]], exclude: Optional[List[str]]
122
+ paths: Iterable[str], include: Optional[list[str]], exclude: Optional[list[str]]
122
123
  ) -> Iterator[str]:
123
124
  filtered = set()
124
125
  if include:
scmrepo/git/lfs/object.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, fields
2
- from typing import Any, Dict
2
+ from typing import Any
3
3
 
4
4
 
5
5
  @dataclass(frozen=True)
@@ -11,5 +11,5 @@ class LFSObject:
11
11
  return self.oid
12
12
 
13
13
  @classmethod
14
- def from_dict(cls, d: Dict[str, Any]) -> "LFSObject":
14
+ def from_dict(cls, d: dict[str, Any]) -> "LFSObject":
15
15
  return cls(**{k: v for k, v in d.items() if k in fields(cls)})
@@ -2,7 +2,7 @@ import hashlib
2
2
  import io
3
3
  import logging
4
4
  from dataclasses import dataclass
5
- from typing import IO, BinaryIO, TextIO, Tuple
5
+ from typing import IO, BinaryIO, TextIO
6
6
 
7
7
  logger = logging.getLogger(__name__)
8
8
 
@@ -13,7 +13,7 @@ ALLOWED_VERSIONS = (LFS_VERSION, LEGACY_LFS_VERSION)
13
13
  HEADERS = [(b"version " + version.encode("utf-8")) for version in ALLOWED_VERSIONS]
14
14
 
15
15
 
16
- def _get_kv(line: str) -> Tuple[str, str]:
16
+ def _get_kv(line: str) -> tuple[str, str]:
17
17
  key, value = line.strip().split(maxsplit=1)
18
18
  return key, value
19
19
 
@@ -1,4 +1,4 @@
1
- from typing import Any, BinaryIO, Callable, Dict, Optional, Union
1
+ from typing import Any, BinaryIO, Callable, Optional, Union
2
2
 
3
3
  from dvc_objects.fs.callbacks import DEFAULT_CALLBACK, Callback, TqdmCallback
4
4
 
@@ -37,7 +37,7 @@ class LFSCallback(Callback):
37
37
  self,
38
38
  path_1: Union[str, BinaryIO],
39
39
  path_2: str,
40
- kwargs: Dict[str, Any],
40
+ kwargs: dict[str, Any],
41
41
  child: Optional[Callback] = None,
42
42
  ):
43
43
  if child:
@@ -1,6 +1,7 @@
1
1
  import errno
2
2
  import os
3
- from typing import TYPE_CHECKING, BinaryIO, Callable, Collection, Optional, Union
3
+ from collections.abc import Collection
4
+ from typing import TYPE_CHECKING, BinaryIO, Callable, Optional, Union
4
5
 
5
6
  from .pointer import Pointer
6
7
  from .progress import LFSCallback
scmrepo/git/objects.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import datetime
2
2
  import stat
3
3
  from abc import ABC, abstractmethod
4
+ from collections.abc import Iterable
4
5
  from dataclasses import dataclass
5
- from typing import Iterable, List, Optional, cast
6
+ from typing import Optional, cast
6
7
 
7
8
  from pygtrie import Trie
8
9
 
@@ -168,7 +169,7 @@ class GitCommit:
168
169
  commit_time: int
169
170
  commit_time_offset: int
170
171
  message: str
171
- parents: List[str]
172
+ parents: list[str]
172
173
  committer_name: str
173
174
  committer_email: str
174
175
  author_name: str
@@ -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
@@ -41,7 +41,7 @@ Requires-Dist: paramiko ==3.3.1 ; extra == 'tests'
41
41
  Requires-Dist: types-certifi ==2021.10.8.3 ; extra == 'tests'
42
42
  Requires-Dist: types-mock ==5.1.0.2 ; extra == 'tests'
43
43
  Requires-Dist: types-paramiko ==3.4.0.20240120 ; extra == 'tests'
44
- Requires-Dist: pytest-docker ==0.12.0 ; (python_version < "3.10" and implementation_name != "pypy") and extra == 'tests'
44
+ Requires-Dist: pytest-docker ==2.2.0 ; (python_version < "3.10" and implementation_name != "pypy") and extra == 'tests'
45
45
 
46
46
  scmrepo
47
47
  =======
@@ -0,0 +1,37 @@
1
+ scmrepo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ scmrepo/asyn.py,sha256=1l4Npa6gmIeZY6t_8S1LK5CJ3qAW_NMgKPrsN-8f9kU,1523
3
+ scmrepo/base.py,sha256=UjEw7iQhYRAxj4Ia9x5NFMjI__AO7ql6IERoFo7hslo,3006
4
+ scmrepo/exceptions.py,sha256=vR8BuCKgKh9lMnCemzNYGHiJctioOmhn_Kv5m8XO69Y,1053
5
+ scmrepo/fs.py,sha256=0izyq5in6b20H2eSjpud7ykDzKE3230qvcM_3oko7iY,7720
6
+ scmrepo/noscm.py,sha256=aiGE-fabmgF6WTp5mdE5KLeqiOobPVQYa-Ie1zSHs8U,463
7
+ scmrepo/progress.py,sha256=fRUMvkcw6GLuVTP_tK7mGpKeJjbJulFP8rPUqyltkYQ,2157
8
+ scmrepo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ scmrepo/utils.py,sha256=_F3rVvPhES-A2JxLGob0RV8BOnHzxbA9aDPClA7_V8M,1512
10
+ scmrepo/git/__init__.py,sha256=3NEW9rBH2ohprKjXIfodDXnpZxAbAtEYUPMO5uk5Hxw,17101
11
+ scmrepo/git/config.py,sha256=oMoxRq8oJOTRZUNArsT6xpNlfP2n1eTXDMlfHtv1pEs,942
12
+ scmrepo/git/credentials.py,sha256=qJZLLyaDH4t2nut3Yep9Jk9ZEkThjJfVMDZXOFajdZU,20943
13
+ scmrepo/git/objects.py,sha256=vqeFpUlMFHL9Yv1h3wTA7mbRWHCVC_4KgLy5aAISD2g,4674
14
+ scmrepo/git/stash.py,sha256=rnZDeOsO9P-k2e7ulCLUmZKSxSCxaRKl3XJlh97F084,2801
15
+ scmrepo/git/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ scmrepo/git/backend/base.py,sha256=acxuSQ0Z-UGNkGraCdLQxBxDHbTdYWi-FzXtwdb-1O8,13535
17
+ scmrepo/git/backend/gitpython.py,sha256=6L47iX1SmqfM04_Ghwd_DEHegOKewCLu-5MTkBZO_Zo,25312
18
+ scmrepo/git/backend/dulwich/__init__.py,sha256=aQeuLqdprJcxnk8Jkp4mlLXkLRzqMnUwiuA3wjf3_dA,34366
19
+ scmrepo/git/backend/dulwich/asyncssh_vendor.py,sha256=OuZ_bWe5-LiZCIMwBRaX_uj03oEcrRgr1uf9i2Xv4Fk,11497
20
+ scmrepo/git/backend/dulwich/client.py,sha256=bcDroljSvNz6s5WWv9UVvZHKkOJOVTK_zU7YCq62TN4,2360
21
+ scmrepo/git/backend/pygit2/__init__.py,sha256=tapIRAh--nzGUcVGijaMSal2ZPscab9c1mHdqiUIxBU,37004
22
+ scmrepo/git/backend/pygit2/callbacks.py,sha256=Ky4YmUPhv9xjU_44ypBYIcaVHJixzaGb6t9HIeUmBP4,2751
23
+ scmrepo/git/backend/pygit2/filter.py,sha256=2NlWfQ7soXN1H7Es6-LctE74hpj3QKQTlYqXRH83VpM,2128
24
+ scmrepo/git/lfs/__init__.py,sha256=at5blRIKnKpg_g5dLRDsGWBFi6SbucRlF_DX6aAkGtE,257
25
+ scmrepo/git/lfs/client.py,sha256=MitdVwI_1_17qwMM-totHG3-qAt80oAkHiVTcLaYapY,5347
26
+ scmrepo/git/lfs/exceptions.py,sha256=cLlImmPXWJJUl44S4xcRBa2T9wYRkWTaKQGwJylwOhA,77
27
+ scmrepo/git/lfs/fetch.py,sha256=ADNpskbDrvMI7ru4AiOf_c1gfw8TQ7Wct0EiN2Pq-qc,4683
28
+ scmrepo/git/lfs/object.py,sha256=rAYY_z9EYoHPfbpF1QHwL7ecYgaETPyCl-zBx0E1oIQ,337
29
+ scmrepo/git/lfs/pointer.py,sha256=BcVbtjoOUG9cEzyJSJDeweqehGZvq43P6NNLDYUGYEI,3181
30
+ scmrepo/git/lfs/progress.py,sha256=C-HGap81Gif_abhUIzQrM4lL4Tbq9I6C909A7zLTiOM,1726
31
+ scmrepo/git/lfs/smudge.py,sha256=sMSatXCTHZ5cAo-gaE_6KXwCHlXGqzkF0dVgIbPwTJU,1563
32
+ scmrepo/git/lfs/storage.py,sha256=FmdltddhyRg4jrCc1PaiC049_m8Ya9ELMikb-iOuvgw,2241
33
+ scmrepo-2.1.1.dist-info/LICENSE,sha256=-1jhbPjoIVHR0cEgahL4Zhct75Ff4MzYCR_jOaJDPq8,11340
34
+ scmrepo-2.1.1.dist-info/METADATA,sha256=uAlODk9oF8tRBPOYX3Cv8r3DgJhjT0StqdJTQTr7PZM,4833
35
+ scmrepo-2.1.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
36
+ scmrepo-2.1.1.dist-info/top_level.txt,sha256=iunjod6w3GogERsAYfLRupnANXnqzX3jbIfbeIQG5cc,8
37
+ scmrepo-2.1.1.dist-info/RECORD,,
@@ -1,37 +0,0 @@
1
- scmrepo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- scmrepo/asyn.py,sha256=YdoLzqF7drmnf1yN24-0IwyosPi1Pf5qlLRVUI4L2qo,1529
3
- scmrepo/base.py,sha256=UjEw7iQhYRAxj4Ia9x5NFMjI__AO7ql6IERoFo7hslo,3006
4
- scmrepo/exceptions.py,sha256=vR8BuCKgKh9lMnCemzNYGHiJctioOmhn_Kv5m8XO69Y,1053
5
- scmrepo/fs.py,sha256=y-SHgIHC5pSfr0CV9H9m5sd0HNydz7o2WWeHYxk0a5U,7733
6
- scmrepo/noscm.py,sha256=aiGE-fabmgF6WTp5mdE5KLeqiOobPVQYa-Ie1zSHs8U,463
7
- scmrepo/progress.py,sha256=fRUMvkcw6GLuVTP_tK7mGpKeJjbJulFP8rPUqyltkYQ,2157
8
- scmrepo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- scmrepo/utils.py,sha256=_F3rVvPhES-A2JxLGob0RV8BOnHzxbA9aDPClA7_V8M,1512
10
- scmrepo/git/__init__.py,sha256=LW8ARrqkNsbVMftoPTREeMXhroD-ZS6h5fXMxf6F0Oc,17136
11
- scmrepo/git/config.py,sha256=_pt8Ygdz71xcbo4KvX_5dW14ujHmPJX3z3W8Ikasd-M,940
12
- scmrepo/git/credentials.py,sha256=R0boJz9UTRENPac8m3TV42KXhn0yT0Dy7V15txXCxPw,20927
13
- scmrepo/git/objects.py,sha256=tYlwcrbs4sI50VPaqllvY9PujjNDdYwRISeVEozNImA,4653
14
- scmrepo/git/stash.py,sha256=rnZDeOsO9P-k2e7ulCLUmZKSxSCxaRKl3XJlh97F084,2801
15
- scmrepo/git/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- scmrepo/git/backend/base.py,sha256=Un_DD84HKjxC3QAULJGnvdfVfDnI6f_K0KQtidfNOdk,13515
17
- scmrepo/git/backend/gitpython.py,sha256=FJs4Y-Gp8N9MLgkiRBK2KnvSfDBBVv1BAZ5UG9penBw,25324
18
- scmrepo/git/backend/dulwich/__init__.py,sha256=iXD5LXb0tdsLvsJLmwtp_LDECNzUyM1R-UufyJWAC-Y,34382
19
- scmrepo/git/backend/dulwich/asyncssh_vendor.py,sha256=443ivGFvttlZ_F8dL_PvAd6J4XbUcP5e26T9DyJP6HA,11502
20
- scmrepo/git/backend/dulwich/client.py,sha256=sxz6eJ1VNVQA32AxWnpjyearcS8O99NnbyCUyO2cPx4,2345
21
- scmrepo/git/backend/pygit2/__init__.py,sha256=eEhY1SEW8TEVVfNhzHVTa_ZbSyeFv7jDvcd_FHXLM10,36986
22
- scmrepo/git/backend/pygit2/callbacks.py,sha256=RXhzUU3IhKFinbZPGzdTn3bcmcPa1dF7CNpFW-kTAHk,2668
23
- scmrepo/git/backend/pygit2/filter.py,sha256=v7HWCy0hmYwk0gLhMxzJXihtJxCA6YXw14ctvujNafk,2134
24
- scmrepo/git/lfs/__init__.py,sha256=at5blRIKnKpg_g5dLRDsGWBFi6SbucRlF_DX6aAkGtE,257
25
- scmrepo/git/lfs/client.py,sha256=5h7BlcSvc9c1VBMCt0p-7XTIEDhX2Y07GOzhjtzl8T0,5561
26
- scmrepo/git/lfs/exceptions.py,sha256=cLlImmPXWJJUl44S4xcRBa2T9wYRkWTaKQGwJylwOhA,77
27
- scmrepo/git/lfs/fetch.py,sha256=2UKkjqqjsFOr3zH1ualVyesUGdZ216veUqpxS_DIz9k,4667
28
- scmrepo/git/lfs/object.py,sha256=2wHbVjloTcAWPtyCnEroEiCr15hq3o-Q0d2qESaEEN4,343
29
- scmrepo/git/lfs/pointer.py,sha256=D7Phz5TgTn7o3GeQWxKVT639OftW4PGSlHRqBIPDpq0,3188
30
- scmrepo/git/lfs/progress.py,sha256=J0j9jlTWeLIK0vLWK9UXEvHsVfKbhJjJp4Bkk55bQ7c,1732
31
- scmrepo/git/lfs/smudge.py,sha256=sMSatXCTHZ5cAo-gaE_6KXwCHlXGqzkF0dVgIbPwTJU,1563
32
- scmrepo/git/lfs/storage.py,sha256=q-bJasUKBmuuI9Nt15ze16miFIpmMkLU9v7MvbQE9cY,2214
33
- scmrepo-2.0.4.dist-info/LICENSE,sha256=-1jhbPjoIVHR0cEgahL4Zhct75Ff4MzYCR_jOaJDPq8,11340
34
- scmrepo-2.0.4.dist-info/METADATA,sha256=tUInr08Sc5Aa8tePMm_v7FCzkf7bmnxuIrIM11NV5PA,4833
35
- scmrepo-2.0.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
36
- scmrepo-2.0.4.dist-info/top_level.txt,sha256=iunjod6w3GogERsAYfLRupnANXnqzX3jbIfbeIQG5cc,8
37
- scmrepo-2.0.4.dist-info/RECORD,,