Prefer using email? Say hi at hello@moveshelf.com
## README: this example shows how we can upload date into a trial on
# Moveshelf using the Moveshelf API.
# This code assumes you have implemented the 'Create subject' example,
# that you have found the subject with a given EHR-id/MRN (my_subject_mrn)
# or name (my_subject_name) within a given project (my_project), and that
# you have access to the subject ID.
# This code also assumes you have implemented the 'Create session' example,
# and that you have found the session with a specific name (my_session)
# This code also assumes you have implemented the 'Create trial' example,
# and that you have found the trial with a specific name (my_trial).
# For that trial as part of a subject and session, we need the "clip_id".
## General configuration. Set values before running the script
my_project = "<organizationName/projectName>" # e.g. support/demoProject
my_subject_mrn = "<subjectMRN>" # subject MRN, e.g. "1234567" or None
my_subject_name = "<subjectName>" # subject name, e.g. Subject1
my_session = "YYYY-MM-DD" # session name, e.g. 2025-09-05
my_condition = "<conditionName>" # e.g. "Barefoot"
my_trial = "<trialName>"
filter_by_extension = None
data_file_name = None # with None, the name of the actual file is used, if needed this name can be used
files_to_upload = [<pathToFile_1>, <pathToFile2>,...] # list of files to be added to the trial
data_type = "raw"
## Add here the code to retrieve the project and find an existing subject and its "subject_details"
# ... subject_found = True
## Add here the code to retrieve an existing session and get its details using "getSessionById"
## Add here the code to retrieve an existing trial and get the ID: clip_id
existing_additional_data = api.getAdditionalData(clip_id)
existing_additional_data = [
data for data in existing_additional_data if not filter_by_extension
or os.path.splitext(data["originalFileName"])[1].lower() == filter_by_extension]
existing_file_names = [data["originalFileName"] for data in existing_additional_data if
len(existing_additional_data) > 0]
## Upload data
for file_to_upload in files_to_upload:
file_name = data_file_name if data_file_name is not None else os.path.basename(file_to_upload)
if file_name in existing_file_names:
print(file_name + " was found in clip, will skip this data.")
continue
print("Uploading data for : " + my_condition + ", " + my_trial + ": " + file_name)
dataId = api.uploadAdditionalData(file_to_upload, clip_id, data_type, file_name)
## General configuration. Set values before running the script
session_folder_path = "<pathToDataFolder>"
file_extension_to_upload = "<extension>" # e.g., ".GCD"
# Define the path to the local JSON file
local_metadata_json = os.path.join(parent_folder, "moveshelf_config_import.json")
# Load JSON file
with open(local_metadata_json, "r") as file:
local_metadata = json.load(file)
# Extract conditionDefinition, representativeTrials, and trialSideSelection
# from metadata JSON
my_condition_definition = local_metadata.get("conditionDefinition", {})
my_representative_trials = local_metadata.get("representativeTrials", {})
my_trial_side_selection = local_metadata.get("trialSideSelection", {})
## Add here the code to retrieve the project and find an existing subject and its "subject_details"
# ... subject_found = True
## Add here the code to retrieve an existing session and get its details using "getSessionById"
## Add here the code to get existing conditions and loop over conditions and trials
# ... clip_id = util.addOrGetTrial(api, session, condition, my_trial)
## Upload data
file_name = data_file_name if data_file_name is not None else f"{my_trial}{file_extension_to_upload}"
print("Uploading data for : " + my_condition + ", " + my_trial + ": " + file_name)
dataId = api.uploadAdditionalData(
os.path.join(session_folder_path, f"{my_trial}{file_extension_to_upload}"),
clip_id,
data_type,
file_name
)
metadata_dict = {
"title": my_trial
}
# Initialize the trial template
custom_options_dict = {"trialTemplate": {}}
trial_template = custom_options_dict["trialTemplate"]
# Add side information if available
side_value = my_trial_side_selection.get(my_trial)
if side_value:
trial_template["sideAdditionalData"] = {dataId: side_value}
# Handle representative trial flags
representative_trial = my_representative_trials.get(my_trial, "")
rep_flags = {}
if "left" in representative_trial:
rep_flags["left"] = True
if "right" in representative_trial:
rep_flags["right"] = True
if rep_flags:
trial_template["representativeTrial"] = rep_flags
# Remove the trialTemplate key if it's still empty
if not trial_template:
custom_options_dict = {}
# Convert to JSON string
custom_options = json.dumps(custom_options_dict)
api.updateClipMetadata(clip_id, metadata_dict, custom_options)
# Fetch trial using the trial ID
new_clip = api.getClipData(clip_id)
print(
f"Found a clip with title: {new_clip['title']},\n"
f"id: {new_clip['id']},\n"
f"and custom options: {new_clip['customOptions']}"
)
## Modifications needed to upload PDF/image files into "Additional files"
my_condition = "Additional files"
my_trial = "<pdf_file_name>"
filter_by_extension = ".pdf" # for images, use e.g. ".jpg"/".png" if needed.
files_to_upload = [
"<path_to_additional_data.pdf>",
]
data_type = "doc" # for images, set data_type to "img"
## Modifications needed to upload raw motion data in ZIP archive into "Additional files"
my_condition = "Additional files"
my_trial = "Raw motion data"
data_file_name = "Raw motion data - " + my_session + ".zip" # Set to None for actual file name.
filter_by_extension = ".zip" # set to None if used without filtering
files_to_upload = [
"<path_to_additional_data.zip>",
]
data_type = "raw"