reprostim.qr.bids_inject¶
Core logic for bids-inject: cross-reference ReproStim videos.tsv with BIDS _scans.tsv files to slice and inject per-acquisition video clips into a BIDS dataset.
See .ai/spec-bids-inject.md for the full specification.
Functions
|
Main entry point for the bids-inject command. |
|
Convert a naive BIDS datetime directly to a naive ReproStim datetime. |
|
Convert a naive BIDS datetime to a naive UTC datetime. |
|
Convert a naive datetime from one timezone context to another. |
Parse a BIDS |
|
|
Parse a DICOM TM (Time) string into a |
|
Convert a naive ReproStim datetime directly to a naive BIDS datetime. |
|
Convert a naive ReproStim datetime to a naive UTC datetime. |
|
Resolve a timezone name string to a |
Convert a |
|
|
Return the current UTC offset for a timezone name, e.g. |
|
Convert a naive UTC datetime to a naive BIDS-domain datetime. |
|
Convert a naive UTC datetime to a naive ReproStim-domain datetime. |
Classes
|
Context for bids-inject processing of scan records. |
|
Mutable counters accumulating per-run injection statistics. |
|
Policy for handling buffer overflow beyond video boundaries. |
|
Output file placement layout within the BIDS dataset. |
|
Recording-type suffix per BEP044:Stimuli. |
|
Policy for handling existing output files. |
|
QR code-based timing refinement mode. |
|
Duration-relevant fields from a BIDS JSON sidecar file. |
|
A single row from a BIDS _scans.tsv file with optionally expanded metadata. |
|
Parsed representation of a single BIDS |
- class reprostim.qr.bids_inject.BiContext(*, dry_run: bool, recursive: bool, match: str = '.*', videos_tsv: str | None = None, time_offset: float = 0.0, qr: ~reprostim.qr.bids_inject.QrMode = QrMode.NONE, buffer_before: str = '0', buffer_after: str = '0', buffer_policy: str = 'flexible', layout: ~reprostim.qr.bids_inject.LayoutMode = LayoutMode.NEARBY, overwrite: ~reprostim.qr.bids_inject.OverwriteMode = OverwriteMode.SKIP, reprostim_timezone: str = 'local', bids_timezone: str = 'local', lock: bool = True, verbose: bool = False, out_func: ~typing.Callable | None = None, summary: ~reprostim.qr.bids_inject.BiSummary = <factory>)[source]¶
Context for bids-inject processing of scan records.
- bids_timezone: str¶
- property bids_tz: tzinfo¶
Resolved
tzinfoforbids_timezone(cached).
- buffer_after: str¶
- buffer_before: str¶
- buffer_policy: str¶
- dry_run: bool¶
- layout: LayoutMode¶
- lock: bool¶
- match: str¶
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- out_func: Callable | None¶
- overwrite: OverwriteMode¶
- recursive: bool¶
- reprostim_timezone: str¶
- property reprostim_tz: tzinfo¶
Resolved
tzinfoforreprostim_timezone(cached).
- time_offset: float¶
- verbose: bool¶
- videos_tsv: str | None¶
- class reprostim.qr.bids_inject.BiSummary(*, n_processed: int = 0, n_injected: int = 0, n_skipped: int = 0, n_errors: int = 0, errors: ~typing.List[str] = <factory>)[source]¶
Mutable counters accumulating per-run injection statistics.
- errors: List[str]¶
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- n_errors: int¶
- n_injected: int¶
- n_processed: int¶
- n_skipped: int¶
- class reprostim.qr.bids_inject.BufferPolicy(value)[source]¶
Policy for handling buffer overflow beyond video boundaries.
- FLEXIBLE = 'flexible'¶
- STRICT = 'strict'¶
- class reprostim.qr.bids_inject.LayoutMode(value)[source]¶
Output file placement layout within the BIDS dataset.
- NEARBY = 'nearby'¶
- TOP_STIMULI = 'top-stimuli'¶
- class reprostim.qr.bids_inject.MediaSuffix(value)[source]¶
Recording-type suffix per BEP044:Stimuli.
- AUDIO = '_audio'¶
- AUDIOVIDEO = '_audiovideo'¶
- VIDEO = '_video'¶
- class reprostim.qr.bids_inject.OverwriteMode(value)[source]¶
Policy for handling existing output files.
- ALWAYS = 'always'¶
- ERROR = 'error'¶
- FORCE = 'force'¶
- SKIP = 'skip'¶
- class reprostim.qr.bids_inject.QrMode(value)[source]¶
QR code-based timing refinement mode.
- AUTO = 'auto'¶
- EMBED_EXISTING = 'embed-existing'¶
- NONE = 'none'¶
- PARSE = 'parse'¶
- class reprostim.qr.bids_inject.ScanMetadata(*, TaskName: str | None = None, FrameAcquisitionDuration: float | None = None, AcquisitionTime: ~typing.List[str] | None = None, RepetitionTime: float | None = None, NumberOfVolumes: int | None = None, extra: dict = <factory>)[source]¶
Duration-relevant fields from a BIDS JSON sidecar file.
Only the four fields required for scan-duration computation are promoted to typed attributes; every other key present in the JSON sidecar is stored verbatim in
extra.Duration is resolved in priority order (see spec):
FrameAcquisitionDuration(ms) — most reliable when present.AcquisitionTimearray —(last - first + TR)seconds whereTR = AcquisitionTime[1] - AcquisitionTime[0].RepetitionTime(s) ×NumberOfVolumes.
- AcquisitionTime: List[str] | None¶
- FrameAcquisitionDuration: float | None¶
- NumberOfVolumes: int | None¶
- RepetitionTime: float | None¶
- TaskName: str | None¶
- extra: dict¶
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- class reprostim.qr.bids_inject.ScanRecord(*, filename: str, acq_time: str, extra: dict = <factory>, metadata: ~reprostim.qr.bids_inject.ScanMetadata | None = None, duration_sec: float | None = None, reprostim_path: str | None = None, reprostim_offset: float | None = None, reprostim_buffer_before: float | None = None, reprostim_buffer_after: float | None = None)[source]¶
A single row from a BIDS _scans.tsv file with optionally expanded metadata.
- acq_time: str¶
- duration_sec: float | None¶
- extra: dict¶
- filename: str¶
- metadata: ScanMetadata | None¶
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- reprostim_buffer_after: float | None¶
- reprostim_buffer_before: float | None¶
- reprostim_offset: float | None¶
- reprostim_path: str | None¶
- class reprostim.qr.bids_inject.ScansModel(*, path: str, records: ~typing.List[~reprostim.qr.bids_inject.ScanRecord] = <factory>)[source]¶
Parsed representation of a single BIDS
*_scans.tsvfile.- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- path: str¶
- records: List[ScanRecord]¶
- reprostim.qr.bids_inject.do_main(paths: List[str], videos_tsv: str, recursive: bool, match: str, buffer_before: str, buffer_after: str, buffer_policy: str, time_offset: float, qr: str, layout: str, reprostim_timezone: str, bids_timezone: str, dry_run: bool, overwrite: str, lock: bool, verbose: bool, out_func: Callable) int[source]¶
Main entry point for the bids-inject command.
Orchestrates loading of videos.tsv, discovery of
*_scans.tsvfiles, per-scan matching, slicing, and injection.- Parameters:
paths (List[str]) – List of file or directory paths from the CLI
PATHSargument.videos_tsv (str) – Path to
videos.tsvproduced byvideo-audit. Video file paths inside the TSV are resolved relative to this file’s location.recursive (bool) – When
True, recurse into subdirectories when searching for*_scans.tsvfiles.match (str) – Regular expression matched against the
filenamefield of eachScanRecord. Only matching records are processed; others are skipped. Default'.*'matches every record.buffer_before (str) – Extra video to include before scan onset. Accepts seconds (e.g.
'10') or ISO 8601 duration (e.g.'PT10S').buffer_after (str) – Extra video to include after scan end. Accepts seconds (e.g.
'10') or ISO 8601 duration (e.g.'PT10S').buffer_policy (str) –
'strict'to error when buffers exceed video boundaries;'flexible'to trim them instead.time_offset (float) – Clock offset in seconds added to
acq_timevalues after timezone normalisation.qr (str) – QR timing refinement mode:
'none','auto','embed-existing', or'parse'.layout (str) – Output placement layout:
'nearby'or'top-stimuli'.reprostim_timezone (str) – Timezone for naive ReproStim timestamps in
videos.tsv. Use'local'for the OS timezone or an IANA name (e.g.'America/New_York').bids_timezone (str) – Timezone for naive BIDS
acq_timevalues. Use'local'or an IANA name.dry_run (bool) – When
True, resolve matches and print planned actions but skipsplit-videoand all file writes.lock (bool) – When
True(default), acquire the advisory file lock before readingvideos.tsv. WhenFalse, skip the lock (dirty-read mode) — useful when the lock file is owned by a different OS user.layout – Output file placement layout:
'nearby'places the output next to the NIfTI in the same BIDS datatype folder;'top-stimuli'places it under astimuli/directory at the BIDS root, mirroring the subject/session/datatype hierarchy.overwrite (str) – Policy for existing output files:
'skip'(default) skips the scan,'force'removes existing file/symlink then re-injects,'always'runs split-video as-is without an existence check,'error'treats existing output as an error.verbose (bool) – When
True, emit verbose progress output.out_func (Callable) – Callable used for user-facing output (e.g.
click.echo).
- Returns:
Exit code —
0on success, non-zero on error.- Return type:
int
- reprostim.qr.bids_inject.dt_bids_to_reprostim(dt: datetime, bids_tz: tzinfo, reprostim_tz: tzinfo) datetime[source]¶
Convert a naive BIDS datetime directly to a naive ReproStim datetime.
Routes through UTC internally:
dt_utc_to_reprostim(dt_bids_to_utc(dt, bids_tz), reprostim_tz).- Parameters:
dt (datetime.datetime) – Naive BIDS
acq_timedatetime.bids_tz (datetime.tzinfo) – BIDS dataset timezone.
reprostim_tz (datetime.tzinfo) – ReproStim capture machine timezone.
- Returns:
Naive datetime in the ReproStim timezone.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_bids_to_utc(dt: datetime, tz: tzinfo) datetime[source]¶
Convert a naive BIDS datetime to a naive UTC datetime.
- Parameters:
dt (datetime.datetime) – Naive BIDS
acq_timedatetime.tz (datetime.tzinfo) – Timezone assumed for the BIDS timestamps.
- Returns:
Naive UTC datetime.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_convert(dt: datetime, tz_from: tzinfo, tz_to: tzinfo) datetime[source]¶
Convert a naive datetime from one timezone context to another.
Attaches tz_from to dt, converts to tz_to, then strips
tzinfoto return a naive datetime. This is the primitive that all higher-level helpers delegate to.- Parameters:
dt (datetime.datetime) – Naive source datetime (no
tzinfo).tz_from (datetime.tzinfo) – Timezone the naive dt implicitly represents.
tz_to (datetime.tzinfo) – Target timezone to convert into.
- Returns:
Naive datetime in tz_to.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_parse_bids(s: str) datetime[source]¶
Parse a BIDS
acq_timeISO 8601 string to a naivedatetime.Any UTC offset present in s is stripped so the returned object has no
tzinfoattached, matching the naive-datetime convention used throughout this module.- Parameters:
s (str) – ISO 8601 datetime string, e.g.
'2025-08-14T15:06:09.742500'.- Returns:
Naive
datetime(notzinfo).- Return type:
datetime.datetime
- Raises:
ValueError – If s cannot be parsed as an ISO 8601 datetime.
- reprostim.qr.bids_inject.dt_parse_dicom_time(value: str) time[source]¶
Parse a DICOM TM (Time) string into a
datetime.timeobject.Accepts the DICOM TM format
HHMMSS.FFFFFFwhere:HH— hours, 00–23MM— minutes, 00–59SS— seconds, 00–60 (60 permitted for leap seconds; clamped to 59 fordatetime.timecompatibility).FFFFFF— optional fractional seconds (1–6 digits, right-padded with zeros to form microseconds)
- Parameters:
value (str) – DICOM TM string, e.g.
'151953.397500'or'151953'.- Returns:
Corresponding
datetime.timeinstance.- Return type:
datetime.time
- Raises:
ValueError – If value does not match the expected DICOM TM format.
- reprostim.qr.bids_inject.dt_reprostim_to_bids(dt: datetime, reprostim_tz: tzinfo, bids_tz: tzinfo) datetime[source]¶
Convert a naive ReproStim datetime directly to a naive BIDS datetime.
Routes through UTC internally:
dt_utc_to_bids(dt_reprostim_to_utc(dt, reprostim_tz), bids_tz).- Parameters:
dt (datetime.datetime) – Naive ReproStim datetime.
reprostim_tz (datetime.tzinfo) – ReproStim capture machine timezone.
bids_tz (datetime.tzinfo) – BIDS dataset timezone.
- Returns:
Naive datetime in the BIDS timezone.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_reprostim_to_utc(dt: datetime, tz: tzinfo) datetime[source]¶
Convert a naive ReproStim datetime to a naive UTC datetime.
- Parameters:
dt (datetime.datetime) – Naive ReproStim datetime from
videos.tsv.tz (datetime.tzinfo) – Timezone the ReproStim capture machine was using.
- Returns:
Naive UTC datetime.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_resolve_tz(name: str) tzinfo[source]¶
Resolve a timezone name string to a
datetime.tzinfoobject.Results are cached via
functools.lru_cache(), so repeated calls with the same name are free after the first resolution.- Parameters:
name (str) –
'local'to use the OS system timezone, or any IANA timezone name (e.g.'America/New_York','UTC').- Returns:
Corresponding
tzinfoinstance.- Return type:
datetime.tzinfo
- Raises:
ZoneInfoNotFoundError – If name is not a recognised IANA timezone.
- reprostim.qr.bids_inject.dt_time_to_sec(t: time) float[source]¶
Convert a
datetime.timeto total seconds since midnight.- Parameters:
t (datetime.time) – Time value to convert.
- Returns:
Total seconds since midnight, including microseconds as a fractional part.
- Return type:
float
- reprostim.qr.bids_inject.dt_tz_label(name: str) str[source]¶
Return the current UTC offset for a timezone name, e.g.
UTC-05:00.Resolves the timezone name via
dt_resolve_tz()and formats the UTC offset as"UTC±HH:MM", e.g."UTC-05:00"or"UTC+00:00".- Parameters:
name (str) – Timezone name accepted by
dt_resolve_tz().- Returns:
UTC offset string.
- Return type:
str
- reprostim.qr.bids_inject.dt_utc_to_bids(dt: datetime, tz: tzinfo) datetime[source]¶
Convert a naive UTC datetime to a naive BIDS-domain datetime.
- Parameters:
dt (datetime.datetime) – Naive UTC datetime.
tz (datetime.tzinfo) – Target timezone (BIDS dataset timezone).
- Returns:
Naive datetime in tz.
- Return type:
datetime.datetime
- reprostim.qr.bids_inject.dt_utc_to_reprostim(dt: datetime, tz: tzinfo) datetime[source]¶
Convert a naive UTC datetime to a naive ReproStim-domain datetime.
- Parameters:
dt (datetime.datetime) – Naive UTC datetime.
tz (datetime.tzinfo) – Target timezone (ReproStim capture machine timezone).
- Returns:
Naive datetime in tz.
- Return type:
datetime.datetime