---
sidebar:
  hidden: true
title: roboto.domain.files.file_system
---
## Module Contents

### FileSystem

```python
class roboto.domain.files.file_system.FileSystem(
    association: roboto.association.Association,
    roboto_client: Optional[roboto.http.RobotoClient] = None,
    file_service: Optional[roboto.storage.FileService] = None,
    org_id: Optional[str] = None,
)
```

`from roboto import FileSystem`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L43-L673)

The files and directories under one association: a dataset, a device, or the org itself.

A `FileSystem` holds that association's directory tree and the operations on it: listing, uploading, downloading, renaming, and deleting files, and creating and renaming directories. Datasets, devices, and orgs each return one as [`files`](/reference/python-sdk/roboto/domain/datasets/dataset#roboto.domain.datasets.dataset.Dataset.files), [`files`](/reference/python-sdk/roboto/domain/devices/device#roboto.domain.devices.device.Device.files), and [`files`](/reference/python-sdk/roboto/domain/orgs/org#roboto.domain.orgs.org.Org.files).

Every relative path a method takes or returns is relative to the root of the association's tree, which files of other associations do not share.

**Parameters**

- **association** (`roboto.association.Association`)
- **roboto_client** (`Optional[roboto.http.RobotoClient]`)
- **file_service** (`Optional[roboto.storage.FileService]`)
- **org_id** (`Optional[str]`)

**Properties**

- **FileSystem.association** (`roboto.association.Association`): The dataset, device, or org whose files this object works on.

#### FileSystem.create_directory()

```python
def create_directory(
    name: str,
    error_if_exists: bool = False,
    create_intermediate_dirs: bool = False,
    parent_path: Optional[pathlib.Path] = None,
    origination: Optional[str] = None,
) -> roboto.domain.files.record.DirectoryRecord
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L89-L144)

Create a directory among the association's files.

**Parameters**

- **name** (`str`): Name of the directory to create.
- **error_if_exists** (`bool`): If True, raises an exception if the directory already exists.
- **parent_path** (`Optional[pathlib.Path]`): Path of the parent directory. If None, creates the directory at the root of the association's files.
- **origination** (`Optional[str]`): Optional string describing the source or context of the directory creation.
- **create_intermediate_dirs** (`bool`): If True, creates intermediate directories in the path if they don't exist. If False, requires all parent directories to already exist.

**Raises**

- [`RobotoConflictException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoConflictException): If the directory already exists and error_if_exists is True.
- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): If the caller lacks permission to create the directory.
- [`RobotoInvalidRequestException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInvalidRequestException): If the directory name is invalid or the parent path does not exist (when create_intermediate_dirs is False).

**Returns**

- `roboto.domain.files.record.DirectoryRecord`: DirectoryRecord of the created directory.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
directory = device.files.create_directory("calib")
print(directory.relative_path)
# calib
```

```python
directory = device.files.create_directory(
    name="final",
    parent_path=pathlib.Path("path/to/deep"),
    create_intermediate_dirs=True,
)
print(directory.relative_path)
# path/to/deep/final
```

#### FileSystem.create_link()

```python
def create_link(
    target: Union[roboto.domain.files.file.File, str],
    relative_path: str,
) -> roboto.domain.files.file.File
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L146-L185)

Put a link to another file at `relative_path` among the association's files.

A link lets one file, such as a URDF in the org's own files, appear in many devices' files without being copied. It pins one version of its target: passing a [`File`](/reference/python-sdk/roboto/domain/files/file#roboto.domain.files.file.File) pins that file's version, and passing a file ID pins the target's current version. Later versions of the target do not move the link; create the link again at the same path to re-point it, which adds a version to the link unless it already pins that target version. Missing parent directories are created. Downloading the link, or asking it for a signed URL, fetches the pinned version of the target.

**Parameters**

- **target** (`Union[roboto.domain.files.file.File, str]`): The file to link to, or its ID. It must be a file in the same org, not a link or a directory.
- **relative_path** (`str`): Where the link sits, relative to the root of the association's files.

**Returns**

- `roboto.domain.files.file.File`: The link, whose [`is_link`](/reference/python-sdk/roboto/domain/files/file#roboto.domain.files.file.File.is_link) is True.

**Raises**

- [`RobotoConflictException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoConflictException): A file or a directory already occupies `relative_path`. The reverse is refused too: uploading a file to a link's path is a conflict until the link is deleted.
- [`RobotoInvalidRequestException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInvalidRequestException): The target is a link or a directory, is in another org, or does not exist at the version to pin.
- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): The caller cannot edit the association's files or view the target.

**Usage**

```python
from roboto.domain import devices, orgs
urdf = orgs.Org.from_id("og_abc123").files.get_file_by_path("urdf/rover/rover.urdf")
device = devices.Device.from_id("rover-01")
link = device.files.create_link(urdf, "urdf/rover.urdf")
link.download(pathlib.Path("/tmp/rover.urdf"))
```

#### FileSystem.delete_files()

```python
def delete_files(
    include_patterns: Optional[list[str]] = None,
    exclude_patterns: Optional[list[str]] = None,
) -> None
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L187-L219)

Delete the association's files that match the given patterns.

Deletes files that match the specified include patterns while excluding those that match exclude patterns. Uses gitignore-style pattern matching for flexible file selection.

**Parameters**

- **include_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to include. If None or empty, all files are considered for deletion. An empty list is treated as no filter (all files), not as "include nothing".
- **exclude_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to exclude from deletion. Takes precedence over include patterns. If None or empty, no files are excluded.

**Raises**

- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): Caller lacks permission to delete files.

**Returns**

- `None`

**Notes**

Pattern matching follows gitignore syntax. See [https://git-scm.com/docs/gitignore](https://git-scm.com/docs/gitignore) for detailed pattern format documentation.

**Usage**

```python
from roboto.domain import orgs
org = orgs.Org.from_id("og_abc123")
org.files.delete_files(include_patterns=["**/*.png"], exclude_patterns=["**/back_camera/**"])
```

#### FileSystem.download_files()

```python
def download_files(
    out_path: pathlib.Path,
    include_patterns: Optional[list[str]] = None,
    exclude_patterns: Optional[list[str]] = None,
    print_progress: bool = True,
) -> list[tuple[roboto.domain.files.record.FileRecord, pathlib.Path]]
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L221-L306)

Download the association's files to a local directory.

Downloads files that match the specified patterns to the given local directory. The files' directory structure is preserved in the download location. If the output directory doesn't exist, it will be created. Files are found with [`list_files()`](/reference/python-sdk/roboto/domain/files/file_system#roboto.domain.files.file_system.FileSystem.list_files), which does not return links yet, so no link is downloaded; download one with [`download()`](/reference/python-sdk/roboto/domain/files/file#roboto.domain.files.file.File.download).

**Parameters**

- **out_path** (`pathlib.Path`): Local directory path where files should be downloaded.
- **include_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to include. If None or empty, all files are downloaded. An empty list is treated as no filter (all files), not as "include nothing".
- **exclude_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to exclude from download. Takes precedence over include patterns. If None or empty, no files are excluded.
- **print_progress** (`bool`): Whether to show a progress bar during download.

**Returns**

- `list[tuple[roboto.domain.files.record.FileRecord, pathlib.Path]]`: List of tuples containing (FileRecord, local_path) for each downloaded file.

**Raises**

- [`RobotoIllegalArgumentException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoIllegalArgumentException): A selected file's path resolves outside `out_path`; nothing is downloaded.
- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): Caller lacks permission to download files.

**Notes**

Pattern matching follows gitignore syntax. See [https://git-scm.com/docs/gitignore](https://git-scm.com/docs/gitignore) for detailed pattern format documentation.

**Usage**

```python
import pathlib
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
downloaded = device.files.download_files(pathlib.Path("/tmp/rover-01"), include_patterns=["calib/**"])
print(f"Downloaded {len(downloaded)} files")
# Downloaded 2 files
```

#### FileSystem.get_file_by_path()

```python
def get_file_by_path(
    relative_path: Union[str, pathlib.Path],
    version_id: Optional[int] = None,
) -> roboto.domain.files.file.File
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L308-L342)

Get a File instance for the association's file at the specified path.

**Parameters**

- **relative_path** (`Union[str, pathlib.Path]`): Path of the file relative to the root of the association's files.
- **version_id** (`Optional[int]`): Specific version of the file to retrieve. If None, gets the latest version.

**Returns**

- `roboto.domain.files.file.File`: File instance representing the file at the specified path.

**Raises**

- [`RobotoNotFoundException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoNotFoundException): The association has no file at the given path.
- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): Caller lacks permission to access the file.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
file = device.files.get_file_by_path("manifest.json")
print(file.file_id)
# fl_xyz789
```

```python
old_file = device.files.get_file_by_path("manifest.json", version_id=1)
print(old_file.version)
# 1
```

#### FileSystem.list_directories()

```python
def list_directories() -> collections.abc.Generator[roboto.domain.files.record.DirectoryRecord, None, None]
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L344-L368)

Yield every directory among the association's files, at any depth.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
for directory in device.files.list_directories():
    print(directory.relative_path)
# calib
# urdf
```

**Returns**

- `collections.abc.Generator[roboto.domain.files.record.DirectoryRecord, None, None]`

#### FileSystem.list_files()

```python
def list_files(
    include_patterns: Optional[list[str]] = None,
    exclude_patterns: Optional[list[str]] = None,
) -> collections.abc.Generator[roboto.domain.files.file.File, None, None]
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L370-L424)

List the association's files with optional pattern-based filtering.

Returns all of the association's files that match the specified include patterns while excluding those that match exclude patterns. Uses gitignore-style pattern matching for flexible file selection.

**Parameters**

- **include_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to include. If None or empty, all files are considered. An empty list is treated as no filter (all files), not as "include nothing".
- **exclude_patterns** (`Optional[list[str]]`): List of gitignore-style patterns for files to exclude. Takes precedence over include patterns. If None or empty, no files are excluded.

**Yields**

- File instances that match the specified patterns.

**Raises**

- [`RobotoUnauthorizedException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoUnauthorizedException): Caller lacks permission to list files.

**Returns**

- `collections.abc.Generator[roboto.domain.files.file.File, None, None]`

**Notes**

Pattern matching follows gitignore syntax. See [https://git-scm.com/docs/gitignore](https://git-scm.com/docs/gitignore) for detailed pattern format documentation.

Files appear in this list shortly after their upload completes, not instantly.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
for file in device.files.list_files():
    print(file.relative_path)
# manifest.json
# calib/front_cam.yaml
```

```python
for file in device.files.list_files(include_patterns=["calib/**"], exclude_patterns=["**/*.bak"]):
    print(file.relative_path)
# calib/front_cam.yaml
```

#### FileSystem.rename_directory()

```python
def rename_directory(
    old_path: str,
    new_path: str,
) -> roboto.domain.files.record.DirectoryRecord
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L426-L457)

Rename or move a directory among the association's files.

Both `old_path` and `new_path` are relative to the root of the association's files. Pass a `new_path` with fewer path components to move the directory up the tree, or a different leaf name at the same depth to rename in place.

**Parameters**

- **old_path** (`str`): Current relative path of the directory (e.g. `"logs/session1"`).
- **new_path** (`str`): Target relative path of the directory (e.g. `"session1"` to move up one level).

**Returns**

- `roboto.domain.files.record.DirectoryRecord`: Updated [`DirectoryRecord`](/reference/python-sdk/roboto/domain/files/record#roboto.domain.files.record.DirectoryRecord) reflecting the new path.

**Raises**

- [`RobotoNotFoundException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoNotFoundException): No directory exists at `old_path`.
- [`RobotoInvalidRequestException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInvalidRequestException): `new_path` conflicts with an existing node or contains a cycle.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
device.files.rename_directory("calib/front", "front_calib")
```

#### FileSystem.rename_file()

```python
def rename_file(file_id: str, new_path: str) -> roboto.domain.files.record.FileRecord
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L459-L497)

Rename or move a file among the association's files.

`new_path` is relative to the root of the association's files. Pass a path with fewer components to move the file up the tree, a different name at the same depth to rename in place, or a path under a different directory to move sideways.

The file's storage URI is unchanged; only its relative path changes.

**Parameters**

- **file_id** (`str`): ID of the file to rename or move.
- **new_path** (`str`): Target relative path for the file (e.g. `"file.bag"` to move to the root, or `"other_dir/file.bag"` to move into an existing directory).

**Returns**

- `roboto.domain.files.record.FileRecord`: Updated [`FileRecord`](/reference/python-sdk/roboto/domain/files/record#roboto.domain.files.record.FileRecord) reflecting the new path.

**Raises**

- [`RobotoNotFoundException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoNotFoundException): No file with `file_id` exists.
- [`RobotoInvalidRequestException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInvalidRequestException): `new_path` conflicts with an existing file, the parent directory does not exist, or the move would create a cycle.

**Usage**

```python
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
record = device.files.rename_file("fl_xyz789", "manifest.json")
record.relative_path
# 'manifest.json'
```

#### FileSystem.upload_directory()

```python
def upload_directory(
    directory_path: pathlib.Path,
    include_patterns: Optional[list[str]] = None,
    exclude_patterns: Optional[list[str]] = None,
    delete_after_upload: bool = False,
    max_batch_size: int = MAX_FILES_PER_MANIFEST,
    print_progress: bool = True,
    device_id: Optional[str] = None,
) -> None
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L499-L547)

Upload all files and directories recursively from the specified directory path.

Use `include_patterns` and `exclude_patterns` to control what files and directories are uploaded, and `delete_after_upload` to clean up your local filesystem after the uploads succeed.

**Parameters**

- **directory_path** (`pathlib.Path`): Local directory whose contents are uploaded, keeping its layout.
- **include_patterns** (`Optional[list[str]]`): gitignore-style patterns for files to include. If None, every file is included.
- **exclude_patterns** (`Optional[list[str]]`): gitignore-style patterns for files to exclude. Takes precedence over `include_patterns`.
- **delete_after_upload** (`bool`): If True, each uploaded local file is deleted once the uploads succeed.
- **max_batch_size** (`int`): Maximum number of files per upload transaction.
- **print_progress** (`bool`): Whether to display an upload progress bar.
- **device_id** (`Optional[str]`): Optional identifier of the device that generated this data.

**Returns**

- `None`

**Notes**

Both pattern lists follow the gitignore pattern format described in [https://git-scm.com/docs/gitignore#\_pattern_format](https://git-scm.com/docs/gitignore#_pattern_format).

**Usage**

```python
import pathlib
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
device.files.upload_directory(
    pathlib.Path("/path/to/calibration"),
    exclude_patterns=["**/*.log"],
)
```

#### FileSystem.upload_file()

```python
def upload_file(
    file_path: pathlib.Path,
    file_destination_path: Optional[str] = None,
    print_progress: bool = True,
    device_id: Optional[str] = None,
) -> roboto.domain.files.file.File
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L549-L599)

Upload a single file associated with [`association`](/reference/python-sdk/roboto/domain/files/file_system#roboto.domain.files.file_system.FileSystem.association).

**Parameters**

- **file_path** (`pathlib.Path`): Local file to upload.
- **file_destination_path** (`Optional[str]`): Destination path among the association's files. Defaults to the file's own name at the root.
- **print_progress** (`bool`): Whether to display an upload progress bar.
- **device_id** (`Optional[str]`): Optional identifier of the device that generated this data.

**Returns**

- `roboto.domain.files.file.File`: The uploaded file. Its record is fetched from the platform the first time it is read.

**Raises**

- [`RobotoInternalException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInternalException): The upload reported success without reporting a file ID.

**Usage**

```python
import pathlib
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
device.files.upload_file(pathlib.Path("/path/to/manifest.json"))
```

#### FileSystem.upload_files()

```python
def upload_files(
    files: collections.abc.Iterable[pathlib.Path],
    file_destination_paths: collections.abc.Mapping[pathlib.Path, str] = {},
    max_batch_size: int = MAX_FILES_PER_MANIFEST,
    print_progress: bool = True,
    device_id: Optional[str] = None,
) -> dict[pathlib.Path, str]
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L601-L651)

Upload multiple files associated with [`association`](/reference/python-sdk/roboto/domain/files/file_system#roboto.domain.files.file_system.FileSystem.association).

**Parameters**

- **files** (`collections.abc.Iterable[pathlib.Path]`): Local files to upload.
- **file_destination_paths** (`collections.abc.Mapping[pathlib.Path, str]`): Mapping from local path to destination path among the association's files. Files not in the mapping upload to the root under their own name.
- **max_batch_size** (`int`): Maximum number of files per upload transaction.
- **print_progress** (`bool`): Whether to display an upload progress bar.
- **device_id** (`Optional[str]`): Optional identifier of the device that generated this data.

**Returns**

- `dict[pathlib.Path, str]`: Mapping from each uploaded local path to the ID of the file record it created.

**Usage**

```python
import pathlib
from roboto.domain import devices
device = devices.Device.from_id("rover-01")
file_ids = device.files.upload_files(
    [pathlib.Path("/path/to/front_cam.yaml")],
    file_destination_paths={pathlib.Path("/path/to/front_cam.yaml"): "calib/front_cam.yaml"},
)
file_ids[pathlib.Path("/path/to/front_cam.yaml")]
# 'fl_0123456789abcdef'
```

### MAX_FILES_PER_MANIFEST

```python
roboto.domain.files.file_system.MAX_FILES_PER_MANIFEST = 500
```

`from roboto.domain.files.file_system import MAX_FILES_PER_MANIFEST`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/files/file_system.py#L40-L40)
