Skip to main content

sshdol

A Python dict-like interface to SSH files, built on dol (Data Object Layer).

What is sshdol?

sshdol provides a familiar mapping (dict-like) interface to interact with files on remote servers via SSH. Instead of dealing with low-level SSH operations, you can interact with remote files just like you would with Python dictionaries:

s["file.txt"] = b"content"  # Write to a file
content = s["file.txt"]  # Read from a file
"file.txt" in s  # Check if file exists
list(s)  # List all files and directories

Why use sshdol?

dol helps create key-value facades to data sources and systems that have Python builtin interfaces. This offers a consistent, easy, and familiar interface to various systems, making it healthier for your code and your developer sanity.

Installation

pip install sshdol

Quick Start

To use sshdol, you need access to an SSH server and appropriate credentials.

from sshdol.base import SshFiles, SshTextFiles

# Connect to a server (several authentication methods supported)
s = SshFiles(host="myserver", rootdir="/path/to/safe/directory")

# Write binary data to a file
s["example.bin"] = b"binary content"

# Read the file
content = s["example.bin"]  # Returns b'binary content'

# List files and directories
files = list(s)  # Returns [..., 'example.bin', ...]

# Check if a file exists
if "example.bin" in s:
    print("File exists!")

Features

Fast sync (to local folder)

There are two ways to copy/sync a remote SSH directory into a local folder.

  • Mapping-based (simple but slow on many files):
import dol
from sshdol.base import SshFiles

src = SshFiles(host="myserver", rootdir="/remote/path")
target = dol.Files("/local/target/folder")

# This works and preserves dol’s familiar Mapping API, but can be very slow
target.update(src)

You can also use higher-level helpers such as xdol.update_with_policy to control sync behavior (e.g., mirror vs copy), but the round-trips remain expensive for large trees. (Note: Both of these are applicable to any Mapping instance src and MutableMapping instance target.)

  • High-performance (recommended for many files):

Use sshdol.sync_to(src, target), which leverages rsync under the hood for orders-of-magnitude faster syncs. It only supports local folder targets (a path).

from sshdol import SshFiles, sync_to

src = SshFiles(host="myserver", rootdir="/remote/path")

# Sync to a local path (fast; uses rsync)
sync_to(src, "/local/target/folder")

# A pathlib.Path works too. An object with a .rootdir (even a dol.Files) is refused:
# its view may be narrower than its rootdir, and --delete would prune the rest.

Notes:

  • Requires rsync installed locally.
  • sync_to is scoped by the store's rootdir, not by any key view (this is why it is a free function: SshFiles.sync_to was removed, because a method of a dol-wrapped store runs on the leaf, i2mint/sshdol#6). It therefore refuses a store wrapped in a dol key codec or filter (WrappedStoreError), since it would copy files the view hides and --delete against the wrong tree. State a sub-scope explicitly: sync_to(src, "/local/dir", subdir="projects"). The target must be a path (for a dol.Files target, pass its directory).
  • Target must be a local filesystem path.
  • You can control deletion timing and safety:
# Remove local files not present on remote (mirror behavior)
sync_to(
    src,
    "/local/target/folder",
    delete_local_files_not_in_remote=True,
    delete_mode="during",  # 'before' | 'after' | 'delay' | 'during'
)

# “Recycle” deletions instead of permanently deleting them
sync_to(
    src,
    "/local/target/folder",
    delete_mode="recycle",  # uses rsync --backup/--backup-dir
    recycle_bin="~/.Trash",  # optional (defaults OS-specifically)
)

Compared to target.update(src), sync_to performs a single rsync negotiation and transfers only changed file blocks, making it dramatically faster on large trees.

Binary and Text Mode

sshdol provides both binary and text interfaces:

# Binary mode (default)
s = SshFiles(host="myserver", rootdir="/path/to/directory")
s["file.txt"] = b"binary content"

# Text mode
t = SshTextFiles(host="myserver", rootdir="/path/to/directory")
t["file.txt"] = "text content"  # Automatically handles encoding/decoding

Recursive Directory Support

Navigate through directories and access nested files with slash-separated paths:

# Create a store with unlimited depth and directory creation
s = SshFiles(
    host="myserver",
    rootdir="/path/to/directory",
    max_levels=None,  # Unlimited recursion for listing
    create_dirs=True,  # Create directories as needed
)

# Write to a deeply nested path (creates directories if they don't exist)
s["dir1/dir2/dir3/file.txt"] = b"nested content"

# Read from the nested path
content = s["dir1/dir2/dir3/file.txt"]  # Returns b'nested content'

# List will show all files and directories recursively
all_files = list(
    s
)  # [..., 'dir1/', 'dir1/dir2/', 'dir1/dir2/dir3/', 'dir1/dir2/dir3/file.txt', ...]

Directory Navigation

Navigate through directories by accessing folders like dictionary keys:

# Get a store instance for a subdirectory
subdir = s["dir1/"]

# List only files in the subdirectory
subdir_files = list(subdir)  # [..., 'dir2/', ...]

# Navigate further
subsubdir = subdir["dir2/"]

Recursion Control

Control the depth of directory recursion:

# Only show top-level files and directories
s0 = SshFiles(host="myserver", max_levels=0)
files_level0 = list(s0)  # [..., 'dir1/', 'file.txt', ...]

# Show files up to one level deep
s1 = SshFiles(host="myserver", max_levels=1)
files_level1 = list(s1)  # [..., 'dir1/', 'dir1/file.txt', 'dir1/dir2/', ...]

Directory Creation

Automatically create directories when writing to nested paths:

# Create directories as needed when writing
s = SshFiles(host="myserver", create_dirs=True)

# This will create all necessary directories
s["new/path/to/file.txt"] = b"content with auto-created directories"

Authentication Options

sshdol supports multiple SSH authentication methods:

# Using SSH config alias (simplest if you have ~/.ssh/config set up)
s = SshFiles(host="myserver")

# Using username/password
s = SshFiles(user="username", password="password", url="example.com")

# Using SSH key
s = SshFiles(user="username", url="example.com", key_filename="~/.ssh/id_rsa")

Advanced Examples

Working with text files

# Create a text file store
t = SshTextFiles(host="myserver")

# Write a text file
t["notes.txt"] = "Hello, this is a text note"

# Read it back
text = t["notes.txt"]  # Returns 'Hello, this is a text note'

Creating a new directory

Now, know that you can make a directory with sshdol.mkdir(store, path), after which it can be written in. (It is a function rather than a method so that it maps the key through any dol key codec you have wrapped the store in; the old SshFiles.mkdir method was removed, i2mint/sshdol#6.)

from sshdol import mkdir

# Create a new directory
mkdir(s, "projects")
projects_dir = s["projects"]

# Write files in the new directory
projects_dir["README.md"] = b"# Projects Directory"

But if you specify create_dirs=True, you are allowing the store to make these directories automatically, at the moment you want to write in them (sort of like what github and some blob storage systems do):

# Create a store with directory creation enabled
s = SshFiles(host="myserver", create_dirs=True)

s["some_folder/that/did/not/exist/README.md"] = b"Write me!"

Handling large directory structures

# Create a store with limited recursion for better performance
s = SshFiles(host="myserver", max_levels=2)

# List files up to 2 levels deep
files = list(s)  # [..., 'dir1/', 'dir1/dir2/', 'dir1/dir2/file.txt', ...]

# You can still access deeper files directly
deep_content = s["dir1/dir2/dir3/dir4/file.txt"]

License

MIT

Metadata

Release files for sshdol 0.0.13

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sshdol 0.0.13
File Size Uploaded
sshdol-0.0.13.tar.gz 43.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sshdol 0.0.13
File Interpreter ABI Platform
sshdol-0.0.13-py3-none-any.whl Python 3 none any Details

Total release size: 80.7 kB

Release files / sshdol-0.0.13.tar.gz

Download URL sshdol-0.0.13.tar.gz
Size 43.8 kB
Tags Source
SHA-256 checksum
How to use checksums
44be2c4736a245da72b2f60e620c4ff4c64432066ccde17d8bffb1bae87b1790
BLAKE2b-256 checksum
How to use checksums
2750c0a42b43436302d84edfc3bc91004ffe4dbf037ec456d3afe2df40fbc570
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / sshdol-0.0.13-py3-none-any.whl

Download URL sshdol-0.0.13-py3-none-any.whl
Size 36.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67c0e04654d7180c057ce8db59e247a03e500afc1bb62dd33eeef20d7dfd2428
BLAKE2b-256 checksum
How to use checksums
fa19b2b39895eef831760a9042ba63266badd3f6eac2cc93130ba95dd57c510b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.0.15

2 release files

0.0.14

2 release files

This release

0.0.13 This release

2 release files

0.0.12

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

1 release file

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page