Skip to main content
from declaw import Sandbox, EntryInfo, WriteInfo, WriteEntry, FileType, FilesystemEvent
sbx.files is the Filesystem sub-module available on every Sandbox instance. All paths must be absolute paths within the sandbox filesystem.

sbx.files.read()

Read a file’s content from the sandbox.
# Read as text (default)
content: str = sbx.files.read("/home/user/script.py")

# Read as bytes
raw: bytearray = sbx.files.read("/data/image.png", format="bytes")

# Read as a streaming iterator
stream = sbx.files.read("/data/large_file.bin", format="stream")
for chunk in stream:
    process(chunk)
path
str
required
Absolute path inside the sandbox.
format
str
default:"'text'"
Output format. One of "text" (returns str), "bytes" (returns bytearray), or "stream" (returns Iterator[bytes]).
user
str
default:"'user'"
Unix user context for the read operation.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns str | bytearray | Iterator[bytes]

sbx.files.write()

Write content to a file. Creates parent directories automatically.
info: WriteInfo = sbx.files.write(
    "/home/user/hello.py",
    "print('hello from sandbox')",
)
print(info.path, info.size)
path
str
required
Absolute path inside the sandbox. Parent directories are created if they do not exist.
data
str | bytes | IO
required
Content to write. Accepts a string, bytes object, or any file-like object with a read() method.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns WriteInfo

sbx.files.write_files()

Write multiple files in a single batch request. More efficient than calling write() in a loop.
from declaw import WriteEntry

results = sbx.files.write_files([
    WriteEntry(path="/home/user/main.py", data="import sys\nprint(sys.argv)"),
    WriteEntry(path="/home/user/data.json", data='{"key": "value"}'),
])
files
list[WriteEntry]
required
List of WriteEntry objects. Each has path (str) and data (str or bytes).
user
str
default:"'user'"
Unix user context applied to all files.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns list[WriteInfo]

sbx.files.list()

List the contents of a directory.
entries: list[EntryInfo] = sbx.files.list("/home/user", depth=2)
for e in entries:
    print(e.type.value, e.path, e.size)
path
str
required
Absolute path to the directory.
depth
int | None
default:"1"
Recursion depth. 1 lists only the immediate children of the directory. None or a larger value recurses deeper.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns list[EntryInfo]

sbx.files.exists()

Check whether a file or directory exists.
if sbx.files.exists("/home/user/output.csv"):
    content = sbx.files.read("/home/user/output.csv")
path
str
required
Absolute path to check.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns bool

sbx.files.get_info()

Get metadata about a single file or directory entry.
info: EntryInfo = sbx.files.get_info("/home/user/script.py")
print(info.name, info.type, info.size)
path
str
required
Absolute path to query.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns EntryInfo

sbx.files.remove()

Remove a file or directory.
sbx.files.remove("/home/user/temp_output.txt")
path
str
required
Absolute path to remove.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns None

sbx.files.rename()

Rename or move a file or directory.
new_entry: EntryInfo = sbx.files.rename(
    "/home/user/draft.py",
    "/home/user/final.py",
)
old_path
str
required
Current absolute path.
new_path
str
required
New absolute path. Can be a different directory (move semantics).
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns EntryInfo for the renamed entry.

sbx.files.make_dir()

Create a directory (including parent directories if needed).
created = sbx.files.make_dir("/home/user/output/results")
path
str
required
Absolute path of the directory to create.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
Returns boolTrue if the directory was created.

sbx.files.watch_dir()

Watch a directory for filesystem events. Returns a WatchHandle that receives events from the sandbox.
handle: WatchHandle = sbx.files.watch_dir(
    "/home/user/data",
    recursive=True,
)
path
str
required
Absolute path of the directory to watch.
user
str
default:"'user'"
Unix user context.
request_timeout
float | None
default:"None"
Per-request HTTP timeout in seconds.
recursive
bool
default:"False"
Watch the directory and all subdirectories recursively.
Returns WatchHandle

Data models

EntryInfo

@dataclass
class EntryInfo:
    name: str          # Filename or directory name
    path: str          # Full absolute path
    type: FileType     # FileType.FILE or FileType.DIR
    size: int = 0      # Size in bytes (0 for directories)

FileType

class FileType(str, Enum):
    FILE = "file"
    DIR  = "dir"

WriteInfo

@dataclass
class WriteInfo:
    path: str      # Absolute path of the written file
    size: int = 0  # Bytes written

WriteEntry

@dataclass
class WriteEntry:
    path: str               # Absolute destination path
    data: str | bytes       # Content to write

FilesystemEvent

@dataclass
class FilesystemEvent:
    type: FilesystemEventType
    path: str
    timestamp: float | None = None

FilesystemEventType

class FilesystemEventType(str, Enum):
    CREATE = "create"
    WRITE  = "write"
    REMOVE = "remove"
    RENAME = "rename"
    CHMOD  = "chmod"

WatchHandle

class WatchHandle:
    def stop(self) -> None: ...
    def get_new_events(self) -> list[FilesystemEvent]: ...
The handle uses a poll-and-drain model — call get_new_events() to pull buffered events. There is no iterator protocol or callback subscription.

Examples

Upload and execute a script

sbx.files.write("/home/user/analyze.py", open("local_analyze.py").read())
result = sbx.commands.run("python3 /home/user/analyze.py")
print(result.stdout)

Batch upload a dataset

from declaw import WriteEntry
import pathlib

entries = [
    WriteEntry(path=f"/data/{f.name}", data=f.read_bytes())
    for f in pathlib.Path("./dataset").iterdir()
    if f.is_file()
]
sbx.files.write_files(entries)

Download generated output

sbx.commands.run("python3 -c \"open('/tmp/out.csv','w').write('a,b\\n1,2')\"")
csv_content = sbx.files.read("/tmp/out.csv")
with open("local_out.csv", "w") as f:
    f.write(csv_content)