Copying and Moving Containers
The Flywheel SDK provides dedicated methods for copying containers at every level of the hierarchy, plus a bulk operation for moving sessions. This page explains the difference between copy and move, covers each copy method and its input model, describes how to filter what gets included in a copy, and shows a workaround for copying a single file.
See Core Concepts: Containers and Core Concepts: Hierarchy for background on the container model.
Copy vs. move
Copy creates a linked reference of the source container in the destination. The original remains intact and continues to exist in its source location. A copy does not duplicate the underlying file data — it only creates a new reference, so the copy does not consume additional storage space.
Note
After a copy is created, the source and the copy are independent. Modifying a file on the copy will increment that file's version on the copy only — it will not affect the original. Metadata (info, tags, notes) is copied at the time of the operation but is not synced afterward. Changes to metadata on the original will not appear on the copy, and vice versa.
Move relocates the source container to a new parent. The original is removed from its source location. Use move when reorganizing data — for example, reassigning sessions to different subjects after a labeling correction.
The SDK exposes these as separate operations:
- Copy:
fw.session_copy(),fw.subject_copy(),fw.acquisition_copy(),fw.project_copy() - Move:
fw.bulk_move_sessions()(sessions only; bulk operation)
Copy methods
Every copy method takes two arguments: the ID of the container to copy, and a *CopyInput model that specifies the destination and optional new label.
All copy methods except fw.project_copy() are synchronous and return the new container directly. fw.project_copy() is asynchronous and returns a ProjectCopyOutput with a task_id you use to track progress.
No container can be copied unless the parent project is copyable. Copying can be enabled via the UI under Projects -> Settings -> Copying or the SDK:
Copy a session
SessionCopyInput fields:
| Field | Type | Description |
|---|---|---|
dst_project_id | str | Destination project. The copy lands under a new or matched subject in this project. |
dst_subject_id | str | Destination subject. Use this instead of dst_project_id to place the session under a specific subject. |
dst_session_label | str | Label for the copied session. If omitted, the original label is used. |
filter | CopyFilter | Controls what is excluded from the copy. See CopyFilter below. |
Copy a subject
SubjectCopyInput fields:
| Field | Type | Description |
|---|---|---|
dst_project_id | str | Destination project. |
dst_subject_label | str | Label for the copied subject. |
filter | CopyFilter | Controls what is excluded from the copy. |
Copy an acquisition
Acquisitions copy into a destination session rather than a project.
AcquisitionCopyInput fields:
| Field | Type | Description |
|---|---|---|
dst_session_id | str | Destination session. |
label | str | Label for the copied acquisition. |
filter | CopyFilter | Controls what is excluded from the copy. |
Copy a project (asynchronous)
Project copy is asynchronous. The call returns immediately with a ProjectCopyOutput that contains a task_id. You must poll separately to determine when the copy has finished.
ProjectCopyInput fields:
| Field | Type | Description |
|---|---|---|
group_id | str | Destination group. |
project_label | str | Label for the copied project. |
snapshot_id | str | Optional. Copy from a specific snapshot rather than the live project. |
filter | CopyFilter | Controls what is excluded from the copy. |
ProjectCopyOutput fields:
| Field | Type | Description |
|---|---|---|
task_id | str | ID of the background task running the copy. Poll this to track progress. |
project_id | str | ID of the newly created project. |
snapshot_id | str | ID of the snapshot used for the copy, if applicable. |
CopyFilter
Every *CopyInput model accepts an optional filter field of type CopyFilter. When omitted, the copy includes everything. Use CopyFilter to exclude specific content categories or to restrict which files are included using file name patterns.
CopyFilter fields:
| Field | Type | Default | Description |
|---|---|---|---|
exclude_analysis | bool | False | When True, analyses are not copied. |
exclude_notes | bool | False | When True, notes are not copied. |
exclude_tags | bool | False | When True, tags are not copied. |
exclude_empty_containers | bool | True | When True, containers with no files are omitted from the copy. |
include_rules | list[str] | None | If set, only files whose names match one of these patterns are included. |
exclude_rules | list[str] | None | If set, files whose names match any of these patterns are excluded. |
include_rules and exclude_rules accept file name glob patterns. When both are set, include_rules takes precedence — the SDK first applies include_rules to build the candidate set, then applies exclude_rules within that set.
Bulk move sessions
fw.bulk_move_sessions() moves multiple sessions into a single destination container in one call. Pass a BulkMoveInput that identifies the source sessions and the one destination, and choose how label conflicts are handled with conflict_mode ("dry", "skip", or "move"). The call returns a list of conflicts — an empty list means a clean move.
destinations must contain exactly one container ID — all sources move into that one target. destination_container_type describes the destination's type ("subjects" for the normal case), and remove_source should be left at its default False.
For the full walkthrough — conflict modes, previewing a move with a dry run, reading the MoveConflict report, and merging subjects — see Advanced Usage: Bulk Move Sessions.
Copying a single file
The SDK does not provide a direct file copy method. To copy one file from one acquisition to another:
- Copy the source acquisition with an
include_rulesfilter that matches only the target file. - The copy lands as a new temporary acquisition containing just that one file.
- Move the file from the temporary acquisition to the target acquisition using
fw.move_file(). - Delete the temporary acquisition.
This approach avoids a full round-trip download and re-upload for the file. For large collections of files, consider whether a full acquisition copy is more practical.