Skip to content

session

SessionBuilder

SessionBuilder(
    launcher: Launcher,
    *,
    experimenter_validator: Callable[[str], str | None]
    | None = validate_username,
    use_cache: bool = True,
)

Assembles a :class:Session by asking the user who is running and on which animal.

This is the one genuinely interactive job with no database behind it, which is why it is not a store. It holds no state between calls, so a recovery flow can construct a session directly and narrow a store with store.scoped(subject=...) instead.

Example
session = SessionBuilder(launcher).build()
store = store.scoped(subject=session.subject)

Parameters:

Name Type Description Default
launcher Launcher

Supplies the repository state and hardware-validation settings stamped onto the session.

required
experimenter_validator Callable[[str], str | None] | None

Validates each experimenter name, returning the canonical name to store or None to reject it. If None, names are accepted as typed.

validate_username
use_cache bool

Whether to seed the prompts with previously entered values.

True
Source code in src/clabe/session.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def __init__(
    self,
    launcher: Launcher,
    *,
    experimenter_validator: Callable[[str], str | None] | None = validate_username,
    use_cache: bool = True,
) -> None:
    """
    Args:
        launcher: Supplies the repository state and hardware-validation settings stamped onto the session.
        experimenter_validator: Validates each experimenter name, returning the canonical name to store
            or None to reject it. If ``None``, names are accepted as typed.
        use_cache: Whether to seed the prompts with previously entered values.
    """
    self._launcher = launcher
    self._experimenter_validator = experimenter_validator
    self._use_cache = use_cache
    self._cache_manager = CacheManager.get_instance()

build

build() -> Session

Prompts for experimenter, subject and notes, and stamps the launcher's repository state.

Returns:

Type Description
Session

The assembled session.

Source code in src/clabe/session.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def build(self) -> Session:
    """
    Prompts for experimenter, subject and notes, and stamps the launcher's repository state.

    Returns:
        The assembled session.
    """
    experimenter = self.prompt_experimenter()
    subject = self.choose_subject()
    notes = ui.prompt_text(ui.TextRequest(label="Enter notes", field="notes"))
    settings = self._launcher.settings
    return Session(
        subject=subject,
        notes=notes,
        experimenter=experimenter,
        commit_hash=self._launcher.repository.head.commit.hexsha,
        allow_dirty_repo=settings.debug_mode or settings.allow_dirty,
        skip_hardware_validation=settings.skip_hardware_validation,
    )

choose_subject

choose_subject() -> str

Prompts for a subject, offering previously used ones for autocompletion.

Returns:

Type Description
str

The selected or entered subject name.

Source code in src/clabe/session.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def choose_subject(self) -> str:
    """
    Prompts for a subject, offering previously used ones for autocompletion.

    Returns:
        The selected or entered subject name.
    """
    subject = ""
    while not subject:
        subject = ui.prompt_autocomplete(
            ui.AutoCompleteRequest(
                label="Subject (type to filter, or enter a new one)",
                options=self._cached_options("subjects"),
                field="subject",
            )
        )
    self._cache_manager.add_to_cache("subjects", subject)
    return subject

prompt_experimenter

prompt_experimenter(strict: bool = True) -> list[str]

Prompts for the experimenter name(s), separated by commas or spaces.

Parameters:

Name Type Description Default
strict bool

Whether to reject empty input.

True

Returns:

Type Description
list[str]

The validated experimenter names.

Source code in src/clabe/session.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def prompt_experimenter(self, strict: bool = True) -> list[str]:
    """
    Prompts for the experimenter name(s), separated by commas or spaces.

    Args:
        strict: Whether to reject empty input.

    Returns:
        The validated experimenter names.
    """
    while True:
        entered = ui.prompt_autocomplete(
            ui.AutoCompleteRequest(
                label="Experimenter name(s) (type to filter, comma-separated for multiple)",
                options=self._cached_options("experimenters"),
                field="experimenter",
            )
        )
        experimenter = entered.replace(",", " ").split()
        if strict and not experimenter:
            ui.notify("Experimenter name is not valid. Try again.", ui.MessageLevel.WARNING)
            continue
        validated, invalid = self._validate_names(experimenter)
        if invalid:
            ui.notify(
                f"Experimenter name(s): {', '.join(invalid)}, is not valid. Try again", ui.MessageLevel.WARNING
            )
            continue
        self._cache_manager.add_to_cache("experimenters", ",".join(validated))
        return validated