Skip to main content

Filesystem operations

The Python SDK reads, writes, lists, moves, and deletes files and directories in a LucidLink filespace. File handles implement Python's standard io interfaces, so code written for local files works with filespace files.

Availability. The examples on this page assume a logged-in client and a linked filespace, set up as in Getting started.

Supported operations

Capability

Description

Read

Read file contents and metadata from any path in the filespace. Stream large files in chunks instead of reading them into memory whole.

Write

Write files to the filespace from your Python application — for example to populate project structures, generate reports, or import data from other systems.

List

List the files and subdirectories of any directory, with or without their metadata — for example to build file manifests or audit content.

Delete

Delete files, empty directories, or whole directory trees — for example for cleanup tasks or archive rotation.

Move

Move or rename files and directories within the filespace. A move is a single native operation, not a copy followed by a delete.

Copy

Copy files with the fsspec file system (fs.cp), within a filespace or across filespaces. There is no native copy: the SDK streams the file content to the new path.

Read

Description

Read file contents and metadata from any path in the filespace. Stream large files in chunks instead of reading them into memory whole.

Write

Description

Write files to the filespace from your Python application — for example to populate project structures, generate reports, or import data from other systems.

List

Description

List the files and subdirectories of any directory, with or without their metadata — for example to build file manifests or audit content.

Delete

Description

Delete files, empty directories, or whole directory trees — for example for cleanup tasks or archive rotation.

Move

Description

Move or rename files and directories within the filespace. A move is a single native operation, not a copy followed by a delete.

Copy

Description

Copy files with the fsspec file system (fs.cp), within a filespace or across filespaces. There is no native copy: the SDK streams the file content to the new path.

Work with files and directories

filespace.file_system provides the file system operations. FsUtils adds one-call helpers on top, such as reading or writing a whole file and deleting a directory tree.

Read and write whole files

from lucidlink import FsUtils
fs_utils = FsUtils(filespace.file_system)
fs_utils.write_bytes("/hello.txt", b"Hello, world!")
content = fs_utils.read_bytes("/hello.txt")print(content)  # b"Hello, world!"

Create and list directories

# create_dir() creates one level: create the parents firstfilespace.file_system.create_dir("/projects")filespace.file_system.create_dir("/projects/2024")
# Names onlynames = [e.name for e in filespace.file_system.read_dir("/projects")]print(names)  # ["2024"]
# Full metadatafor entry in filespace.file_system.read_dir("/projects"):    print(f"{entry.name}: {entry.size} bytes")

Delete and move

from lucidlink import FsUtils
filespace.file_system.delete("/hello.txt")filespace.file_system.delete_dir("/projects/2024")  # Directory must be emptyFsUtils(filespace.file_system).delete_tree("/projects")
filespace.file_system.move("/old_name.txt", "/new_name.txt")

Check existence and read metadata

from lucidlink import FsUtils
# A missing path raises FileNotFoundErrortry:    data = FsUtils(filespace.file_system).read_bytes("/config.json")except FileNotFoundError:    data = None
try:    entries = filespace.file_system.read_dir("/backups")except FileNotFoundError:    entries = []
info = filespace.file_system.get_entry("/report.pdf")print(f"Size: {info.size}, Type: {info.type}")print(f"Modified (ns since epoch): {info.modified_at}")
# Counters for the whole file systemstats = filespace.file_system.statistics()print(f"Entries: {stats.entries_count}, Storage: {stats.storage_size} bytes")

Stream file contents

file_system.open() returns a stream compatible with io.RawIOBase. It supports buffered and text modes, seeking, and chunked reads and writes.

# Binary streaming (read)with filespace.file_system.open("/large_file.dat", "rb", buffering=8192) as f:    for chunk in iter(lambda: f.read(4096), b""):        process(chunk)
# Text streaming with an encoding (read)with filespace.file_system.open("/document.txt", "rt", encoding="utf-8") as f:    for line in f:        print(line.strip())
# Byte-range read: 100 bytes from offset 1000with filespace.file_system.open("/data.bin", "rb") as f:    f.seek(1000)    data = f.read(100)
# Streaming writesdata = b"x" * 1024 * 1024with filespace.file_system.open("/output.dat", "wb") as f:    for i in range(10):        f.write(data)

Use fsspec and pandas

The Python SDK registers the lucidlink:// protocol with fsspec. A path has the form lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/path, and libraries that work with fsspec, such as pandas, read and write filespace files with it. PyArrow does not open these URLs: give it a LucidLinkFileSystem as filesystem. fsspec support is an optional extra:

pip install "lucidlink[fsspec]"

fsspec file system

from lucidlink.fsspec import LucidLinkFileSystem
fs = LucidLinkFileSystem(token="<SECRET_KEY>")
entries = fs.ls("lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/", detail=True)
# Download and uploadfs.get(    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/file.txt",    "local_file.txt",)fs.put(    "local_file.txt",    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/uploaded.txt",)
# A native move, not a copy followed by a delete. An existing file at the# destination is replaced; an existing directory receives the source.fs.mv(    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/old.txt",    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/new.txt",)
# mv takes one path, never a glob or a list: move each match into an# existing directory. A trailing slash does not make mv move into a# directory, so create it first; otherwise every match overwrites the last.root = "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>"fs.makedirs(f"{root}/archive", exist_ok=True)for path in fs.glob(f"{root}/staging/*.csv"):    fs.mv(path, f"{root}/archive/")
# Modification and creation times as timezone-aware UTC datetimesfs.modified("lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/new.txt")fs.created("lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/new.txt")
fs.mkdir("lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/new_dir")fs.rmdir("lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/empty_dir")
fs.close()

By default, writing into a missing directory through a LucidLinkFileSystem method, such as fs.open(path, "wb"), raises FileNotFoundError. Pass auto_mkdir=True, or storage_options={"auto_mkdir": True}, to create missing parent directories on write. The SDK creates only missing directories inside the filespace, and only on a write: reading a file from a missing directory still raises FileNotFoundError.

Each LucidLinkFileSystem instance is a separate client, and fsspec creates one instance per thread, per process, and per set of storage options, including auto_mkdir. Clients see each other's changes only after a delay, so read with the same storage options you write with. After fs.close(), every call on that instance raises ClientClosedError; create a new instance for further work.

Worker processes started with the fork start method cannot use LucidLink while a client runs in the parent: every call raises ClientError. Use the spawn or forkserver start method instead.

pandas

import pandas as pd
df = pd.read_csv(    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/data.csv",    storage_options={"token": "<SECRET_KEY>"},)
df.to_parquet(    "lucidlink://<WORKSPACE_NAME>/<FILESPACE_NAME>/output.parquet",    storage_options={"token": "<SECRET_KEY>"},)