---
title: Directories
description: Inspect and edit a dataset's virtual directory tree - list, tree, stats, create, rename, delete.
section: API Reference
order: 18
---
Pictograph organizes a dataset's images into **virtual directories**. A directory is a
label on the image, not a physical location, so moving an image between directories
never rewrites stored bytes.

In REST, the directory path is part of the URL: `/train/cars` becomes
`.../directories/road-signs/train/cars`.

Datasets and directories are addressed by **name** and **path**; a UUID is
accepted anywhere a name is. A dataset outside your organization returns 404.

## list

Direct children of `parent_path` (use `""` for the root), or every directory in the
dataset when `parent_path` is omitted.

Source: [`Directories.list`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `parent_path` | `str \| None` | `None` | `None` = all directories; `""` = root-level only; a path = that directory's children |

```python
directories = client.directories.list(
    dataset_name="road-signs",
    parent_path="",
)
for d in directories:
    print(d.full_path, d.image_count)
```

```bash
pictograph directories list road-signs --parent ""
```

```bash
curl -s "https://api.pictograph.io/api/v1/developer/directories/road-signs?parent_path=" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `Sequence[Directory]`

<details>
<summary><code>Directory</code> &middot; 10 fields</summary>

```python
class Directory(BaseModel):
    """A single virtual directory in a dataset."""
    id: str
    dataset_id: str
    organization_id: str | None = None
    name: str
    parent_directory_id: str | None = None
    full_path: str
    image_count: int = 0
    created_by: str | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None
```

</details>

## tree

The whole hierarchy in one request, each node carrying its `children`. Use this to
render a sidebar instead of walking `list` level by level.

Source: [`Directories.tree`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |

```python
tree = client.directories.tree(
    dataset_name="road-signs",
)
for node in tree:
    print(node.name, len(node.children))
```

```bash
pictograph directories tree road-signs
```

```bash
curl -s "https://api.pictograph.io/api/v1/developer/directories/road-signs/tree" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `Sequence[DirectoryTreeNode]`

<details>
<summary><code>DirectoryTreeNode</code> &middot; 5 fields</summary>

```python
class DirectoryTreeNode(BaseModel):
    """A node in the hierarchical directory tree (children nested recursively)."""
    id: str
    name: str
    full_path: str
    image_count: int = 0
    children: list[DirectoryTreeNode] = []
```

</details>

## stats

Image statistics for one directory, rolling up its subdirectories by default.

Source: [`Directories.stats`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `directory_path` | `str` | required | Directory path, e.g. `/train/cars`. Leading slash optional. |
| `include_subdirectories` | `bool` | `True` | Roll up subdirectories too |

```python
stats = client.directories.stats(
    dataset_name="road-signs",
    directory_path="/train/cars",
    include_subdirectories=True,
)
print(stats.total_images, stats.total_directories, stats.total_size_bytes)
```

```bash
pictograph directories stats road-signs /train/cars
```

```bash
curl -s "https://api.pictograph.io/api/v1/developer/directories/road-signs/train/cars/stats?include_subdirectories=true" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `DirectoryStats`

<details>
<summary><code>DirectoryStats</code> &middot; 4 fields</summary>

```python
class DirectoryStats(BaseModel):
    """Aggregate image statistics for a directory (and, by default, its subdirectories)."""
    total_directories: int
    total_images: int
    total_size_bytes: int
    directories_by_status: dict[str, int] = {}
```

</details>

## create

Idempotent: creating an existing path returns it. Missing parents are auto-created,
the same way an upload into a directory path does, so use this to pre-stage an empty
structure ahead of uploads. Requires `member`+ role.

Source: [`Directories.create`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `directory_path` | `str` | required | Full virtual path to create, e.g. `"/train/positive"`. |

```python
directory = client.directories.create(
    dataset_name="road-signs",
    directory_path="/train/positive",
)
print(directory.id, directory.full_path)
```

```bash
pictograph directories create road-signs /train/positive
```

```bash
curl -s -X POST "https://api.pictograph.io/api/v1/developer/directories/" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{"dataset": "road-signs", "directory_path": "/train/positive"}'
```

**Returns** `Directory`

<details>
<summary><code>Directory</code> &middot; 10 fields</summary>

```python
class Directory(BaseModel):
    """A single virtual directory in a dataset."""
    id: str
    dataset_id: str
    organization_id: str | None = None
    name: str
    parent_directory_id: str | None = None
    full_path: str
    image_count: int = 0
    created_by: str | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None
```

</details>

## rename

The directory row, every descendant directory's path, and every contained image's
directory path move together in one call. No bytes move. `new_name` is a single path
segment, not a path. A sibling with that name is a 409. Requires `member`+ role.

Source: [`Directories.rename`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `directory_path` | `str` | required | Full virtual path of the directory to rename. |
| `new_name` | `str` | required | The new name (a single path segment, not a path). |

```python
directory = client.directories.rename(
    dataset_name="road-signs",
    directory_path="/train/cars",
    new_name="negatives",
)
```

```bash
pictograph directories rename road-signs /train/cars negatives
```

```bash
curl -s -X PATCH "https://api.pictograph.io/api/v1/developer/directories/road-signs/train/cars/rename" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{"new_name": "negatives"}'
```

**Returns** `Directory`

<details>
<summary><code>Directory</code> &middot; 10 fields</summary>

```python
class Directory(BaseModel):
    """A single virtual directory in a dataset."""
    id: str
    dataset_id: str
    organization_id: str | None = None
    name: str
    parent_directory_id: str | None = None
    full_path: str
    image_count: int = 0
    created_by: str | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None
```

</details>

## delete

Empty-only by default. `cascade=True` first moves the directory's images to its
parent, then deletes. Requires `member`+ role.

Source: [`Directories.delete`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/directories.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `directory_path` | `str` | required | Virtual directory path, leading slash, e.g. `/train`. |
| `cascade` | `bool` | `False` | Move the directory's images up to its parent, then delete. Without it a non-empty directory is a 409. |

```python
client.directories.delete(
    dataset_name="road-signs",
    directory_path="/train/cars",
    cascade=True,
)
```

```bash
pictograph directories delete road-signs /train/cars --cascade --yes
```

```bash
curl -s -X DELETE "https://api.pictograph.io/api/v1/developer/directories/road-signs/train/cars?cascade=true" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `None`

## Common errors

| Status | Exception | Cause |
|---|---|---|
| 403 | `ForbiddenError` | No access to the organization, or a mutation without `member`+ role |
| 404 | `NotFoundError` | Dataset or directory does not exist in your organization |
| 409 | `ConflictError` | `rename` target name already exists as a sibling |