Skip to content

study_import

Bulk study metadata & lights: the import contract.

The browser (or any client) parses CSV/XLSX itself and maps columns to this vocabulary; the SERVER decides — these JSON batch requests validate, resolve study names, coerce times and apply per item with the platform's per-item error convention. There is no file-shaped write path.

Two rules carry the sharp edges:

  • Field presence is the PATCH semantics: an absent field leaves the study unchanged, an explicit null clears it. Clients must serialize with exclude_unset — a partial re-upload can never silently wipe data.
  • Clock time is the primary lights spelling ("23:15"), resolved per study against its recording's own wall-clock frame with overnight wrap — accepted only while the study's recording span is ≤ 24 hours (recordings may run for days, making a bare clock time ambiguous; such rows error per item and must use the datetime or elapsed-ms spelling). Exactly one spelling per marker.

STUDY_IMPORT_COLUMNS = [StudyImportColumn(key='study', kind='study_key', aliases=['study', 'study_name', 'name', 'study_id', 'id'], description='The study each row addresses, by exact name or id. Required.'), StudyImportColumn(key='subject_key', kind='text', aliases=['subject_key', 'subject', 'subject_id', 'subject_code', 'participant', 'participant_id'], description="The person the study belongs to. Rows sharing a key within the project form one subject's series. Compared case- and whitespace-insensitively; blank leaves the study standing alone."), StudyImportColumn(key='session_index', kind='integer', aliases=['session_index', 'session', 'night', 'night_index', 'visit', 'visit_index'], description="Declared position of the study in its subject's series, 1 = first. Blank orders by recording start instead. A subject whose studies are only partly numbered is left out of session-indexed figures and named in a warning."), StudyImportColumn(key='age', kind='integer', aliases=['age', 'age_years', 'subject_age'], unit='years', description='Subject age in years (0–125). NULL clears.'), StudyImportColumn(key='sex', kind='sex', aliases=['sex', 'gender'], description="Subject sex (the platform's Sex vocabulary). NULL clears."), StudyImportColumn(key='bmi', kind='decimal', aliases=['bmi', 'body_mass_index'], unit='kg/m²', description='Body mass index (5–200). NULL clears.'), StudyImportColumn(key='lights_off_clock', kind='clock', aliases=['lights_off', 'lights_off_clock', 'lights off', 'loff'], description="Lights-off as wall clock HH:MM[:SS] in the recording's own frame, resolved with overnight wrap. Only valid while the study's recording span is ≤ 24 h — longer spans must use the datetime or ms spelling."), StudyImportColumn(key='lights_on_clock', kind='clock', aliases=['lights_on', 'lights_on_clock', 'lights on', 'lon'], description='Lights-on as wall clock HH:MM[:SS], resolved with overnight wrap after lights-off.'), StudyImportColumn(key='lights_off_datetime', kind='datetime', aliases=['lights_off_datetime', 'lights_off_at'], description="Lights-off as an absolute datetime in the recording's wall-clock frame (alternate spelling)."), StudyImportColumn(key='lights_on_datetime', kind='datetime', aliases=['lights_on_datetime', 'lights_on_at'], description='Lights-on as an absolute datetime (alternate spelling).'), StudyImportColumn(key='lights_off_ms', kind='elapsed_ms', aliases=['lights_off_ms', 'lights_off_elapsed_ms'], unit='ms', description='Lights-off as milliseconds from recording start (alternate spelling).'), StudyImportColumn(key='lights_on_ms', kind='elapsed_ms', aliases=['lights_on_ms', 'lights_on_elapsed_ms'], unit='ms', description='Lights-on as milliseconds from recording start (alternate spelling).')] module-attribute

The one column table: frontend auto-mapping, SDK docs, and the template download all derive from this — never duplicate it.

BatchPatchStudiesMetadataRequest pydantic-model

Bases: BaseModel

Apply metadata patches across many studies (207 per-item results).

Fields:

BatchPatchStudiesMetadataResponse pydantic-model

Bases: BaseModel

Per-item results plus the usual batch summary.

Fields:

BatchSetStudyLightsRequest pydantic-model

Bases: BaseModel

Assign lights markers across many studies (207 per-item results).

Fields:

replace_existing = False pydantic-field

False: rows whose targeted marker already exists error per-item (manual edits win by default). True: overwrite.

BatchSetStudyLightsResponse pydantic-model

Bases: BaseModel

Per-item results plus the usual batch summary.

Fields:

BatchStudyMetadataSummary pydantic-model

Bases: BatchSummary

Summary for a metadata/lights batch.

Fields:

  • total (int)
  • updated (int)
  • errors (int)

LightsInstant pydantic-model

Bases: BaseModel

One lights marker in exactly one spelling.

clock is primary: wall clock in the recording's own frame, resolved per study with overnight wrap (a 23:30 recording start with lights_off 00:15 lands the next calendar day). datetime is an absolute wall-clock datetime in the same frame; elapsed_ms counts from recording start.

Fields:

Validators:

  • _exactly_one_spelling

clock = None pydantic-field

Wall clock "HH:MM" or "HH:MM:SS". Only resolvable while the study's recording span is ≤ 24 h; longer spans error per item (use datetime or elapsed_ms).

datetime = None pydantic-field

ISO datetime in the recording's wall-clock frame (any timezone suffix is ignored; times are read in the recording's own wall-clock frame).

StudyImportColumn pydantic-model

Bases: BaseModel

One column the import understands — drives auto-mapping and docs.

Fields:

aliases pydantic-field

Lower-cased header spellings that auto-map to this column.

description pydantic-field

What the column sets.

key pydantic-field

Canonical column key (the API field name).

kind pydantic-field

Value shape, for parsing/validation.

unit = None pydantic-field

Display unit, if any.

StudyLightsAssignment pydantic-model

Bases: BaseModel

One study's lights markers.

Presence semantics as everywhere in this module: an absent marker is left unchanged, an explicit null DELETES the marker. At least one of the two must be present.

Fields:

Validators:

  • _something_to_do

StudyLightsResult pydantic-model

Bases: BaseModel

Outcome for one lights row.

Fields:

  • study (str)
  • study_id (UUID | None)
  • status (Literal['updated', 'error'])
  • lights_off_ms (int | None)
  • lights_on_ms (int | None)
  • error (BatchItemError | None)

StudyMetadataPatch pydantic-model

Bases: BaseModel

One study's metadata changes.

Field PRESENCE is the semantics: absent = unchanged, explicit null = clear. Serialize with exclude_unset. Bounds match the canonical StudyMetadata (the batch-creation item is harmonised to the same).

Fields:

Validators:

  • _something_to_do

session_index = None pydantic-field

Declared position in the subject's series; null derives it.

study pydantic-field

Study name or id. Names resolve within the project: 0 matches → not_found, >1 → conflict (rename or use ids).

subject_key = None pydantic-field

The subject this study belongs to; null detaches it.

StudyMetadataResult pydantic-model

Bases: BaseModel

Outcome for one metadata patch row.

Fields:

study pydantic-field

The row's study key, as submitted.

study_id = None pydantic-field

The resolved study, when resolution succeeded.