sovabids.tui

Terminal User Interface for sovabids.

Classes

DirPickerScreen

Modal that lets user browse and confirm a directory.

SetupPane

FilesListScreen

Modal showing all matched files with extraction details on click.

ChannelNamesScreen

Modal showing channel names and types from a file.

RulesPane

MappingsPane

ConvertPane

SovabidsApp

sovabids TUI — EEG to BIDS conversion wizard.

Functions

_flatten_dict(→ dict)

Flatten nested dict with dot-notation keys.

main(→ None)

Module Contents

class sovabids.tui.DirPickerScreen(start: str = '.')

Bases: textual.screen.ModalScreen[str]

Modal that lets user browse and confirm a directory.

DEFAULT_CSS = Multiline-String
Show Value
"""
    DirPickerScreen {
        align: center middle;
    }
    DirPickerScreen > Vertical {
        width: 80%;
        height: 80%;
        border: thick $primary;
        background: $surface;
        padding: 1;
    }
    DirPickerScreen DirectoryTree {
        height: 1fr;
    }
    DirPickerScreen Label {
        height: 1;
        margin-bottom: 1;
    }
    DirPickerScreen Horizontal {
        height: 3;
        align: right middle;
    }
    DirPickerScreen Button {
        margin-left: 1;
    }
    """
_start = b'.'
compose() textual.app.ComposeResult
on_directory_tree_directory_selected(event: textual.widgets.DirectoryTree.DirectorySelected) None
on_button_pressed(event: textual.widgets.Button.Pressed) None
class sovabids.tui.SetupPane

Bases: textual.widgets.Static

DEFAULT_CSS = Multiline-String
Show Value
"""
    SetupPane { padding: 1 2; }
    SetupPane Label { margin-top: 1; }
    SetupPane .path-row { height: 3; }
    SetupPane Input { width: 1fr; }
    SetupPane Button { width: 14; margin-left: 1; }
    SetupPane .hint { color: $text-muted; margin-bottom: 1; }
    """
compose() textual.app.ComposeResult
on_button_pressed(event: textual.widgets.Button.Pressed) None
get_values() dict
class sovabids.tui.FilesListScreen(files: list[str], pattern: str = '', mode: str = 'placeholder', fields: list[str] | None = None)

Bases: textual.screen.ModalScreen

Modal showing all matched files with extraction details on click.

DEFAULT_CSS = Multiline-String
Show Value
"""
    FilesListScreen { align: center middle; }
    FilesListScreen > Vertical {
        width: 92%; height: 90%;
        border: thick $primary; background: $surface; padding: 1;
    }
    FilesListScreen DataTable { height: 1fr; }
    FilesListScreen #extraction-panel {
        height: auto;
        max-height: 40%;
        border: solid $primary;
        padding: 0 1;
        color: $success;
        overflow-y: auto;
    }
    FilesListScreen #extraction-panel.muted { color: $text-muted; }
    FilesListScreen #extraction-panel.error { color: $error; }
    FilesListScreen Horizontal { height: 3; align: right middle; }
    """
_files
_pattern = ''
_mode = 'placeholder'
_fields = []
compose() textual.app.ComposeResult
on_mount() None
on_data_table_row_highlighted(event: textual.widgets.DataTable.RowHighlighted) None
_show_extraction(filepath: str) None
on_button_pressed(event: textual.widgets.Button.Pressed) None
on_key(event) None
class sovabids.tui.ChannelNamesScreen(filepath: str)

Bases: textual.screen.ModalScreen

Modal showing channel names and types from a file.

DEFAULT_CSS = Multiline-String
Show Value
"""
    ChannelNamesScreen { align: center middle; }
    ChannelNamesScreen > Vertical {
        width: 70%; height: 85%;
        border: thick $primary; background: $surface; padding: 1;
    }
    ChannelNamesScreen DataTable { height: 1fr; }
    ChannelNamesScreen #ch-status { color: $text-muted; height: 1; }
    ChannelNamesScreen Horizontal { height: 3; align: right middle; }
    """
_filepath
compose() textual.app.ComposeResult
on_mount() None
_load_worker() None
_populate(ch_names: list, ch_types: list) None
on_button_pressed(event: textual.widgets.Button.Pressed) None
on_key(event) None
sovabids.tui._flatten_dict(d: dict, prefix: str = '') dict

Flatten nested dict with dot-notation keys.

class sovabids.tui.RulesPane

Bases: textual.widgets.Static

DEFAULT_CSS = Multiline-String
Show Value
"""
    RulesPane { padding: 1 2; }
    RulesPane Label { margin-top: 1; }
    RulesPane .hint { color: $text-muted; }
    RulesPane .pattern-examples {
        color: $text-muted;
        margin-bottom: 1;
        padding: 0 2;
        border-left: solid $primary;
    }
    RulesPane #ext-count { color: $text-muted; height: 1; margin-bottom: 1; }
    RulesPane #preview-row { height: auto; margin-top: 1; }
    RulesPane #preview-label {
        padding: 1;
        border: solid $primary;
        color: $success;
        width: 1fr;
        height: auto;
        min-height: 3;
    }
    RulesPane #preview-label.error { color: $error; }
    RulesPane #preview-label.muted { color: $text-muted; }
    RulesPane #show-files { width: 18; margin-left: 1; }
    RulesPane Select { margin-bottom: 1; }
    RulesPane Input { margin-bottom: 1; }
    RulesPane .section-head { margin-top: 1; }
    RulesPane RadioSet { margin-bottom: 1; }
    RulesPane #regex-fields-row { display: none; height: auto; }
    RulesPane #regex-fields-row.visible { display: block; }
    RulesPane #regex-examples { display: none; }
    RulesPane #regex-examples.visible { display: block; }
    RulesPane #io-example-row { display: none; height: auto; }
    RulesPane #io-examples { display: none; }
    RulesPane #io-src-row { height: 3; }
    RulesPane #io-src-row Input { width: 1fr; }
    RulesPane #io-src-row Button { width: 18; margin-left: 1; }
    RulesPane #pattern-section { height: auto; }
    RulesPane .inspect-row { height: 3; margin-bottom: 1; }
    RulesPane .inspect-row Button { margin-right: 1; }
    """
_preview_lock: ClassVar
_preview_timer = None
_matched_files: list[str] = []
compose() textual.app.ComposeResult
on_input_changed(event: textual.widgets.Input.Changed) None
on_select_changed(event: textual.widgets.Select.Changed) None
on_radio_set_changed(event: textual.widgets.RadioSet.Changed) None
on_button_pressed(event: textual.widgets.Button.Pressed) None
_get_mode_and_fields() tuple[str, list[str]]
_get_io_example() tuple[str, str]
_schedule_ext_count() None
_run_ext_count() None
_ext_count_worker(source: str, ext: str) None
_psd_worker(filepath: str) None
_schedule_preview() None
_run_preview() None
_preview_worker(source: str, pattern: str, ext: str, mode: str, fields: list[str], io_src: str = '', io_tgt: str = '') None
_update_show_files_btn(files: list[str]) None
_set_preview(text: str, css_class: str) None
_get_source() str
get_rules() dict
class sovabids.tui.MappingsPane

Bases: textual.widgets.Static

DEFAULT_CSS = Multiline-String
Show Value
"""
    MappingsPane { padding: 1 2; }
    MappingsPane #mappings-status { margin-bottom: 1; color: $text-muted; }
    MappingsPane DataTable { height: 1fr; }
    MappingsPane Horizontal { height: 3; margin-bottom: 1; }
    MappingsPane Button { margin-right: 1; }
    """
_mappings: textual.reactive.reactive[list]
compose() textual.app.ComposeResult
on_mount() None
on_button_pressed(event: textual.widgets.Button.Pressed) None
_generate() None
_gen_worker(source: str, bids: str, rules: dict) None
_populate_table(individuals: list) None
_save_mappings_yaml() None
_set_status(msg: str, error: bool = False) None
class sovabids.tui.ConvertPane

Bases: textual.widgets.Static

DEFAULT_CSS = Multiline-String
Show Value
"""
    ConvertPane { padding: 1 2; }
    ConvertPane Horizontal { height: 3; margin-bottom: 1; }
    ConvertPane Button { margin-right: 1; }
    ConvertPane RichLog { height: 1fr; border: solid $primary; }
    """
compose() textual.app.ComposeResult
on_button_pressed(event: textual.widgets.Button.Pressed) None
_start_convert() None
_convert_worker(mapping_data: dict) None
_log(msg: str) None
class sovabids.tui.SovabidsApp

Bases: textual.app.App

sovabids TUI — EEG to BIDS conversion wizard.

TITLE = 'sovabids'
SUB_TITLE = 'EEG BIDS conversion'
CSS = Multiline-String
Show Value
"""
    TabbedContent { height: 1fr; }
    TabPane { height: 1fr; }
    """
BINDINGS = [('q', 'quit', 'Quit'), ('ctrl+s', 'save_rules', 'Save rules')]
_mapping_data: dict | None = None
_pending_input_id: str = ''
compose() textual.app.ComposeResult
_on_dir_picked(path: str) None
action_save_rules() None
sovabids.tui.main() None