Skip to content

BidsExportRoutine

Bases: BaseStandaloneRoutine

This class provides methods for creating and managing BIDS datasets and their modality agnostic files plus modality specific files.

Source code in psychopy_bids/bids_settings/__init__.py
class BidsExportRoutine(BaseStandaloneRoutine):
    """
    This class provides methods for creating and managing BIDS datasets and their modality agnostic
    files plus modality specific files.
    """

    categories = ["BIDS"]
    targets = ["PsychoPy"]
    iconFile = Path(__file__).parent / "BIDS.png"
    tooltip = _translate(
        "BIDS export: creates BIDS structure, writes tsv file and update"
        " further files"
    )
    plugin = "psychopy-bids"

    def __init__(
        self,
        exp,
        name="bids",
        experiment_bids="bids",
        data_type="beh",
        acq="",
        event_json="",
        runs=True,
        bids_license="CC-BY-4.0",
    ):
        # Initialise base routine
        BaseStandaloneRoutine.__init__(self, exp, name=name)

        self.exp.requireImport(
            importName="BIDSHandler", importFrom="psychopy_bids.bids"
        )

        self.type = "BIDSexport"

        # Basic params
        self.order += ["data_type", "experiment_bids", "acq", "event_json"]

        self.params["name"].hint = _translate(
            "Name of the task. No two tasks should have the same name."
        )
        self.params["name"].label = _translate("task name")

        hnt = _translate(
            "Name of the experiment (parent folder), if this (task) is part of"
            " a larger one."
        )
        self.params["experiment_bids"] = Param(
            experiment_bids,
            valType="str",
            inputType="single",
            categ="Basic",
            allowedTypes=[],
            canBePath=False,
            hint=hnt,
            label=_translate("experiment name"),
        )

        hnt = _translate("BIDS defined data type")
        self.params["data_type"] = Param(
            data_type,
            valType="str",
            inputType="choice",
            categ="Basic",
            allowedVals=[
                "func",
                "dwi",
                "fmap",
                "anat",
                "perf",
                "meg",
                "eeg",
                "ieeg",
                "beh",
                "pet",
                "micr",
            ],
            hint=hnt,
            label=_translate("data type"),
        )

        hnt = _translate(
            "Custom label to distinguish different conditions present during"
            " multiple runs of the same task"
        )
        self.params["acq"] = Param(
            acq,
            valType="str",
            inputType="single",
            categ="Basic",
            allowedVals=[],
            canBePath=False,
            hint=hnt,
            label=_translate("acquisition mode"),
        )

        hnt = _translate(
            "Name of the default event JSON file. Will be copied into each"
            " subject folder."
        )
        self.params["event_json"] = Param(
            event_json,
            valType="str",
            inputType="file",
            allowedTypes=[],
            categ="Basic",
            updates="constant",
            allowedUpdates=["constant"],
            hint=hnt,
            label=_localized["event_json"],
        )

        # license
        hnt = _translate("License of the dataset")
        self.params["bids_license"] = Param(
            bids_license,
            valType="str",
            inputType="choice",
            categ="Basic",
            allowedVals=[
                "CC0-1.0",
                "CC-BY-4.0",
                "CC-BY-SA-4.0",
                "CC-BY-ND-4.0",
                "CC-BY-NC-4.0",
                "CC-BY-NC-SA-4.0",
                "CC-BY-NC-ND-4.0",
                "ODC-By-1.0",
                "ODbL-1.0",
                "PDDL-1.0",
                "GFDL-1.3-or-later",
            ],
            hint=hnt,
            label=_translate("license"),
        )

        # runs params
        hnt = _translate("Should runs be added to event file name?")
        self.params["runs"] = Param(
            runs,
            valType="bool",
            inputType="bool",
            categ="Basic",
            hint=hnt,
            label=_translate("Add runs to event filename"),
        )

        # these inherited params are harmless but might as well trim:
        for parameter in (
            "startType",
            "startVal",
            "startEstim",
            "stopVal",
            "stopType",
            "durationEstim",
            "saveStartStop",
            "syncScreenRefresh",
        ):
            if parameter in self.params:
                del self.params[parameter]

    def writeStartCode(self, buff):
        """Write code at the beginning of the experiment."""
        original_indent_level = buff.indentLevel
        inits = self.params

        code = "# create initial folder structure\nif expInfo['session']:\n"
        buff.writeIndentedLines(code)
        buff.setIndentLevel(1, relative=True)
        code = (
            "bids_handler = BIDSHandler(dataset=%(experiment_bids)s,\n"
            " subject=expInfo['participant'], task=expInfo['expName'],\n"
            " session=expInfo['session'], data_type=%(data_type)s, acq=%(acq)s,\n"
            " runs=%(runs)s)\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "else:"
        buff.writeIndentedLines(code)
        buff.setIndentLevel(1, relative=True)
        code = (
            "bids_handler = BIDSHandler(dataset=%(experiment_bids)s,\n"
            " subject=expInfo['participant'], task=expInfo['expName'],\n"
            " data_type=%(data_type)s, acq=%(acq)s, runs=%(runs)s)\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = (
            "bids_handler.createDataset()\n"
            "bids_handler.addLicense(%(bids_license)s)\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(original_indent_level)

    def writeExperimentEndCode(self, buff):
        """Write code at the end of the routine."""
        original_indent_level = buff.indentLevel
        inits = self.params

        code = (
            "# get participant_info and events from the ExperimentHandler\n"
            "ignore_list = [\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = (
            "'participant',\n"
            "'session',\n"
            "'date',\n"
            "'expName',\n"
            "'psychopyVersion',\n"
            "'OS',\n"
            "'frameRate'\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "]\nparticipant_info = {\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = (
            "key: thisExp.extraInfo[key]\n"
            "for key in thisExp.extraInfo\n"
            "if key not in ignore_list\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "}\n# write tsv file and update\ntry:\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = (
            "if any(isinstance(item, BIDSBehEvent) for item in bids_handler.events):\n"
        )
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = "event_file = bids_handler.writeBehEvents(participant_info)\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "else:\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = "event_file = bids_handler.writeTaskEvents(participant_info)\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "bids_handler.addJSONSidecar(\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = "event_file,\n%(event_json)s,\nthisExp.extraInfo['psychopyVersion']\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = ")\nbids_handler.addStimuliFolder(event_file)\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(-1, relative=True)
        code = "except KeyError:\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(1, relative=True)
        code = "pass\n"
        buff.writeIndentedLines(code % inits)
        buff.setIndentLevel(original_indent_level)

writeExperimentEndCode(buff)

Write code at the end of the routine.

Source code in psychopy_bids/bids_settings/__init__.py
def writeExperimentEndCode(self, buff):
    """Write code at the end of the routine."""
    original_indent_level = buff.indentLevel
    inits = self.params

    code = (
        "# get participant_info and events from the ExperimentHandler\n"
        "ignore_list = [\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = (
        "'participant',\n"
        "'session',\n"
        "'date',\n"
        "'expName',\n"
        "'psychopyVersion',\n"
        "'OS',\n"
        "'frameRate'\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "]\nparticipant_info = {\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = (
        "key: thisExp.extraInfo[key]\n"
        "for key in thisExp.extraInfo\n"
        "if key not in ignore_list\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "}\n# write tsv file and update\ntry:\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = (
        "if any(isinstance(item, BIDSBehEvent) for item in bids_handler.events):\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = "event_file = bids_handler.writeBehEvents(participant_info)\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "else:\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = "event_file = bids_handler.writeTaskEvents(participant_info)\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "bids_handler.addJSONSidecar(\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = "event_file,\n%(event_json)s,\nthisExp.extraInfo['psychopyVersion']\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = ")\nbids_handler.addStimuliFolder(event_file)\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "except KeyError:\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(1, relative=True)
    code = "pass\n"
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(original_indent_level)

writeStartCode(buff)

Write code at the beginning of the experiment.

Source code in psychopy_bids/bids_settings/__init__.py
def writeStartCode(self, buff):
    """Write code at the beginning of the experiment."""
    original_indent_level = buff.indentLevel
    inits = self.params

    code = "# create initial folder structure\nif expInfo['session']:\n"
    buff.writeIndentedLines(code)
    buff.setIndentLevel(1, relative=True)
    code = (
        "bids_handler = BIDSHandler(dataset=%(experiment_bids)s,\n"
        " subject=expInfo['participant'], task=expInfo['expName'],\n"
        " session=expInfo['session'], data_type=%(data_type)s, acq=%(acq)s,\n"
        " runs=%(runs)s)\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = "else:"
    buff.writeIndentedLines(code)
    buff.setIndentLevel(1, relative=True)
    code = (
        "bids_handler = BIDSHandler(dataset=%(experiment_bids)s,\n"
        " subject=expInfo['participant'], task=expInfo['expName'],\n"
        " data_type=%(data_type)s, acq=%(acq)s, runs=%(runs)s)\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(-1, relative=True)
    code = (
        "bids_handler.createDataset()\n"
        "bids_handler.addLicense(%(bids_license)s)\n"
    )
    buff.writeIndentedLines(code % inits)
    buff.setIndentLevel(original_indent_level)