Skip to content

Commit 177b9bb

Browse files
Merge pull request #79 from byteskeptical/name_game
Name Game
2 parents 6cb55b1 + 5f08414 commit 177b9bb

8 files changed

Lines changed: 67 additions & 23 deletions

File tree

.github/workflows/document.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ jobs:
2020

2121
steps:
2222
- name: Clone Repository
23-
uses: actions/checkout@v3
23+
uses: actions/checkout@v6
2424
- name: Python ${{ matrix.python-version }}
25-
uses: actions/setup-python@v3
25+
uses: actions/setup-python@v6
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828
- name: Build

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ jobs:
1818

1919
steps:
2020
- name: Clone Repository
21-
uses: actions/checkout@v3
21+
uses: actions/checkout@v6
2222
with:
2323
fetch-depth: 0
2424
- name: Python ${{ matrix.python-version }}
25-
uses: actions/setup-python@v3
25+
uses: actions/setup-python@v6
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828
- name: Dependencies

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ jobs:
2222

2323
steps:
2424
- name: Clone Repository
25-
uses: actions/checkout@v3
25+
uses: actions/checkout@v6
2626
- name: Python ${{ matrix.python-version }}
27-
uses: actions/setup-python@v3
27+
uses: actions/setup-python@v6
2828
with:
2929
python-version: ${{ matrix.python-version }}
3030
- name: ${{ matrix.os }} SSH

docs/changes.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
1.2.1 (current, released 2026-2-11)
1+
1.2.2 (current, released 2026-5-10)
22
-----------------------------------
3+
* adding new test for _sftp_channel exception handling.
4+
* adding curve25519-sha256@libssh.org to kex list.
5+
* fix for UnboundLocalError on a certain exception in _sftp_channel.
6+
* removing diffie-hellman-group-exchange-sha1 from kex list per paramiko.
7+
* removing ssh-rsa from public key type list per paramiko.
8+
9+
1.2.1 (released 2026-2-11)
10+
--------------------------
311
* adding boolean to rename for switch between posix and standard behavior.
412
* change in default path behavior where cwd is set when default path is not.
513
* update drivedrop to better handle all non-UNC Windows path possibilities.

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
# built documents.
5555
#
5656
# The short X.Y version.
57-
version = '1.2.1'
57+
version = '1.2.2'
5858
# The full version, including alpha/beta/rc tags.
59-
release = '1.2.1'
59+
release = '1.2.2'
6060

6161
# The language for content autogenerated by Sphinx. Refer to documentation
6262
# for a list of supported languages.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ keywords = [
4848
name = 'sftpretty'
4949
readme = 'README.rst'
5050
requires-python = '>=3.6'
51-
version = '1.2.1'
51+
version = '1.2.2'
5252

5353
[project.scripts]
5454
sftpretty = 'sftpretty:Connection'

sftpretty/__init__.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ def __init__(self, config=None, knownhosts=Path(
7474
'hmac-sha1', 'hmac-md5')
7575
self.disabled_algorithms = {}
7676
self.hostkeys = hostkeys.HostKeys()
77-
self.kex = ('ecdh-sha2-nistp521', 'ecdh-sha2-nistp384',
78-
'ecdh-sha2-nistp256', 'diffie-hellman-group16-sha512',
77+
self.kex = ('curve25519-sha256@libssh.org', 'ecdh-sha2-nistp521',
78+
'ecdh-sha2-nistp384', 'ecdh-sha2-nistp256',
79+
'diffie-hellman-group16-sha512',
7980
'diffie-hellman-group-exchange-sha256',
80-
'diffie-hellman-group-exchange-sha1')
81+
'diffie-hellman-group14-sha256')
8182
self.key_types = ('ssh-ed25519', 'ecdsa-sha2-nistp521',
8283
'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp256',
83-
'rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa')
84+
'rsa-sha2-512', 'rsa-sha2-256')
8485
self.log = False
8586
self.log_level = 'info'
8687
self.ssh_config = SSHConfig()
@@ -300,24 +301,26 @@ def _sftp_channel(self):
300301
channel = None
301302
fatal = False
302303

304+
self._cache.__dict__.setdefault('cwd', self._default_path)
305+
303306
try:
304307
channel_name, data = next(
305308
(key, value)
306309
for key, value in self._channels.items()
307-
if not value['busy']
310+
if not value['busy'] and not value['meta'].closed
308311
)
312+
313+
channel = data['channel']
309314
meta = data['meta']
310-
if not meta.closed:
311-
channel = data['channel']
312-
self._channels[channel_name]['busy'] = True
313-
log.debug(f'Cached Channel: [{channel_name}]')
315+
self._channels[channel_name]['busy'] = True
316+
log.debug(f'Cached Channel: [{channel_name}]')
314317
except StopIteration:
315318
pass
316319

317320
try:
318321
if channel is None:
319-
channel = SFTPClient.from_transport(self._transport)
320322
channel_name = uuid4().hex
323+
channel = SFTPClient.from_transport(self._transport)
321324
meta = channel.get_channel()
322325
meta.set_name(channel_name)
323326
log.debug(f'Channel Name: [{channel_name}]')
@@ -326,7 +329,6 @@ def _sftp_channel(self):
326329
}
327330

328331
meta.settimeout(self._timeout)
329-
self._cache.__dict__.setdefault('cwd', self._default_path)
330332

331333
if self._cache.cwd is None:
332334
self._cache.cwd = drivedrop(channel.normalize('.'))
@@ -344,6 +346,7 @@ def _sftp_channel(self):
344346
log.error(_message)
345347
raise TimeoutError(_message)
346348
except SFTPError as err:
349+
code = err.args[0] if err.args else None
347350
_message_map = {
348351
SFTP_FAILURE: (
349352
'A generic failure occurred on the SFTP server for path: '
@@ -361,9 +364,9 @@ def _sftp_channel(self):
361364
),
362365
}
363366
_message = _message_map.get(
364-
err.errno,
367+
code,
365368
('Unhandled SFTP error on directory change to '
366-
f'[{self._cache.cwd}] (Code {err.errno}): {err}')
369+
f'[{self._cache.cwd}] (Code {code}): {err}')
367370
)
368371
log.error(_message)
369372
raise err

tests/test_connection.py

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

33
import pytest
44

5+
from paramiko import SFTPError
56
from paramiko.ed25519key import Ed25519Key
67

78
from common import conn, LOCAL, VFS
@@ -10,6 +11,38 @@
1011
HostKeysException, SSHException)
1112

1213

14+
def test_channel_exception(sftpserver):
15+
'''test except blocks in _sftp_channel don't raise secondary errors'''
16+
with sftpserver.serve_content(VFS):
17+
with Connection(**conn(sftpserver)) as sftp:
18+
sftp.close()
19+
with pytest.raises(AttributeError):
20+
sftp.listdir()
21+
22+
with sftpserver.serve_content(VFS):
23+
with Connection(**conn(sftpserver)) as sftp:
24+
with pytest.raises(OSError):
25+
sftp.chdir('/does/not/exist')
26+
27+
with sftpserver.serve_content(VFS):
28+
with Connection(**conn(sftpserver)) as sftp:
29+
with pytest.raises(SFTPError):
30+
sftp.chdir('/home/test/read.me')
31+
32+
with sftpserver.serve_content(VFS):
33+
sftp = Connection(**conn(sftpserver))
34+
sftp._transport.close()
35+
with pytest.raises(SSHException):
36+
sftp.listdir()
37+
38+
with sftpserver.serve_content(VFS):
39+
with Connection(**conn(sftpserver)) as sftp:
40+
sftp.timeout = 0.0001
41+
with pytest.raises(TimeoutError,
42+
match='operation timed out after'):
43+
sftp.listdir()
44+
45+
1346
def test_cnopts_bad_knownhosts():
1447
'''test setting knownhosts to a not understood file'''
1548
with pytest.raises(HostKeysException):

0 commit comments

Comments
 (0)