From 6073f46d63bc03a1a5967e8f4a9ab82ea11e310a Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:56:41 +0000 Subject: [PATCH 01/11] fix for drivedrop helper function to better handle all valid non-UNC style Windows paths --- sftpretty/__init__.py | 5 +---- sftpretty/helpers.py | 11 ++++------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 5b313c32..56496cdd 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -747,11 +747,8 @@ def get_r(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' - with self._sftp_channel(): - remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() - lwd = Path(localdir).absolute().as_posix() - rwd = remotedir + rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} tree[rwd] = [(rwd, lwd)] diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index 4ed65795..dd157f30 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -15,16 +15,16 @@ def _callback(filename, bytes_so_far, bytes_total, logger=None): else: print(message) - def drivedrop(filepath): if filepath: - if PureWindowsPath(filepath).drive: + if PureWindowsPath(filepath).drive and not filepath.startswith('//'): filepath = PurePosixPath('/').joinpath( - *PurePosixPath(filepath).parts[1:]).as_posix() + *PureWindowsPath(filepath).parts[1:]).as_posix() + filepath = filepath.encode('unicode_escape').decode() + filepath = filepath.replace('\\', '/').replace('//', '/') return filepath - def hash(filename, algorithm=sha3_512(), blocksize=65536): '''hash contents of a file, file like object or string @@ -57,7 +57,6 @@ def hash(filename, algorithm=sha3_512(), blocksize=65536): return algorithm.hexdigest() - def localtree(container, localdir, remotedir, recurse=True): '''recursively descend local directory mapping the tree to a dictionary container. @@ -100,7 +99,6 @@ def localtree(container, localdir, remotedir, recurse=True): except Exception as err: raise err - def retry(exceptions, tries=0, delay=3, backoff=2, silent=False, logger=None): '''Exception type based retry decorator for all your problematic functions @@ -173,7 +171,6 @@ def _retry(*args, **kwargs): return _retry return wrapper - def st_mode_to_int(val): '''SFTAttributes st_mode returns an stat type that shows more than what can be set. Trim off those bits and convert to an int representation. From 869b29df942fd0dac882539ea2ab709bfccd5266 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 04:37:51 +0000 Subject: [PATCH 02/11] removing unnecessary drivedrop calls, changing self._cache.cwd behavior to lookup default_path if one is not set before chdir'ing to better support relative paths --- sftpretty/__init__.py | 21 +++++++++++---------- sftpretty/helpers.py | 4 ++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 56496cdd..47bf68d4 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -328,10 +328,10 @@ def _sftp_channel(self): meta.settimeout(self._timeout) self._cache.__dict__.setdefault('cwd', self._default_path) - if self._cache.cwd: - channel.chdir(drivedrop(self._cache.cwd)) - else: - self._cache.cwd = '/' + if self._cache.cwd is None: + self._cache.cwd = channel.normalize('.') + + channel.chdir(self._cache.cwd) log.info(f'Current Working Directory: [{self._cache.cwd}]') yield channel @@ -957,6 +957,7 @@ def put_d(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' localdir = Path(localdir) + remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() self.mkdir_p(Path(remotedir).joinpath(localdir.parts[-1]).as_posix()) @@ -1043,7 +1044,7 @@ def put_r(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' lwd = Path(localdir).absolute().as_posix() - rwd = self.normalize(remotedir) + rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} tree[lwd] = [(lwd, rwd)] @@ -1189,7 +1190,7 @@ def chdir(self, remotepath): ''' with self._sftp_channel() as channel: channel.chdir(drivedrop(remotepath)) - self._cache.cwd = drivedrop(channel.normalize('.')) + self._cache.cwd = channel.normalize('.') def chmod(self, remotepath, mode=700): '''Set the permission mode of a remotepath, where mode is an octal. @@ -1277,7 +1278,7 @@ def getcwd(self): :returns: (str) Remote current working directory. None, if not set. ''' with self._sftp_channel() as channel: - cwd = drivedrop(channel.getcwd()) + cwd = channel.getcwd() return cwd @@ -1427,9 +1428,9 @@ def normalize(self, remotepath): :raises: IOError, if remotepath can't be resolved ''' with self._sftp_channel() as channel: - expanded_path = channel.normalize(drivedrop(remotepath)) + absolute_path = channel.normalize(drivedrop(remotepath)) - return drivedrop(expanded_path) + return absolute_path def open(self, remotefile, bufsize=-1, mode='r'): '''Open a file on the remote server. @@ -1613,7 +1614,7 @@ def pwd(self): :returns: (str) Current working directory. ''' with self._sftp_channel() as channel: - self._cache.cwd = drivedrop(channel.normalize('.')) + self._cache.cwd = channel.normalize('.') return self._cache.cwd diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index dd157f30..01acae82 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -25,6 +25,7 @@ def drivedrop(filepath): return filepath + def hash(filename, algorithm=sha3_512(), blocksize=65536): '''hash contents of a file, file like object or string @@ -57,6 +58,7 @@ def hash(filename, algorithm=sha3_512(), blocksize=65536): return algorithm.hexdigest() + def localtree(container, localdir, remotedir, recurse=True): '''recursively descend local directory mapping the tree to a dictionary container. @@ -99,6 +101,7 @@ def localtree(container, localdir, remotedir, recurse=True): except Exception as err: raise err + def retry(exceptions, tries=0, delay=3, backoff=2, silent=False, logger=None): '''Exception type based retry decorator for all your problematic functions @@ -171,6 +174,7 @@ def _retry(*args, **kwargs): return _retry return wrapper + def st_mode_to_int(val): '''SFTAttributes st_mode returns an stat type that shows more than what can be set. Trim off those bits and convert to an int representation. From 429b075ad14fbc2b29223c6fe38600d4cae7d1f3 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 05:06:48 +0000 Subject: [PATCH 03/11] fixing some test fallout from new self._cache.cwd behavior always setting the cwd, small lint fix for helper file --- sftpretty/__init__.py | 17 +++++++++++------ sftpretty/helpers.py | 1 + tests/test_getcwd.py | 2 +- tests/test_issue_65.py | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 47bf68d4..509722d3 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -643,7 +643,9 @@ def get_d(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' - remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() + with self._sftp_channel(): + remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() + filelist = self.listdir_attr(remotedir) if not Path(localdir).is_dir(): @@ -748,7 +750,8 @@ def get_r(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' lwd = Path(localdir).absolute().as_posix() - rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() + with self._sftp_channel(): + rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} tree[rwd] = [(rwd, lwd)] @@ -957,7 +960,8 @@ def put_d(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' localdir = Path(localdir) - remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() + with self._sftp_channel(): + remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() self.mkdir_p(Path(remotedir).joinpath(localdir.parts[-1]).as_posix()) @@ -1044,7 +1048,8 @@ def put_r(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' lwd = Path(localdir).absolute().as_posix() - rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() + with self._sftp_channel(): + rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} tree[lwd] = [(lwd, rwd)] @@ -1428,9 +1433,9 @@ def normalize(self, remotepath): :raises: IOError, if remotepath can't be resolved ''' with self._sftp_channel() as channel: - absolute_path = channel.normalize(drivedrop(remotepath)) + absolute = channel.normalize(drivedrop(remotepath)) - return absolute_path + return absolute def open(self, remotefile, bufsize=-1, mode='r'): '''Open a file on the remote server. diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index 01acae82..3273eb1d 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -15,6 +15,7 @@ def _callback(filename, bytes_so_far, bytes_total, logger=None): else: print(message) + def drivedrop(filepath): if filepath: if PureWindowsPath(filepath).drive and not filepath.startswith('//'): diff --git a/tests/test_getcwd.py b/tests/test_getcwd.py index 9caaadf6..4e922e69 100644 --- a/tests/test_getcwd.py +++ b/tests/test_getcwd.py @@ -11,7 +11,7 @@ def test_getcwd_none(sftpserver): cnn = conn(sftpserver) cnn['default_path'] = None with Connection(**cnn) as sftp: - assert sftp.getcwd() is None + assert sftp.getcwd() == '/' def test_getcwd_default_path(sftpserver): diff --git a/tests/test_issue_65.py b/tests/test_issue_65.py index 46c82fb0..99d86654 100644 --- a/tests/test_issue_65.py +++ b/tests/test_issue_65.py @@ -14,7 +14,7 @@ def test_issue_65(sftpserver): cnn = conn(sftpserver) cnn['default_path'] = None with Connection(**cnn) as sftp: - assert sftp.getcwd() is None + assert sftp.getcwd() == '/' with sftp.cd(pubpath.as_posix()): pass From dd6028797ab13608a2d8c927be3294b14041e7a4 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 05:12:23 +0000 Subject: [PATCH 04/11] trailing spaces in strange places --- sftpretty/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 509722d3..f13e0888 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -643,7 +643,7 @@ def get_d(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' - with self._sftp_channel(): + with self._sftp_channel(): remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() filelist = self.listdir_attr(remotedir) @@ -750,7 +750,7 @@ def get_r(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' lwd = Path(localdir).absolute().as_posix() - with self._sftp_channel(): + with self._sftp_channel(): rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} @@ -960,7 +960,7 @@ def put_d(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' localdir = Path(localdir) - with self._sftp_channel(): + with self._sftp_channel(): remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() self.mkdir_p(Path(remotedir).joinpath(localdir.parts[-1]).as_posix()) @@ -1048,7 +1048,7 @@ def put_r(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' lwd = Path(localdir).absolute().as_posix() - with self._sftp_channel(): + with self._sftp_channel(): rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() tree = {} From 5456cf6db9d6b8159200272f6a34d6b5c9f1e508 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 05:45:48 +0000 Subject: [PATCH 05/11] still need drivedrop around paramiko normalize calls --- sftpretty/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index f13e0888..93b7e9a2 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -329,7 +329,7 @@ def _sftp_channel(self): self._cache.__dict__.setdefault('cwd', self._default_path) if self._cache.cwd is None: - self._cache.cwd = channel.normalize('.') + self._cache.cwd = drivedrop(channel.normalize('.')) channel.chdir(self._cache.cwd) log.info(f'Current Working Directory: [{self._cache.cwd}]') @@ -1195,7 +1195,7 @@ def chdir(self, remotepath): ''' with self._sftp_channel() as channel: channel.chdir(drivedrop(remotepath)) - self._cache.cwd = channel.normalize('.') + self._cache.cwd = drivedrop(channel.normalize('.')) def chmod(self, remotepath, mode=700): '''Set the permission mode of a remotepath, where mode is an octal. @@ -1435,7 +1435,7 @@ def normalize(self, remotepath): with self._sftp_channel() as channel: absolute = channel.normalize(drivedrop(remotepath)) - return absolute + return drivedrop(absolute) def open(self, remotefile, bufsize=-1, mode='r'): '''Open a file on the remote server. @@ -1619,7 +1619,7 @@ def pwd(self): :returns: (str) Current working directory. ''' with self._sftp_channel() as channel: - self._cache.cwd = channel.normalize('.') + self._cache.cwd = drivedrop(channel.normalize('.')) return self._cache.cwd From bbe57103d27a88f75ae03fd28d4d8938d9d25cda Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 06:27:41 +0000 Subject: [PATCH 06/11] missed a few needed drivedrop calls --- sftpretty/__init__.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 93b7e9a2..5107bc51 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -331,7 +331,7 @@ def _sftp_channel(self): if self._cache.cwd is None: self._cache.cwd = drivedrop(channel.normalize('.')) - channel.chdir(self._cache.cwd) + channel.chdir(drivedrop(self._cache.cwd)) log.info(f'Current Working Directory: [{self._cache.cwd}]') yield channel @@ -643,9 +643,7 @@ def get_d(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' - with self._sftp_channel(): - remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() - + remotedir = self.normalize(remotedir) filelist = self.listdir_attr(remotedir) if not Path(localdir).is_dir(): @@ -750,8 +748,7 @@ def get_r(self, remotedir, localdir, callback=None, :raises: Any exception raised by operations will be passed through. ''' lwd = Path(localdir).absolute().as_posix() - with self._sftp_channel(): - rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() + rwd = self.normalize(remotedir) tree = {} tree[rwd] = [(rwd, lwd)] @@ -960,8 +957,7 @@ def put_d(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' localdir = Path(localdir) - with self._sftp_channel(): - remotedir = Path(self._cache.cwd).joinpath(remotedir).as_posix() + remotedir = self.normalize(remotedir) self.mkdir_p(Path(remotedir).joinpath(localdir.parts[-1]).as_posix()) @@ -1048,8 +1044,7 @@ def put_r(self, localdir, remotedir, callback=None, confirm=True, :raises OSError: if localdir doesn't exist ''' lwd = Path(localdir).absolute().as_posix() - with self._sftp_channel(): - rwd = Path(self._cache.cwd).joinpath(remotedir).as_posix() + rwd = self.normalize(remotedir) tree = {} tree[lwd] = [(lwd, rwd)] @@ -1283,7 +1278,7 @@ def getcwd(self): :returns: (str) Remote current working directory. None, if not set. ''' with self._sftp_channel() as channel: - cwd = channel.getcwd() + cwd = drivedrop(channel.getcwd()) return cwd From 61e8d3e9e2ae4680fc1a69e395acaa64e789f1ad Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:05:42 +0000 Subject: [PATCH 07/11] need additional shim in drivedrop to deal with os.path.isabs behavior change in python 3.13+, which paramiko uses in normalize calls --- sftpretty/helpers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index 3273eb1d..a1fd9e86 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -23,6 +23,8 @@ def drivedrop(filepath): *PureWindowsPath(filepath).parts[1:]).as_posix() filepath = filepath.encode('unicode_escape').decode() filepath = filepath.replace('\\', '/').replace('//', '/') + else if filepath.startswith('//'): + filepath = filepath.replace('//', '/') return filepath From a032cce2323c47984ef858edb3300530bf8b6a05 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:08:23 +0000 Subject: [PATCH 08/11] elif not else if in python duh --- sftpretty/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index a1fd9e86..1789bd77 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -23,7 +23,7 @@ def drivedrop(filepath): *PureWindowsPath(filepath).parts[1:]).as_posix() filepath = filepath.encode('unicode_escape').decode() filepath = filepath.replace('\\', '/').replace('//', '/') - else if filepath.startswith('//'): + elif filepath.startswith('//'): filepath = filepath.replace('//', '/') return filepath From fadd305c492f4081b997d1ae548cb33a12183824 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:25:26 +0000 Subject: [PATCH 09/11] now there's a trailing slash, wrapping the shim in PurePosixPath call --- sftpretty/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sftpretty/helpers.py b/sftpretty/helpers.py index 1789bd77..8233c246 100644 --- a/sftpretty/helpers.py +++ b/sftpretty/helpers.py @@ -24,7 +24,7 @@ def drivedrop(filepath): filepath = filepath.encode('unicode_escape').decode() filepath = filepath.replace('\\', '/').replace('//', '/') elif filepath.startswith('//'): - filepath = filepath.replace('//', '/') + filepath = PurePosixPath(filepath.replace('//', '/')).as_posix() return filepath From 979597ef8dfec9965fd00d277cb35e847f7ace50 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Wed, 11 Feb 2026 01:41:13 +0000 Subject: [PATCH 10/11] adding boolean posix to rename function to allowing switching between posix_rename and standard rename behavior. Added to existing rename test to include new codepath, version bump --- LICENSE | 2 +- docs/changes.rst | 12 +++++++++--- docs/conf.py | 6 +++--- pyproject.toml | 2 +- sftpretty/__init__.py | 9 ++++++--- tests/test_rename.py | 8 ++++++-- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/LICENSE b/LICENSE index df010701..bbf3c269 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2021, byteskeptical +Copyright (c) 2026, byteskeptical All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/docs/changes.rst b/docs/changes.rst index 3073d4ed..4feeff51 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,7 +1,13 @@ -1.2.0 (current, released 2025-12-21) ------------------------------------- +1.2.1 (current, released 2026-2-11) +----------------------------------- + * adding boolean to rename for switch between posix and standard behavior. + * change in default path behavior where cwd is set when default path is not. + * update drivedrop to better handle all non-UNC Windows path possibilities. + +1.2.0 (released 2025-12-21) +--------------------------- * fix for change in pathlib behavior in Python 3.13+ on Windows. - * fix for parsing limitation of .stem causing issues with dots in path names. + * fix for parsing limitation of .stem causing issue with dots in path names. 1.1.11 (released 2025-10-22) ---------------------------- diff --git a/docs/conf.py b/docs/conf.py index 1ec0b7fd..459455df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -47,16 +47,16 @@ # General information about the project. project = u'sftpretty' -copyright = u'2025, byteskeptical' +copyright = u'2026, byteskeptical' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '1.2.0' +version = '1.2.1' # The full version, including alpha/beta/rc tags. -release = '1.2.0' +release = '1.2.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 18381556..5f917831 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ keywords = [ name = 'sftpretty' readme = 'README.rst' requires-python = '>=3.6' -version = '1.2.0' +version = '1.2.1' [project.scripts] sftpretty = 'sftpretty:Connection' diff --git a/sftpretty/__init__.py b/sftpretty/__init__.py index 5107bc51..c566b5c6 100644 --- a/sftpretty/__init__.py +++ b/sftpretty/__init__.py @@ -1509,19 +1509,22 @@ def remove(self, remotefile): with self._sftp_channel() as channel: channel.remove(drivedrop(remotefile)) - def rename(self, remotepath, newpath): + def rename(self, remotepath, newpath, posix=True): '''Rename a path on the remote host. :param str remotepath: Remote path to rename. - :param str newpath: New name for remote path. + :param bool posix: *Default: True* - If set uses posix rename + extension behavior from OpenSSH otherwise fallback to standard + SFTP rename behavior. :returns: None :raises: IOError ''' with self._sftp_channel() as channel: - channel.posix_rename(drivedrop(remotepath), drivedrop(newpath)) + renamer = channel.posix_rename if posix else channel.rename + renamer(drivedrop(remotepath), drivedrop(newpath)) def rmdir(self, remotedir): '''Delete remote directory. diff --git a/tests/test_rename.py b/tests/test_rename.py index e10d5960..fd1ca3d0 100644 --- a/tests/test_rename.py +++ b/tests/test_rename.py @@ -13,10 +13,14 @@ def test_rename(lsftp): lsftp.remove(base_fname) assert base_fname not in lsftp.listdir() lsftp.put(fname) - lsftp.rename(base_fname, 'bob') + lsftp.rename(base_fname, 'alice') rdirs = lsftp.listdir() - assert 'bob' in rdirs + assert 'alice' in rdirs assert base_fname not in rdirs + lsftp.rename(base_fname, 'bob', posix=False) + rdirs = lsftp.listdir() + assert 'alice' not in rdirs + assert 'bob' in rdirs lsftp.remove('bob') From b4ac0f5600731eed68db3843bb350fcf43841014 Mon Sep 17 00:00:00 2001 From: byteskeptical <40208858+byteskeptical@users.noreply.github.com> Date: Wed, 11 Feb 2026 02:48:54 +0000 Subject: [PATCH 11/11] got caught up in the rename game, have to use the new name instead of base name --- tests/test_rename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_rename.py b/tests/test_rename.py index fd1ca3d0..f559a5f1 100644 --- a/tests/test_rename.py +++ b/tests/test_rename.py @@ -17,7 +17,7 @@ def test_rename(lsftp): rdirs = lsftp.listdir() assert 'alice' in rdirs assert base_fname not in rdirs - lsftp.rename(base_fname, 'bob', posix=False) + lsftp.rename('alice', 'bob', posix=False) rdirs = lsftp.listdir() assert 'alice' not in rdirs assert 'bob' in rdirs