skills/latchbio-integration/references/data-management.md
This reference distinguishes the two supported Python data models:
LPath is the modern, pathlib-like API for explicit remote operations.LatchFile and LatchDir are the established workflow parameter types for
automatic task staging and output upload.Do not assume methods from one model exist on the other. In particular,
LatchDir.glob() is not a current SDK API.
Use LPath when you need to:
LPath value in Registry with SDK 2.67.22+Use LatchFile or LatchDir when you need to:
latch.verified wrappersIt is normal to accept a LatchFile in a workflow and construct an LPath
from its remote_path for a targeted remote operation.
Common forms include:
latch:///path/in/current-workspace
latch://12345.account/path/in/workspace
latch://shared/path/to/shared-data
latch://67890.node
latch:///... resolves relative to the active or execution workspace.Do not concatenate URLs with filesystem utilities that discard the URL scheme.
LPath supports / for child paths.
LPathImport it from its actual module:
from latch.ldata.path import LPath
from latch.ldata.path import LPath
root = LPath("latch:///welcome")
if root.exists():
print(root.node_id())
print(root.name())
print(root.is_dir())
print(root.size_recursive())
for child in root.iterdir():
print(child.path, child.content_type(), child.size())
iterdir() is shallow. It returns an iterator of child LPath objects and
does not recursively traverse nested directories.
Metadata is cached for the lifetime of the object after a lookup. Call
fetch_metadata() after an external rename or modification when fresh values
are required.
Always provide an explicit destination for durable files:
from pathlib import Path
from latch.ldata.path import LPath
remote = LPath("latch:///inputs/design.csv")
local = remote.download(Path("work/design.csv"), cache=True)
print(local.read_text(encoding="utf-8"))
Without a destination, the SDK downloads beneath ~/.latch/lpath/ and
registers the temporary directory for cleanup when the process exits. Do not
rely on that path after process termination.
With cache=True, the SDK uses the remote version identifier and local extended
attributes where supported. Explicit paths plus caching are especially
important in long-lived Pods and Plots.
The destination's parent must exist:
from pathlib import Path
from latch.ldata.path import LPath
destination_dir = LPath("latch:///results/run-001")
destination_dir.mkdirp()
report = destination_dir / "report.txt"
report.upload_from(Path("report.txt"))
upload_from accepts either a local file or directory. Avoid concurrent writes
to the same destination.
from latch.ldata.path import LPath
source = LPath("latch:///results/run-001/report.txt")
backup = LPath("latch:///archive/run-001/report.txt")
source.copy_to(backup)
Deletion is recursive and destructive:
target = LPath("latch:///scratch/run-001")
target.rmr()
Before rmr():
LatchFile and LatchDirThese types carry both a local execution path and an optional remote path:
from pathlib import Path
from latch import small_task
from latch.types import LatchFile
@small_task
def summarize(input_file: LatchFile) -> LatchFile:
source = Path(input_file.local_path)
output = Path("/root/summary.txt")
output.write_text(
f"name={source.name}\nbytes={source.stat().st_size}\n",
encoding="utf-8",
)
return LatchFile(str(output), "latch:///results/summary.txt")
For a passed input:
local_path is the staged path on the task machine.remote_path identifies its source in Latch Data or S3.For a returned value:
Use LatchOutputFile and LatchOutputDir in workflow signatures for
destinations that may not exist yet:
from latch.types import LatchOutputDir, LatchOutputFile
Returning a local LatchDir to an existing remote directory adds or updates
the returned children. It does not imply deletion of unrelated remote files.
Do not depend on this merge behavior as a synchronization or cleanup strategy.
LatchDir.iterdir() lists children of a remote directory. For globbing local
task outputs into remote LatchFile values, use file_glob:
from latch import small_task
from latch.types import LatchFile, file_glob
@small_task
def collect_fastq_outputs() -> list[LatchFile]:
# Run the scientific tool here; it must create outputs/*.fastq.gz.
return file_glob("outputs/*.fastq.gz", "latch:///results/fastq/")
Inspect help for the installed version before scripting a command:
latch --version
latch cp --help
latch sync --help
Common operations:
# List
latch ls latch:///inputs
# Upload or download
latch cp ./sample.fastq.gz latch:///inputs/sample.fastq.gz
latch cp latch:///results/report.html ./report.html
# Create parents
latch mkdirp latch:///results/run-001
# Synchronize a local tree to a remote directory
latch sync ./results latch:///results/run-001
# Recursive removal — confirm the target first
latch rmr latch:///scratch/run-001
Prefer mkdirp and rmr; the older mkdir, rm, touch, and open commands
were deprecated.
LPath): https://wiki.latch.bio/workflows/sdk/api/working-with-filesLPath source in the 2.76.8 release commit: https://github.com/latchbio/latch/blob/0faa9dcd8186444ac008f50adf95d43f0fa30e06/src/latch/ldata/path.py