sync_pull(sftp, remote_path, local_directory, recursive=True, ignore=None, keep_tree=False)

Like rsync but with SFTP, to download files.

WARNING: at the moment, sync is only done based on names. An improvement is to take other parameters into acccount like hash or size.

Parameters:
  • sftp

    (sftputil.SFTP) the SFTP connection to use for sync.

  • remote_path

    (str|pathlib.Path) The remote path to sync. Can be a directory or a file.

  • local_directory

    (str|pathlib.Path) The local path where to sync the remote_path. Must be an existing directory.

  • recursive

    (bool) Whether to sync subdirectories as well.

  • ignore

    (regex str) a pattern to ignore some paths (matches the full path).

  • keep_tree

    (bool) If True, the whole directory path given in remote_path is created in local_directory. If False, only the leaf is synchronized. Default is False. Example: if remote_path is /dir1/dir2/dir3/file When keep_tree=True, the file is written on this local path: <local_directory>/dir1/dir2/dir3/file When keep_tree=False, the file is written on this local path: <local_directory>/file

Source code in sftputil/sync.py
def sync_pull(
    sftp,
    remote_path,
    local_directory,
    recursive=True,
    ignore=None,
    keep_tree=False,
):
    """Like rsync but with SFTP, to download files.

    WARNING: at the moment, sync is only done based on names. An improvement is to
    take other parameters into acccount like hash or size.

    Args:
        sftp: (sftputil.SFTP) the SFTP connection to use for sync.
        remote_path: (str|pathlib.Path) The remote path to sync. Can be a directory
            or a file.
        local_directory: (str|pathlib.Path) The local path where to sync the
            remote_path. Must be an existing directory.
        recursive: (bool) Whether to sync subdirectories as well.
        ignore: (regex str) a pattern to ignore some paths (matches the full path).
        keep_tree: (bool) If True, the whole directory path given in `remote_path`
            is created in `local_directory`. If False, only the leaf is
            synchronized. Default is False.
            Example:
                if `remote_path` is `/dir1/dir2/dir3/file`
                When keep_tree=True, the file is written on this local path:
                `<local_directory>/dir1/dir2/dir3/file`
                When keep_tree=False, the file is written on this local path:
                `<local_directory>/file`

    Raises:
        NotADirectoryError if `local_directory` is not a local directory.
        FileNotFoundError if the `remote_path` points to nothing.
    """
    remote_path = pathlib.PurePosixPath(remote_path)
    # Check the remote_path existence
    if not sftp.exists(remote_path):
        raise FileNotFoundError(f"'{remote_path}' not found on '{sftp.hostname}'")

    # Create the local directory if it does not exist
    local_base_dir = pathlib.Path(local_directory)
    if not local_base_dir.is_dir():
        raise NotADirectoryError(local_base_dir)

    # If remote_path is a file, just get it without walking
    if sftp.is_file(remote_path):
        _sync_pull_files(
            sftp,
            [remote_path.name],
            remote_path.parent,
            local_base_dir,
            remote_path,
            keep_tree,
            ignore,
        )
        return

    for walked_path, dirs, files in sftp.walk(remote_path):
        # Start by syncing files
        _sync_pull_files(
            sftp, files, walked_path, local_base_dir, remote_path, keep_tree, ignore
        )
        # If sync is not recursive, just stop there
        if not recursive:
            break
        # Create directories if necessary
        for dirname in dirs:
            local_dir_path = _build_local_path(
                local_base_dir, remote_path, walked_path, dirname, keep_tree
            )
            local_dir_path.mkdir(parents=True, exist_ok=True)