scmrepo 3.3.10__py3-none-any.whl → 3.3.11__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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  import os
5
- from collections.abc import Coroutine, Iterator, Sequence
5
+ from collections.abc import Coroutine, Iterator
6
6
  from typing import (
7
7
  TYPE_CHECKING,
8
8
  Any,
@@ -18,6 +18,7 @@ from scmrepo.asyn import BaseAsyncObject, sync_wrapper
18
18
  from scmrepo.exceptions import AuthError
19
19
 
20
20
  if TYPE_CHECKING:
21
+ from collections.abc import Sequence
21
22
  from pathlib import Path
22
23
 
23
24
  from asyncssh.auth import KbdIntPrompts, KbdIntResponse
@@ -40,6 +41,12 @@ async def _read_all(read: Callable[[int], Coroutine], n: Optional[int] = None) -
40
41
  return b"".join(result)
41
42
 
42
43
 
44
+ async def _getpass(*args, **kwargs) -> str:
45
+ from getpass import getpass
46
+
47
+ return await asyncio.to_thread(getpass, *args, **kwargs)
48
+
49
+
43
50
  class _StderrWrapper:
44
51
  def __init__(self, stderr: "SSHReader", loop: asyncio.AbstractEventLoop) -> None:
45
52
  self.stderr = stderr
@@ -97,45 +104,6 @@ class AsyncSSHWrapper(BaseAsyncObject):
97
104
  close = sync_wrapper(_close)
98
105
 
99
106
 
100
- # NOTE: Github's SSH server does not strictly comply with the SSH protocol.
101
- # When validating a public key using the rsa-sha2-256 or rsa-sha2-512
102
- # signature algorithms, RFC4252 + RFC8332 state that the server should respond
103
- # with the same algorithm in SSH_MSG_USERAUTH_PK_OK. Github's server always
104
- # returns "ssh-rsa" rather than the correct sha2 algorithm name (likely for
105
- # backwards compatibility with old SSH client reasons). This behavior causes
106
- # asyncssh to fail with a key-mismatch error (since asyncssh expects the server
107
- # to behave properly).
108
- #
109
- # See also:
110
- # https://www.ietf.org/rfc/rfc4252.txt
111
- # https://www.ietf.org/rfc/rfc8332.txt
112
- def _process_public_key_ok_gh(self, _pkttype, _pktid, packet):
113
- from asyncssh.misc import ProtocolError
114
-
115
- algorithm = packet.get_string()
116
- key_data = packet.get_string()
117
- packet.check_end()
118
-
119
- # pylint: disable=protected-access
120
- if (
121
- (
122
- algorithm == b"ssh-rsa"
123
- and self._keypair.algorithm
124
- not in (
125
- b"ssh-rsa",
126
- b"rsa-sha2-256",
127
- b"rsa-sha2-512",
128
- )
129
- )
130
- or (algorithm not in (b"ssh-rsa", self._keypair.algorithm))
131
- or key_data != self._keypair.public_data
132
- ):
133
- raise ProtocolError("Key mismatch")
134
-
135
- self.create_task(self._send_signed_request())
136
- return True
137
-
138
-
139
107
  class InteractiveSSHClient(SSHClient):
140
108
  _conn: Optional["SSHClientConnection"] = None
141
109
  _keys_to_try: Optional[list["FilePath"]] = None
@@ -171,7 +139,7 @@ class InteractiveSSHClient(SSHClient):
171
139
  self._keys_to_try = []
172
140
  options = self._conn._options # pylint: disable=protected-access
173
141
  config = options.config
174
- client_keys = cast(Sequence["FilePath"], config.get("IdentityFile", ()))
142
+ client_keys = cast("Sequence[FilePath]", config.get("IdentityFile", ()))
175
143
  if not client_keys:
176
144
  client_keys = [
177
145
  os.path.expanduser(os.path.join("~", ".ssh", path))
@@ -202,8 +170,6 @@ class InteractiveSSHClient(SSHClient):
202
170
  return None
203
171
 
204
172
  async def _read_private_key_interactive(self, path: "FilePath") -> "SSHKey":
205
- from getpass import getpass
206
-
207
173
  from asyncssh.public_key import (
208
174
  KeyEncryptionError,
209
175
  KeyImportError,
@@ -215,11 +181,8 @@ class InteractiveSSHClient(SSHClient):
215
181
  if passphrase:
216
182
  return read_private_key(path, passphrase=passphrase)
217
183
 
218
- loop = asyncio.get_running_loop()
219
184
  for _ in range(3):
220
- passphrase = await loop.run_in_executor(
221
- None, getpass, f"Enter passphrase for key '{path}': "
222
- )
185
+ passphrase = await _getpass(f"Enter passphrase for key {path!r}: ")
223
186
  if passphrase:
224
187
  try:
225
188
  key = read_private_key(path, passphrase=passphrase)
@@ -239,23 +202,20 @@ class InteractiveSSHClient(SSHClient):
239
202
  lang: str,
240
203
  prompts: "KbdIntPrompts",
241
204
  ) -> Optional["KbdIntResponse"]:
242
- from getpass import getpass
243
-
244
205
  if os.environ.get("GIT_TERMINAL_PROMPT") == "0":
245
206
  return None
246
207
 
247
- def _getpass(prompt: str) -> str:
248
- return getpass(prompt=prompt).rstrip()
249
-
250
208
  if instructions:
251
209
  pass
252
- loop = asyncio.get_running_loop()
253
- return [
254
- await loop.run_in_executor(
255
- None, _getpass, f"({name}) {prompt}" if name else prompt
256
- )
257
- for prompt, _ in prompts
258
- ]
210
+
211
+ response: list[str] = []
212
+ for prompt, _echo in prompts:
213
+ p = await _getpass(f"({name}) {prompt}" if name else prompt)
214
+ response.append(p.rstrip())
215
+ return response
216
+
217
+ async def password_auth_requested(self) -> str:
218
+ return await _getpass()
259
219
 
260
220
 
261
221
  class AsyncSSHVendor(BaseAsyncObject, SSHVendor):
@@ -286,12 +246,6 @@ class AsyncSSHVendor(BaseAsyncObject, SSHVendor):
286
246
  key_filename: Optional path to private keyfile
287
247
  """
288
248
  import asyncssh
289
- from asyncssh.auth import MSG_USERAUTH_PK_OK, _ClientPublicKeyAuth
290
-
291
- # pylint: disable=protected-access
292
- _ClientPublicKeyAuth._packet_handlers[MSG_USERAUTH_PK_OK] = (
293
- _process_public_key_ok_gh
294
- )
295
249
 
296
250
  try:
297
251
  conn = await asyncssh.connect(
@@ -289,7 +289,9 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
289
289
  bare = True
290
290
  try:
291
291
  with RemoteCallbacks(progress=progress) as cb:
292
- repo = clone_repository(url, to_path, callbacks=cb, bare=bare)
292
+ repo = clone_repository(
293
+ url, os.fspath(to_path), callbacks=cb, bare=bare
294
+ )
293
295
  if mirror:
294
296
  cls._set_mirror(repo, progress=progress)
295
297
  except GitError as exc:
@@ -66,6 +66,8 @@ class RemoteCallbacks(_RemoteCallbacks, AbstractContextManager):
66
66
  else:
67
67
  creds = Credential(username=username_from_url, url=url).fill()
68
68
  self._store_credentials = creds
69
+ assert creds.username is not None
70
+ assert creds.password is not None
69
71
  return UserPass(creds.username, creds.password)
70
72
  except CredentialNotFoundError:
71
73
  pass
scmrepo/git/objects.py CHANGED
@@ -160,7 +160,7 @@ class GitTrie:
160
160
  }
161
161
  )
162
162
 
163
- return cast(dict, ret)
163
+ return cast("dict", ret)
164
164
 
165
165
 
166
166
  @dataclass
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: scmrepo
3
- Version: 3.3.10
3
+ Version: 3.3.11
4
4
  Summary: scmrepo
5
5
  Author-email: Iterative <support@dvc.org>
6
6
  License: Apache-2.0
@@ -38,12 +38,13 @@ Requires-Dist: pytest-sugar; extra == "tests"
38
38
  Requires-Dist: pytest-test-utils<0.2,>=0.1.0; extra == "tests"
39
39
  Requires-Dist: proxy.py; extra == "tests"
40
40
  Provides-Extra: dev
41
- Requires-Dist: mypy==1.14.1; extra == "dev"
41
+ Requires-Dist: mypy==1.15.0; extra == "dev"
42
42
  Requires-Dist: scmrepo[tests]; extra == "dev"
43
43
  Requires-Dist: types-certifi; extra == "dev"
44
44
  Requires-Dist: types-mock; extra == "dev"
45
45
  Requires-Dist: types-paramiko; extra == "dev"
46
46
  Requires-Dist: types-tqdm; extra == "dev"
47
+ Dynamic: license-file
47
48
 
48
49
  scmrepo
49
50
  =======
@@ -11,16 +11,16 @@ scmrepo/utils.py,sha256=_F3rVvPhES-A2JxLGob0RV8BOnHzxbA9aDPClA7_V8M,1512
11
11
  scmrepo/git/__init__.py,sha256=elQErQSqekg-XWfxjNmEV0X00xtvy0LDFvy9nmv71Ls,17187
12
12
  scmrepo/git/config.py,sha256=0t0OBmJ9SIa5tf22QdcGzhZfdMzzppvEmceUDg8ZPyE,943
13
13
  scmrepo/git/credentials.py,sha256=tn8TlyCJUz8HOF7eL6F5Yj4n9vREsFwXrjLU1isi13s,22312
14
- scmrepo/git/objects.py,sha256=vqeFpUlMFHL9Yv1h3wTA7mbRWHCVC_4KgLy5aAISD2g,4674
14
+ scmrepo/git/objects.py,sha256=qx8zAHZIrr0SDbZGD9wVShlMZK57nef8stIeRVqYdCU,4676
15
15
  scmrepo/git/stash.py,sha256=wKWnYj_xpdT_3pvHiXtE7_I_By4S-Zbxf4Lv-ZY2sxI,2785
16
16
  scmrepo/git/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  scmrepo/git/backend/base.py,sha256=nVMkUIeSVu-ZLCd2QPxMfTgrjnTOejM1UET9R7qKJRc,13560
18
18
  scmrepo/git/backend/gitpython.py,sha256=myfZY2x27DbDvIBUXzDjswXEViR5MKH0qgowwzcn7aY,25340
19
19
  scmrepo/git/backend/dulwich/__init__.py,sha256=7UJJyEPqgc2tfPs1WN_XdvRkMsGyFA1HVgTf7mrgLNE,35098
20
- scmrepo/git/backend/dulwich/asyncssh_vendor.py,sha256=clqsPC9ayulwgb5VLp-69hEbN9XMPvjh_0diBlH4wv4,11520
20
+ scmrepo/git/backend/dulwich/asyncssh_vendor.py,sha256=E3AyXok4S4FwsG9cMdswklf1bYRMmcmQM7Unri2fSVo,9882
21
21
  scmrepo/git/backend/dulwich/client.py,sha256=XjNBfOp0L8M3iPpqcX_4bmXsO7hwrkyqg5wMbZULD-I,2358
22
- scmrepo/git/backend/pygit2/__init__.py,sha256=pj9Naxq38JxjI0Aujknamqy4SV4g0Vy0tYN5kcuRbaU,36317
23
- scmrepo/git/backend/pygit2/callbacks.py,sha256=BFIFMzUpSC-CtNY50yTqksAusASgidzsQrG-B-Ry2lw,2749
22
+ scmrepo/git/backend/pygit2/__init__.py,sha256=7meRePoB_bUx0UY2wPm2nxI4DFabn5nenVP8Cyf7AZc,36366
23
+ scmrepo/git/backend/pygit2/callbacks.py,sha256=Mk-2e5dfJPNLsczRiK4rTnjHd5ZyonmegdwiFwM9Anc,2849
24
24
  scmrepo/git/backend/pygit2/filter.py,sha256=8Ibn_2oXM32YRpyovxGKYhtPZLUYTBLDi9--bScOP00,2198
25
25
  scmrepo/git/lfs/__init__.py,sha256=at5blRIKnKpg_g5dLRDsGWBFi6SbucRlF_DX6aAkGtE,257
26
26
  scmrepo/git/lfs/client.py,sha256=64u5lJijUASNJ4H_Eg7aEb8j3z3eluuNUWGnYvfNnvo,10187
@@ -31,8 +31,8 @@ scmrepo/git/lfs/pointer.py,sha256=BcVbtjoOUG9cEzyJSJDeweqehGZvq43P6NNLDYUGYEI,31
31
31
  scmrepo/git/lfs/progress.py,sha256=AcWvygDG0ee__Jec5BlRr58F-lAj3d4Z_j7JbW3OUcI,4733
32
32
  scmrepo/git/lfs/smudge.py,sha256=1O_fznptWo4CKXqcJgUoWP6cgWWhvGAZ3d87kasG3cQ,1610
33
33
  scmrepo/git/lfs/storage.py,sha256=nx_HvHHC1sf15Qgbsj8jEOkdHXkZ8VUEh8QBtt9sLwI,2348
34
- scmrepo-3.3.10.dist-info/LICENSE,sha256=-1jhbPjoIVHR0cEgahL4Zhct75Ff4MzYCR_jOaJDPq8,11340
35
- scmrepo-3.3.10.dist-info/METADATA,sha256=gUXgbfV8ouHPqtPHzpNQsJzPZPs5e4_yUwqBbj7ZoTU,4793
36
- scmrepo-3.3.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
- scmrepo-3.3.10.dist-info/top_level.txt,sha256=iunjod6w3GogERsAYfLRupnANXnqzX3jbIfbeIQG5cc,8
38
- scmrepo-3.3.10.dist-info/RECORD,,
34
+ scmrepo-3.3.11.dist-info/licenses/LICENSE,sha256=-1jhbPjoIVHR0cEgahL4Zhct75Ff4MzYCR_jOaJDPq8,11340
35
+ scmrepo-3.3.11.dist-info/METADATA,sha256=2edjOxEKBOCfYNiG_cFDExx5Q8P1eXQfrMTAtSlOzZ8,4815
36
+ scmrepo-3.3.11.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
37
+ scmrepo-3.3.11.dist-info/top_level.txt,sha256=iunjod6w3GogERsAYfLRupnANXnqzX3jbIfbeIQG5cc,8
38
+ scmrepo-3.3.11.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5