From 6ed03da442dd60c92d7b8088f36409e34b302808 Mon Sep 17 00:00:00 2001 From: olivier Date: Thu, 20 Jun 2024 10:48:20 +0100 Subject: [PATCH 01/43] WIP fibrephotometry --- docs/source/usage_neurophotometrics.rst | 130 ++++++++++++++++++++++++ iblrig/commands.py | 11 +- iblrig/pydantic_definitions.py | 5 + iblrig/transfer_experiments.py | 13 +++ 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 docs/source/usage_neurophotometrics.rst diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst new file mode 100644 index 000000000..0ca36e5a8 --- /dev/null +++ b/docs/source/usage_neurophotometrics.rst @@ -0,0 +1,130 @@ +Neurophotometrics recording with iblrigv8 +========================================= + +This document describes how to use the iblrigv8 software to record Photometry using Neurophotometrics FP3002 system. + +Setup +----- + +Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer. + +.. code:: yaml + + device_neurophotometrics: + BONSAI_WORKFLOW: devices/neurophotometrics/photometry_NP3002.bonsai + + + +Starting a task +--------------- + +Below shows how to start the electrophysiology for the subject 'example' with 2 probes: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_ephys_session example 2 + + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag ephys + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + + +Look at the raw data +-------------------- + +This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display. + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + viewephys + +.. image:: img/viewephys.png + :width: 800 + :alt: Alternative text + + +More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephysNeuropixel recording with iblrigv8 +================================== + +This document describes how to use the iblrigv8 software to record from the Neuropixel computer. + +Setup +----- + +Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer. + +To get access to the viewephys visualizer: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + pip install viewephys + +Starting a task +--------------- + +Below shows how to start the electrophysiology for the subject 'example' with 2 probes: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_ephys_session example 2 + + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag ephys + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + + +Look at the raw data +-------------------- + +This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display. + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + viewephys + +.. image:: img/viewephys.png + :width: 800 + :alt: Alternative text + + +More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys \ No newline at end of file diff --git a/iblrig/commands.py b/iblrig/commands.py index 18e50223c..37c2298d2 100644 --- a/iblrig/commands.py +++ b/iblrig/commands.py @@ -12,13 +12,18 @@ from iblrig.hardware import Bpod from iblrig.online_plots import OnlinePlots from iblrig.path_helper import get_local_and_remote_paths -from iblrig.transfer_experiments import BehaviorCopier, EphysCopier, SessionCopier, VideoCopier +from iblrig.transfer_experiments import BehaviorCopier, EphysCopier, NeurophotometricsCopier, SessionCopier, VideoCopier from iblutil.util import setup_logger logger = logging.getLogger(__name__) -tag2copier = {'behavior': BehaviorCopier, 'video': VideoCopier, 'ephys': EphysCopier} +tag2copier = { + 'behavior': BehaviorCopier, + 'video': VideoCopier, + 'ephys': EphysCopier, + 'neurophotometrics': NeurophotometricsCopier, +} def _transfer_parser(description: str) -> argparse.ArgumentParser: @@ -102,7 +107,7 @@ def transfer_video_data_cli(): setup_logger('iblrig', level='INFO') warnings.warn( 'transfer_video_data will be removed in the future. Use "transfer_data video" instead.', FutureWarning, stacklevel=2 - ) + ) # see transfer_data_cli above args = _transfer_parser('Copy video data to the local server.').parse_args() transfer_data(**{**vars(args), 'tag': 'video'}, interactive=True) diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index 0d68312a4..85e895701 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -162,6 +162,10 @@ class HardwareSettingsCamera(BunchModel): ) +class HardwareSettingsNeurophotometrics(BunchModel): + BONSAI_WORKFLOW: Path + + class HardwareSettingsCameraWorkflow(BunchModel): setup: ExistingFilePath | None = Field( title='Optional camera setup workflow', @@ -200,6 +204,7 @@ class HardwareSettings(BunchModel): device_scale: HardwareSettingsScale = HardwareSettingsScale() device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None device_microphone: HardwareSettingsMicrophone | None = None + device_neurophotometrics: HardwareSettingsNeurophotometrics | None = None VERSION: str diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index c4d3ef266..891bfbbed 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -580,3 +580,16 @@ def _copy_collections(self): remote_folder=self.remote_session_path.joinpath('raw_ephys_data'), overwrite=True, ) + + +class NeurophotometricsCopier(SessionCopier): + tag = 'neurophotometrics' + assert_connect_on_init = True + + def initialize_experiment(self, acquisition_description=None, **kwargs): + if not acquisition_description: + acquisition_description = dict(devices={'neurophotometrics': {'NP3002': None}}) + # TODO add the sync file with DAQami + # sync_file = Path(iblrig.__file__).parent.joinpath('device_descriptions', 'sync', 'daqami.yaml') + self._experiment_description = acquisition_description + super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) From c472fa347eff46077e2fa463e1708e62a2acbc71 Mon Sep 17 00:00:00 2001 From: owinter Date: Thu, 20 Jun 2024 14:37:51 +0100 Subject: [PATCH 02/43] WIP photometry copiers / starters --- docs/source/usage_neurophotometrics.rst | 7 ++-- iblrig/neurophotometrics.py | 52 +++++++++++++++++++++++++ iblrig/pydantic_definitions.py | 12 +++--- pyproject.toml | 1 + 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 iblrig/neurophotometrics.py diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index 0ca36e5a8..cea20a5bb 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -10,10 +10,11 @@ Just make sure iblrigv8 is installed according to the instructions and that the file is configured with the local folder and remote folder for the data transfer. .. code:: yaml - + RIG_NAME: photometry + MAIN_SYNC: False device_neurophotometrics: - BONSAI_WORKFLOW: devices/neurophotometrics/photometry_NP3002.bonsai - + BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai + VERSION: 1.0.0 Starting a task diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py new file mode 100644 index 000000000..1e5df98a0 --- /dev/null +++ b/iblrig/neurophotometrics.py @@ -0,0 +1,52 @@ +import argparse +import datetime +import logging +from pathlib import Path + +from iblutil.util import setup_logger +import iblrig +from iblrig.tools import call_bonsai +import iblrig.path_helper + +from iblrig.pydantic_definitions import HardwareSettings + +_logger = logging.getLogger(__name__) + + +def start_workflow(debug: bool = False): + # TODO docstring + # format the current date and time as a standard string + datestr = datetime.datetime.now().strftime('%Y-%m-%d') + timestr = datetime.datetime.now().strftime('T%H%M%S') + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) + _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') + bonsai_params = { + 'FilenamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), + 'FilenameDO0': str(folder_neurophotometrics.joinpath('bonsai_DO0.csv')), + 'FilenameDO1': str(folder_neurophotometrics.joinpath('bonsai_DO1.csv')), + 'FilenameDI0': str(folder_neurophotometrics.joinpath('bonsai_DI0.csv')), + } + hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai(workflow_file, debug=debug, parameters=bonsai_params) + + +def init_neurophotometrics_session(): + # TODO this needs to link the session (subject/date/number) to a photometry recording + # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) + # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) + pass + + +def start_workflow_cmd(): + """ + Command line interface for preparing a neurophotometrics session on the photometry computer + :return: + """ + parser = argparse.ArgumentParser(prog='start_photometry_recording', + description='Prepare photometry computer PC for recording session.') + parser.add_argument('--debug', action='store_true', help='enable debugging mode') + args = parser.parse_args() + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') + start_workflow(debug=args.debug) diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index 85e895701..83149c3a4 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -195,12 +195,12 @@ class HardwareSettings(BunchModel): model_config = ConfigDict(title='hardware_settings.yaml') RIG_NAME: str MAIN_SYNC: bool - device_bpod: HardwareSettingsBpod - device_frame2ttl: HardwareSettingsFrame2TTL - device_rotary_encoder: HardwareSettingsRotaryEncoder - device_screen: HardwareSettingsScreen - device_sound: HardwareSettingsSound - device_valve: HardwareSettingsValve + device_bpod: HardwareSettingsBpod | None = None + device_frame2ttl: HardwareSettingsFrame2TTL | None = None + device_rotary_encoder: HardwareSettingsRotaryEncoder | None = None + device_screen: HardwareSettingsScreen | None = None + device_sound: HardwareSettingsSound | None = None + device_valve: HardwareSettingsValve | None = None device_scale: HardwareSettingsScale = HardwareSettingsScale() device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None device_microphone: HardwareSettingsMicrophone | None = None diff --git a/pyproject.toml b/pyproject.toml index 9a0e613c6..cfa8d18be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ install_spinnaker = "iblrig.video:install_spinnaker" install_pyspin = "iblrig.video:install_pyspin" start_video_session = "iblrig.video:prepare_video_session_cmd" start_ephys_session = "iblrig.ephys:prepare_ephys_session_cmd" +start_neurophotometrics = 'iblrig.neurophotometrics:start_workflow_cmd' convert_uis = "iblrig.gui.tools:convert_uis" validate_iblrig = "iblrig.hardware_validation:run_all_validators_cli" validate_video = "iblrig.video:validate_video_cmd" From ccbb381b8af9ce0641a37fc6a96cbb623f63479d Mon Sep 17 00:00:00 2001 From: owinter Date: Mon, 24 Jun 2024 12:32:50 +0100 Subject: [PATCH 03/43] Start photometry workflow --- iblrig/neurophotometrics.py | 13 +++++++------ iblrig/tools.py | 12 ++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 1e5df98a0..a1705b7e6 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -22,14 +22,15 @@ def start_workflow(debug: bool = False): folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') bonsai_params = { - 'FilenamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), - 'FilenameDO0': str(folder_neurophotometrics.joinpath('bonsai_DO0.csv')), - 'FilenameDO1': str(folder_neurophotometrics.joinpath('bonsai_DO1.csv')), - 'FilenameDI0': str(folder_neurophotometrics.joinpath('bonsai_DI0.csv')), + 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), } hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) - call_bonsai(workflow_file, debug=debug, parameters=bonsai_params) + # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai( + workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002.bonsai'), + parameters=bonsai_params, + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), + ) def init_neurophotometrics_session(): diff --git a/iblrig/tools.py b/iblrig/tools.py index 99ab066f4..429dbb6bd 100644 --- a/iblrig/tools.py +++ b/iblrig/tools.py @@ -201,7 +201,10 @@ def _build_bonsai_cmd( debug: bool = False, bootstrap: bool = True, editor: bool = True, -) -> list[str]: + wait: bool = True, + check: bool = False, + bonsai_executable: str | Path = None, +) -> subprocess.Popen[bytes] | subprocess.Popen[str | bytes | Any] | subprocess.CompletedProcess: """ Execute a Bonsai workflow within a subprocess call. @@ -232,14 +235,15 @@ def _build_bonsai_cmd( If the Bonsai executable does not exist. If the specified workflow file does not exist. """ - if not BONSAI_EXE.exists(): - raise FileNotFoundError(BONSAI_EXE) + bonsai_executable = BONSAI_EXE if bonsai_executable is None else bonsai_executable + if not bonsai_executable.exists(): + raise FileNotFoundError(bonsai_executable) workflow_file = Path(workflow_file) if not workflow_file.exists(): raise FileNotFoundError(workflow_file) create_bonsai_layout_from_template(workflow_file) - cmd = [str(BONSAI_EXE), str(workflow_file)] + cmd = [str(bonsai_executable), str(workflow_file)] if start: cmd.append('--start' if debug else '--start-no-debug') if not editor: From e728df5521975479eabb9a708e92b732c96f7b4f Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 28 Jun 2024 13:06:20 +0100 Subject: [PATCH 04/43] photometry: start bonsai workflow script --- .../FP3002_digital_inputs.bonsai | 102 ++++++++++++++ .../FP3002_digital_inputs.bonsai.layout | 101 ++++++++++++++ iblrig/neurophotometrics.py | 127 ++++++++++-------- 3 files changed, 277 insertions(+), 53 deletions(-) create mode 100644 devices/neurophotometrics/FP3002_digital_inputs.bonsai create mode 100644 devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai b/devices/neurophotometrics/FP3002_digital_inputs.bonsai new file mode 100644 index 000000000..39d58619c --- /dev/null +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai @@ -0,0 +1,102 @@ + + + + + + + + + + StartPhotometry + COM3 + + + 0 + Green + + + 928 + 224 + + + 194 + 194 + + 928 + 224 + 194 + 194 + + G0 + + + 1 + Green + + + 900 + 417 + + + 194 + 188 + + 900 + 417 + 194 + 188 + + G1 + + + + + + + + + + + + + false + false + false + D:\iblrigv8_data\neurophotometrics\2024-06-25\T115602\raw_photometry.csv + None + + + + + true + true + false + false + + + + + + + D:\iblrigv8_data\neurophotometrics\2024-06-25\T114558\digitial_input_1.csv + false + false + None + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout b/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout new file mode 100644 index 000000000..2e84050a0 --- /dev/null +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout @@ -0,0 +1,101 @@ + + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + \ No newline at end of file diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index a1705b7e6..876230aca 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -1,53 +1,74 @@ -import argparse -import datetime -import logging -from pathlib import Path - -from iblutil.util import setup_logger -import iblrig -from iblrig.tools import call_bonsai -import iblrig.path_helper - -from iblrig.pydantic_definitions import HardwareSettings - -_logger = logging.getLogger(__name__) - - -def start_workflow(debug: bool = False): - # TODO docstring - # format the current date and time as a standard string - datestr = datetime.datetime.now().strftime('%Y-%m-%d') - timestr = datetime.datetime.now().strftime('T%H%M%S') - dict_paths = iblrig.path_helper.get_local_and_remote_paths() - folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) - _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') - bonsai_params = { - 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), - } - hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) - call_bonsai( - workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002.bonsai'), - parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), - ) - - -def init_neurophotometrics_session(): - # TODO this needs to link the session (subject/date/number) to a photometry recording - # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) - # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) - pass - - -def start_workflow_cmd(): - """ - Command line interface for preparing a neurophotometrics session on the photometry computer - :return: - """ - parser = argparse.ArgumentParser(prog='start_photometry_recording', - description='Prepare photometry computer PC for recording session.') - parser.add_argument('--debug', action='store_true', help='enable debugging mode') - args = parser.parse_args() - setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(debug=args.debug) +import argparse +import datetime +import logging +from pathlib import Path + +from iblutil.util import setup_logger, rrmdir +import iblrig +from iblrig.tools import call_bonsai +import iblrig.path_helper + +from iblrig.pydantic_definitions import HardwareSettings + +_logger = logging.getLogger(__name__) + + +def start_workflow(debug: bool = False): + # TODO docstring + # format the current date and time as a standard string + datestr = datetime.datetime.now().strftime('%Y-%m-%d') + timestr = datetime.datetime.now().strftime('T%H%M%S') + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) + bonsai_params = { + 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), + 'FileNameDigitalInput': str(folder_neurophotometrics.joinpath('digital_inputs.csv')), + 'PortName': 'COM3' # TODO: hardware settings + } + _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') + rrmdir(folder_neurophotometrics) + folder_neurophotometrics.mkdir(parents=True, exist_ok=True) + hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai( + workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002_digital_inputs.bonsai'), + parameters=bonsai_params, + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + start=False, + ) + rrmdir(folder_neurophotometrics) + # TODO we call the init sessions here + +def init_neurophotometrics_session(): + # TODO this needs to link the session (subject/date/number) to a photometry recording + # this means + # 1) link from one session to possibly several regions (ie. columns of the datafile) + # 2) link one session to a digital input number + # we use a single entry point for both modes of acquisition (ie. with or without a daq) + + # first read in the columns name from the photometry file + # then locate the sessions acquired from the same day on the local server + # for the case without a DAQ + # at last the digital input is hardcoded from input1 input0 + # for the case with a DAQ + # we need a hardware setting linking the rig name to a daq channel + # we get the rig name from the stub file on the server / UDP or ask for it in the GUI + + # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) + # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) + + + pass + + +def start_workflow_cmd(): + """ + Command line interface for preparing a neurophotometrics session on the photometry computer + :return: + """ + parser = argparse.ArgumentParser(prog='start_photometry_recording', + description='Prepare photometry computer PC for recording session.') + parser.add_argument('--debug', action='store_true', help='enable debugging mode') + args = parser.parse_args() + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') + start_workflow(debug=args.debug) From 1360ce65c90b7f1e75a6947e03b89cdae82f8d14 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:04:03 +0100 Subject: [PATCH 05/43] minimal set of parameters to start a photometry session --- docs/source/usage_neurophotometrics.rst | 94 ++----------------------- iblrig/neurophotometrics.py | 17 ++--- iblrig/pydantic_definitions.py | 1 + 3 files changed, 16 insertions(+), 96 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index cea20a5bb..27761dc7d 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -6,14 +6,16 @@ This document describes how to use the iblrigv8 software to record Photometry us Setup ----- -Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py -file is configured with the local folder and remote folder for the data transfer. +- iblrigv8 is installed according to the instructions +- `settings/iblrig_settings.yaml` file is configured with the local folder and remote folder for the data transfer. +- `settings/hardware_settings.yaml` file is configured with the neurophotometrics device .. code:: yaml RIG_NAME: photometry MAIN_SYNC: False device_neurophotometrics: BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai + COM_NEUROPHOTOMETRY: 'COM3' VERSION: 1.0.0 @@ -26,7 +28,7 @@ Below shows how to start the electrophysiology for the subject 'example' with 2 cd C:\iblrigv8\ venv\scripts\Activate.ps1 - start_ephys_session example 2 + start_neurophotometrics Copy command @@ -40,92 +42,8 @@ To initiate the data transfer from the local server to the remote server, open a .. code:: powershell C:\iblrigv8\venv\scripts\Activate.ps1 - transfer_data --tag ephys + transfer_data --tag photometry The transfer local and remote directories are set in the ``iblrig/settings/iblrig_settings.py`` file. - -Look at the raw data --------------------- - -This will launch the viewephys GUI, you can then use file -> open and navigate -to open the raw data file you wish to display. - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - viewephys - -.. image:: img/viewephys.png - :width: 800 - :alt: Alternative text - - -More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephysNeuropixel recording with iblrigv8 -================================== - -This document describes how to use the iblrigv8 software to record from the Neuropixel computer. - -Setup ------ - -Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py -file is configured with the local folder and remote folder for the data transfer. - -To get access to the viewephys visualizer: - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - pip install viewephys - -Starting a task ---------------- - -Below shows how to start the electrophysiology for the subject 'example' with 2 probes: - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - start_ephys_session example 2 - - -Copy command ------------- - -Usage -~~~~~ - -To initiate the data transfer from the local server to the remote server, open a terminal and type. - -.. code:: powershell - - C:\iblrigv8\venv\scripts\Activate.ps1 - transfer_data --tag ephys - -The transfer local and remote directories are set in the -``iblrig/settings/iblrig_settings.py`` file. - - -Look at the raw data --------------------- - -This will launch the viewephys GUI, you can then use file -> open and navigate -to open the raw data file you wish to display. - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - viewephys - -.. image:: img/viewephys.png - :width: 800 - :alt: Alternative text - - -More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys \ No newline at end of file diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 876230aca..512f8a456 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,9 +13,11 @@ _logger = logging.getLogger(__name__) -def start_workflow(debug: bool = False): +def start_workflow(): # TODO docstring # format the current date and time as a standard string + hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + settings = hardware_settings['device_neurophotometrics'] datestr = datetime.datetime.now().strftime('%Y-%m-%d') timestr = datetime.datetime.now().strftime('T%H%M%S') dict_paths = iblrig.path_helper.get_local_and_remote_paths() @@ -23,20 +25,19 @@ def start_workflow(debug: bool = False): bonsai_params = { 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), 'FileNameDigitalInput': str(folder_neurophotometrics.joinpath('digital_inputs.csv')), - 'PortName': 'COM3' # TODO: hardware settings + 'PortName': settings.COM_NEUROPHOTOMETRY, } _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') - rrmdir(folder_neurophotometrics) folder_neurophotometrics.mkdir(parents=True, exist_ok=True) - hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + + workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) call_bonsai( - workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002_digital_inputs.bonsai'), + workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings start=False, ) - rrmdir(folder_neurophotometrics) + # TODO we call the init sessions here def init_neurophotometrics_session(): diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index 83149c3a4..b7d329ef6 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -164,6 +164,7 @@ class HardwareSettingsCamera(BunchModel): class HardwareSettingsNeurophotometrics(BunchModel): BONSAI_WORKFLOW: Path + COM_NEUROPHOTOMETRY: str | None = None class HardwareSettingsCameraWorkflow(BunchModel): From 32c9eccecf451f8a5ffd62521cf0a75275b15f93 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:25:26 +0100 Subject: [PATCH 06/43] add the default bonsai path relative to home --- iblrig/neurophotometrics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 512f8a456..5d072a83d 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -31,10 +31,11 @@ def start_workflow(): folder_neurophotometrics.mkdir(parents=True, exist_ok=True) workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) + call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), # TODO: hardware settings start=False, ) From 5f98134608153d7bfaccbac36714fc7e1b4439f5 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:33:15 +0100 Subject: [PATCH 07/43] debug arguement --- iblrig/neurophotometrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 5d072a83d..d7a10392c 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,7 +13,7 @@ _logger = logging.getLogger(__name__) -def start_workflow(): +def start_workflow(debug=False): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) From a309c94efdc78119138fcdaabaf51389d61b0f08 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:36:55 +0100 Subject: [PATCH 08/43] bonsai executable --- iblrig/neurophotometrics.py | 2 +- iblrig/tools.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index d7a10392c..3e6e48f10 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,7 +13,7 @@ _logger = logging.getLogger(__name__) -def start_workflow(debug=False): +def start_workflow(debug=False, ): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) diff --git a/iblrig/tools.py b/iblrig/tools.py index 429dbb6bd..701f33d3c 100644 --- a/iblrig/tools.py +++ b/iblrig/tools.py @@ -265,6 +265,7 @@ def call_bonsai( editor: bool = True, wait: bool = True, check: bool = False, + bonsai_executable: str | Path = None, ) -> subprocess.Popen[bytes] | subprocess.Popen[str | bytes | Any] | subprocess.CompletedProcess: """ Execute a Bonsai workflow within a subprocess call. @@ -302,7 +303,7 @@ def call_bonsai( If the specified workflow file does not exist. """ - cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor) + cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor, bonsai_executable=bonsai_executable) cwd = Path(workflow_file).parent log.info(f'Starting Bonsai workflow `{workflow_file.name}`') log.debug(' '.join(map(str, cmd))) From 63f1cb9523814780951dea2c71b9a38bc03a31df Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 11:36:21 +0100 Subject: [PATCH 09/43] add documentation --- docs/source/usage_neurophotometrics.rst | 10 +++++++--- iblrig/neurophotometrics.py | 5 +---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index 27761dc7d..b98bb086a 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -16,19 +16,23 @@ Setup device_neurophotometrics: BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai COM_NEUROPHOTOMETRY: 'COM3' - VERSION: 1.0.0 Starting a task --------------- -Below shows how to start the electrophysiology for the subject 'example' with 2 probes: - +- Start the Bonsai workflow by running the following command in powershell: .. code:: powershell cd C:\iblrigv8\ venv\scripts\Activate.ps1 start_neurophotometrics +- in Bonsai click on the FP3002 node and load the desired photometry settings file +- start the task + +The task will start and the photometry data will be saved in the data local folder with the following stucture: +- {local_data_folder}\neurophotometrics\yyyy-mm-dd\THHMMSS +Where yyyy-mm-dd is the date of the recording and HHMMSS is the time of the recording. Copy command diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 3e6e48f10..0f49e5e07 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -35,10 +35,9 @@ def start_workflow(debug=False, ): call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), # TODO: hardware settings + bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), start=False, ) - # TODO we call the init sessions here def init_neurophotometrics_session(): @@ -58,8 +57,6 @@ def init_neurophotometrics_session(): # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) - - pass From e577630e949c80a04f676e1fd0547cc24b527b62 Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 11 Oct 2024 16:37:52 +0100 Subject: [PATCH 10/43] WIP copier photometry --- docs/source/usage_neurophotometrics.rst | 33 ++++++++++++++++++------- iblrig/graphic.py | 7 ++---- iblrig/neurophotometrics.py | 3 ++- iblrig/pydantic_definitions.py | 4 ++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index b98bb086a..4c7a1e23d 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -10,16 +10,18 @@ Setup - `settings/iblrig_settings.yaml` file is configured with the local folder and remote folder for the data transfer. - `settings/hardware_settings.yaml` file is configured with the neurophotometrics device -.. code:: yaml - RIG_NAME: photometry - MAIN_SYNC: False - device_neurophotometrics: - BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai - COM_NEUROPHOTOMETRY: 'COM3' + .. code:: yaml + RIG_NAME: photometry + MAIN_SYNC: False + device_neurophotometrics: + DEVICE_MODEL: NP3002 + BONSAI_EXECUTABLE: C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe + BONSAI_WORKFLOW: devices\neurophotometrics\FP3002.bonsai + COM_NEUROPHOTOMETRY: COM3 -Starting a task ---------------- +Starting a photometry recording +-------------------------------- - Start the Bonsai workflow by running the following command in powershell: .. code:: powershell @@ -30,11 +32,24 @@ Starting a task - in Bonsai click on the FP3002 node and load the desired photometry settings file - start the task -The task will start and the photometry data will be saved in the data local folder with the following stucture: +The photometry recording will start and the photometry data will be saved in the data local folder with the following stucture: - {local_data_folder}\neurophotometrics\yyyy-mm-dd\THHMMSS Where yyyy-mm-dd is the date of the recording and HHMMSS is the time of the recording. + +Starting a photometry session +-------------------------------- + +- Start the Bonsai workflow by running the following command in powershell: +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_photometry_session --subject=Mickey --roi G0 G1 --location NBM SI + + + Copy command ------------ diff --git a/iblrig/graphic.py b/iblrig/graphic.py index 9301bbeb2..16e19bc12 100644 --- a/iblrig/graphic.py +++ b/iblrig/graphic.py @@ -1,10 +1,7 @@ """Popup and string input prompts""" - -import tkinter as tk -from tkinter import simpledialog - - def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): + import tkinter as tk + from tkinter import simpledialog root = tk.Tk() root.withdraw() ask = simpledialog.askinteger if askint else simpledialog.askfloat diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 0f49e5e07..88aa6eb57 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -17,7 +17,7 @@ def start_workflow(debug=False, ): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - settings = hardware_settings['device_neurophotometrics'] + settings = hardware_settings.device_neurophotometrics datestr = datetime.datetime.now().strftime('%Y-%m-%d') timestr = datetime.datetime.now().strftime('T%H%M%S') dict_paths = iblrig.path_helper.get_local_and_remote_paths() @@ -40,6 +40,7 @@ def start_workflow(debug=False, ): ) # TODO we call the init sessions here + def init_neurophotometrics_session(): # TODO this needs to link the session (subject/date/number) to a photometry recording # this means diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index b7d329ef6..c5b8efea7 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -163,7 +163,9 @@ class HardwareSettingsCamera(BunchModel): class HardwareSettingsNeurophotometrics(BunchModel): - BONSAI_WORKFLOW: Path + DEVICE_MODEL: Literal['NP3002'] = 'NP3002' + BONSAI_EXECUTABLE: ExistingFilePath = Path(Path.home().joinpath('AppData', 'Local', 'Bonsai', 'Bonsai.exe')) + BONSAI_WORKFLOW: Path = Path('devices', 'neurophotometrics', 'FP3002.bonsai') COM_NEUROPHOTOMETRY: str | None = None From bcc789d0415c5a38bd91034418b7a8b10d88098a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 16:54:02 +0100 Subject: [PATCH 11/43] save changes to the bonsai workflow --- .../FP3002_digital_inputs.bonsai | 76 ++++++++++++++----- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai b/devices/neurophotometrics/FP3002_digital_inputs.bonsai index 39d58619c..0f6ba23bc 100644 --- a/devices/neurophotometrics/FP3002_digital_inputs.bonsai +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai @@ -12,24 +12,24 @@ StartPhotometry - COM3 + COM4 0 Green - 928 - 224 + 824 + 492 - 194 - 194 + 166 + 180 - 928 - 224 - 194 - 194 + 824 + 492 + 166 + 180 G0 @@ -38,20 +38,58 @@ Green - 900 - 417 + 703 + 353 - 194 - 188 + 154 + 180 - 900 - 417 - 194 - 188 + 703 + 353 + 154 + 180 G1 + + 2 + Green + + + 943 + 134 + + + 180 + 176 + + 943 + 134 + 180 + 176 + + G2 + + + 3 + Green + + + 767 + 180 + + + 176 + 182 + + 767 + 180 + 176 + 182 + + G3 + @@ -66,7 +104,7 @@ false false false - D:\iblrigv8_data\neurophotometrics\2024-06-25\T115602\raw_photometry.csv + D:\iblrigv8_data\neurophotometrics\2024-10-10\T142948\raw_photometry.csv None @@ -82,7 +120,7 @@ - D:\iblrigv8_data\neurophotometrics\2024-06-25\T114558\digitial_input_1.csv + D:\iblrigv8_data\neurophotometrics\2024-10-10\T142948\digital_inputs.csv false false None From 732116c9d5de250d8fa39ae6cfacf30c23411c9b Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 11 Oct 2024 17:04:58 +0100 Subject: [PATCH 12/43] add argument parser --- iblrig/graphic.py | 3 +++ iblrig/neurophotometrics.py | 36 ++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/iblrig/graphic.py b/iblrig/graphic.py index 16e19bc12..afc0cfcfa 100644 --- a/iblrig/graphic.py +++ b/iblrig/graphic.py @@ -1,7 +1,10 @@ """Popup and string input prompts""" + + def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): import tkinter as tk from tkinter import simpledialog + root = tk.Tk() root.withdraw() ask = simpledialog.askinteger if askint else simpledialog.askfloat diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 88aa6eb57..cce46e46c 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -1,19 +1,19 @@ import argparse import datetime import logging +from collections.abc import Iterable from pathlib import Path -from iblutil.util import setup_logger, rrmdir import iblrig -from iblrig.tools import call_bonsai import iblrig.path_helper - from iblrig.pydantic_definitions import HardwareSettings +from iblrig.tools import call_bonsai +from iblutil.util import setup_logger _logger = logging.getLogger(__name__) -def start_workflow(debug=False, ): +def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], debug: bool = False): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) @@ -35,7 +35,7 @@ def start_workflow(debug=False, ): call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), + bonsai_executable=Path(Path.home().joinpath(r'AppData\Local\Bonsai\Bonsai.exe')), start=False, ) # TODO we call the init sessions here @@ -43,7 +43,7 @@ def start_workflow(debug=False, ): def init_neurophotometrics_session(): # TODO this needs to link the session (subject/date/number) to a photometry recording - # this means + # this means # 1) link from one session to possibly several regions (ie. columns of the datafile) # 2) link one session to a digital input number # we use a single entry point for both modes of acquisition (ie. with or without a daq) @@ -66,9 +66,25 @@ def start_workflow_cmd(): Command line interface for preparing a neurophotometrics session on the photometry computer :return: """ - parser = argparse.ArgumentParser(prog='start_photometry_recording', - description='Prepare photometry computer PC for recording session.') - parser.add_argument('--debug', action='store_true', help='enable debugging mode') + parser = argparse.ArgumentParser( + prog='start_photometry_recording', description='Prepare photometry computer PC for recording session.' + ) + parser.add_argument('-s', '--subject', type=str, required=True, help='Subject name') + parser.add_argument( + '-r', '--rois', nargs='+', type=str, required=True, help='Define ROI(s). Separate multiple values by spaces.' + ) + parser.add_argument( + '-l', + '--locations', + nargs='+', + type=str, + required=True, + help='Location of Fiber(s). Separate multiple values by spaces.', + ) + parser.add_argument('-d', '--debug', action='store_true', help='Enable debugging mode') args = parser.parse_args() + + assert len(args.roi) == len(args.location), 'The number of ROIs and locations must be the same.' + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(debug=args.debug) + start_workflow(subject=args.subject, rois=args.roi, locations=args.location, debug=args.debug) From 7e1eaf1a98779476af5303a7329d442fa9498f85 Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 11 Oct 2024 17:26:42 +0100 Subject: [PATCH 13/43] start_photometry_task_cmd --- iblrig/neurophotometrics.py | 28 ++++++++++++++-------------- pyproject.toml | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index cce46e46c..ac24ba66d 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -2,10 +2,9 @@ import datetime import logging from collections.abc import Iterable -from pathlib import Path -import iblrig import iblrig.path_helper +from iblrig.constants import BASE_PATH from iblrig.pydantic_definitions import HardwareSettings from iblrig.tools import call_bonsai from iblutil.util import setup_logger @@ -13,8 +12,10 @@ _logger = logging.getLogger(__name__) -def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], debug: bool = False): - # TODO docstring +def start_workflow_cmd(debug: bool = False): + """ + Start a photometry recording regardless of behaviour. + """ # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) settings = hardware_settings.device_neurophotometrics @@ -29,19 +30,16 @@ def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], } _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') folder_neurophotometrics.mkdir(parents=True, exist_ok=True) - - workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) - + workflow_file = BASE_PATH.joinpath(settings.BONSAI_WORKFLOW) call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r'AppData\Local\Bonsai\Bonsai.exe')), + bonsai_executable=settings.BONSAI_EXECUTABLE, start=False, ) - # TODO we call the init sessions here -def init_neurophotometrics_session(): +def init_neurophotometrics_session(subject: str, rois: Iterable[str], locations: Iterable[str], sync_channel: int = 1): # TODO this needs to link the session (subject/date/number) to a photometry recording # this means # 1) link from one session to possibly several regions (ie. columns of the datafile) @@ -61,9 +59,10 @@ def init_neurophotometrics_session(): pass -def start_workflow_cmd(): +def start_photometry_task_cmd(): """ - Command line interface for preparing a neurophotometrics session on the photometry computer + Command line interface for preparing a neurophotometrics session on the photometry computer. + start_photometry_recording -s Algernon --rois G0 G1 --locations :return: """ parser = argparse.ArgumentParser( @@ -79,12 +78,13 @@ def start_workflow_cmd(): nargs='+', type=str, required=True, - help='Location of Fiber(s). Separate multiple values by spaces.', + help='Location of Fiber(s). Separate multiple values by spaces. Usually Allen brain acronyms.', ) parser.add_argument('-d', '--debug', action='store_true', help='Enable debugging mode') + parser.add_argument('-c', '--sync-channel', type=int, default=1, help='Sync channel') args = parser.parse_args() assert len(args.roi) == len(args.location), 'The number of ROIs and locations must be the same.' setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(subject=args.subject, rois=args.roi, locations=args.location, debug=args.debug) + init_neurophotometrics_session(subject=args.subject, rois=args.roi, locations=args.location, sync_channel=args.sync_channel) diff --git a/pyproject.toml b/pyproject.toml index cfa8d18be..b9ec7ff05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ install_pyspin = "iblrig.video:install_pyspin" start_video_session = "iblrig.video:prepare_video_session_cmd" start_ephys_session = "iblrig.ephys:prepare_ephys_session_cmd" start_neurophotometrics = 'iblrig.neurophotometrics:start_workflow_cmd' +start_photometry_task = 'iblrig.neurophotometrics:start_photometry_task_cmd' convert_uis = "iblrig.gui.tools:convert_uis" validate_iblrig = "iblrig.hardware_validation:run_all_validators_cli" validate_video = "iblrig.video:validate_video_cmd" From cc037efdf615a9b53e236cdc2e896f65b452f03c Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 25 Oct 2024 11:02:02 +0100 Subject: [PATCH 14/43] add methods for converting bpod data into a dataframe --- iblrig/raw_data_loaders.py | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index 2fb33647d..a0e1e6d78 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -1,11 +1,14 @@ import json import logging +import re from pathlib import Path from typing import Any import pandas as pd +from pandas.core.dtypes.concat import union_categoricals log = logging.getLogger(__name__) +RE_PATTERN_EVENT = re.compile(r'^(\D+\d)_?(.+)$') def load_task_jsonable(jsonable_file: str | Path, offset: int | None = None) -> tuple[pd.DataFrame, list[Any]]: @@ -37,3 +40,80 @@ def load_task_jsonable(jsonable_file: str | Path, offset: int | None = None) -> trials_table = pd.DataFrame(trials_table) return trials_table, bpod_data + + +def bpod_session_events_to_dataframe(bpod_data: list[dict[str, Any]], trials: int | list[int] | slice | None = None): + """ + Convert Bpod session data into a single Pandas DataFrame. + + Parameters + ---------- + bpod_data : list of dict + A list of dictionaries as returned by load_task_jsonable, where each dictionary contains data for a single trial. + trials : int, list of int, slice, or None, optional + Specifies which trials to include in the DataFrame. All trials are included by default. + + Returns + ------- + pd.DataFrame + A Pandas DataFrame containing combined event data from the specified trials, with columns for time, event, channel, + and value. + """ + # define trial index + if trials is None: + trials = range(len(bpod_data)) + elif isinstance(trials, int): + return _bpod_trial_events_to_dataframe(bpod_data[trials], trials) + elif isinstance(trials, slice): + trials = range(len(bpod_data))[trials] + + # loop over requested trials + dataframes = [] + for trial in trials: + dataframes.append(_bpod_trial_events_to_dataframe(bpod_data[trial], trial)) + + # combine trials into a single dataframe + categories_event = union_categoricals([df['Event'] for df in dataframes]) + categories_channel = union_categoricals([df['Channel'] for df in dataframes]) + for df in dataframes: + df['Event'] = df['Event'].cat.set_categories(categories_event.categories) + df['Channel'] = df['Channel'].cat.set_categories(categories_channel.categories) + return pd.concat(dataframes, ignore_index=True) + + +def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: + """ + Convert a single Bpod trial's data into a Pandas DataFrame. + + Parameters + ---------- + bpod_trial_data : dict + A dictionary containing data for a single trial, including timestamps and events. + trial : int + An integer representing the trial index. + + Returns + ------- + pd.DataFrame + A Pandas DataFrame containing the event data for the specified trial, with columns for time, event, channel, and value. + """ + trial_start = bpod_trial_data['Trial start timestamp'] + trial_end = bpod_trial_data['Trial end timestamp'] + + # convert bpod trial data to list of tuples, containing timestamps and event-names + event_list = [(time, event) for event, times in bpod_trial_data['Events timestamps'].items() for time in times] + event_list = [(0, 'TrialStart')] + sorted(event_list) + [(trial_end - trial_start, 'TrialEnd')] + + # create dataframe + df = pd.DataFrame(data=event_list, columns=['Time', 'Event']) + df['Time'] = pd.to_timedelta(df['Time'] + trial_start, unit='seconds') + df['Event'] = df['Event'].astype('category') + df.insert(1, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) + + # deduce channels and values from event names + df[['Channel', 'Value']] = df['Event'].str.extract(RE_PATTERN_EVENT, expand=True) + df['Channel'] = df['Channel'].astype('category') + df['Value'] = df['Value'].replace({'Low': 0, 'High': 1, 'Out': 0, 'In': 1}) + df['Value'] = pd.to_numeric(df['Value'], errors='coerce', downcast='unsigned', dtype_backend='numpy_nullable') + + return df From aa4a8270725bfb5da5186ee86218b9f362e62f2c Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Sun, 27 Oct 2024 17:10:31 +0000 Subject: [PATCH 15/43] add methods for converting state timing to dataframe --- iblrig/raw_data_loaders.py | 55 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index a0e1e6d78..24caca57b 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import Any +import numpy as np import pandas as pd from pandas.core.dtypes.concat import union_categoricals @@ -56,7 +57,7 @@ def bpod_session_events_to_dataframe(bpod_data: list[dict[str, Any]], trials: in Returns ------- pd.DataFrame - A Pandas DataFrame containing combined event data from the specified trials, with columns for time, event, channel, + A Pandas DataFrame containing combined event data from the specified trials, with columns for time, trial, event, channel, and value. """ # define trial index @@ -95,7 +96,8 @@ def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) Returns ------- pd.DataFrame - A Pandas DataFrame containing the event data for the specified trial, with columns for time, event, channel, and value. + A Pandas DataFrame containing the event data for the specified trial, with columns for time, trial event, channel, + and value. """ trial_start = bpod_trial_data['Trial start timestamp'] trial_end = bpod_trial_data['Trial end timestamp'] @@ -117,3 +119,52 @@ def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) df['Value'] = pd.to_numeric(df['Value'], errors='coerce', downcast='unsigned', dtype_backend='numpy_nullable') return df + + +def bpod_session_states_to_dataframe(bpod_data: list[dict[str, Any]], trials: int | list[int] | slice | None = None): + """ + Convert Bpod session data into a single Pandas DataFrame. + + Parameters + ---------- + bpod_data : list of dict + A list of dictionaries as returned by load_task_jsonable, where each dictionary contains data for a single trial. + trials : int, list of int, slice, or None, optional + Specifies which trials to include in the DataFrame. All trials are included by default. + + Returns + ------- + pd.DataFrame + A Pandas DataFrame containing combined event data from the specified trials, with columns for time, trial, event, channel, + and value. + """ + # define trial index + if trials is None: + trials = range(len(bpod_data)) + elif isinstance(trials, slice): + trials = range(len(bpod_data))[trials] + + # loop over requested trials + dataframes = [] + for trial in trials: + dataframes.append(_bpod_trial_states_to_dataframe(bpod_data[trial], trial)) + + # combine trials into a single dataframe + categories_state = union_categoricals([df['State'] for df in dataframes]) + for df in dataframes: + df['State'] = df['State'].cat.set_categories(categories_state.categories) + return pd.concat(dataframes, ignore_index=True) + + +def _bpod_trial_states_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: + data = bpod_trial_data['States timestamps'] + trial_start = bpod_trial_data['Trial start timestamp'] + + state_list = sorted([(t0, t1, state) for state, times in data.items() for t0, t1 in times if not np.isnan(t0)]) + df = pd.DataFrame(data=state_list, columns=['Start Time', 'End Time', 'State']) + df['Start Time'] = pd.to_timedelta(df['Start Time'] + trial_start) + df['End Time'] = pd.to_timedelta(df['End Time'] + trial_start) + df['State'] = df['State'].astype('category') + df.insert(0, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) + + return df From b4bc6ab4a4d505f2874c964cb4eefd1d3a548c4f Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Sun, 27 Oct 2024 18:10:48 +0000 Subject: [PATCH 16/43] combine methods for getting trials data and event data as dataframes --- iblrig/raw_data_loaders.py | 116 +++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index 24caca57b..4a2cb091d 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -43,7 +43,7 @@ def load_task_jsonable(jsonable_file: str | Path, offset: int | None = None) -> return trials_table, bpod_data -def bpod_session_events_to_dataframe(bpod_data: list[dict[str, Any]], trials: int | list[int] | slice | None = None): +def bpod_session_data_to_dataframe(bpod_data: list[dict[str, Any]], trials: int | list[int] | slice | None = None): """ Convert Bpod session data into a single Pandas DataFrame. @@ -57,32 +57,50 @@ def bpod_session_events_to_dataframe(bpod_data: list[dict[str, Any]], trials: in Returns ------- pd.DataFrame - A Pandas DataFrame containing combined event data from the specified trials, with columns for time, trial, event, channel, - and value. + A Pandas DataFrame containing event data from the specified trials, with the following columns: + + * Time : datetime.timedelta + timestamp of the event (datetime.timedelta) + * Type : str (categorical) + type of the event (TrialStart, StateStart, InputEvent, etc.) + * Trial : int + index of the trial, zero-based + * State : str (categorical) + name of the state (only for types StateStart and StateEnd) + * Event : str (categorical) + name of the event (only for type InputEvent) + * Channel : str (categorical) + name of the event's channel (only for a subset of InputEvents) + * Value : int + value of the event (only for a subset of InputEvents) """ # define trial index if trials is None: trials = range(len(bpod_data)) elif isinstance(trials, int): - return _bpod_trial_events_to_dataframe(bpod_data[trials], trials) + return bpod_trial_data_to_dataframe(bpod_data[trials], trials) elif isinstance(trials, slice): trials = range(len(bpod_data))[trials] # loop over requested trials dataframes = [] for trial in trials: - dataframes.append(_bpod_trial_events_to_dataframe(bpod_data[trial], trial)) + dataframes.append(bpod_trial_data_to_dataframe(bpod_data[trial], trial)) # combine trials into a single dataframe + categories_type = union_categoricals([df['Type'] for df in dataframes]) + categories_state = union_categoricals([df['State'] for df in dataframes]) categories_event = union_categoricals([df['Event'] for df in dataframes]) categories_channel = union_categoricals([df['Channel'] for df in dataframes]) for df in dataframes: + df['Type'] = df['Type'].cat.set_categories(categories_type.categories) + df['State'] = df['State'].cat.set_categories(categories_state.categories) df['Event'] = df['Event'].cat.set_categories(categories_event.categories) df['Channel'] = df['Channel'].cat.set_categories(categories_channel.categories) return pd.concat(dataframes, ignore_index=True) -def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: +def bpod_trial_data_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: """ Convert a single Bpod trial's data into a Pandas DataFrame. @@ -96,21 +114,44 @@ def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) Returns ------- pd.DataFrame - A Pandas DataFrame containing the event data for the specified trial, with columns for time, trial event, channel, - and value. + A Pandas DataFrame containing event data from the specified trial, with the following columns: + + * Time : datetime.timedelta + timestamp of the event (datetime.timedelta) + * Type : str (categorical) + type of the event (TrialStart, StateStart, InputEvent, etc.) + * Trial : int + index of the trial, zero-based + * State : str (categorical) + name of the state (only for types StateStart and StateEnd) + * Event : str (categorical) + name of the event (only for type InputEvent) + * Channel : str (categorical) + name of the event's channel (only for a subset of InputEvents) + * Value : int + value of the event (only for a subset of InputEvents) """ trial_start = bpod_trial_data['Trial start timestamp'] trial_end = bpod_trial_data['Trial end timestamp'] - # convert bpod trial data to list of tuples, containing timestamps and event-names - event_list = [(time, event) for event, times in bpod_trial_data['Events timestamps'].items() for time in times] - event_list = [(0, 'TrialStart')] + sorted(event_list) + [(trial_end - trial_start, 'TrialEnd')] + state_times = bpod_trial_data['States timestamps'].items() + event_times = bpod_trial_data['Events timestamps'].items() + + # convert bpod data to list of tuples + event_list = [(0, 'TrialStart', pd.NA, pd.NA)] + event_list += [(t, 'StateStart', state, pd.NA) for state, times in state_times for t, _ in times if not np.isnan(t)] + event_list += [(t, 'InputEvent', pd.NA, event) for event, times in event_times for t in times] + event_list += [(t, 'StateEnd', state, pd.NA) for state, times in state_times for _, t in times if not np.isnan(t)] + event_list += [(trial_end - trial_start, 'TrialEnd', pd.NA, pd.NA)] + event_list = sorted(event_list) # create dataframe - df = pd.DataFrame(data=event_list, columns=['Time', 'Event']) + df = pd.DataFrame(data=event_list, columns=['Time', 'Type', 'State', 'Event']) df['Time'] = pd.to_timedelta(df['Time'] + trial_start, unit='seconds') + df['Type'] = df['Type'].astype('category') + df['State'] = df['State'].astype('category') df['Event'] = df['Event'].astype('category') - df.insert(1, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) + df.insert(2, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) # deduce channels and values from event names df[['Channel', 'Value']] = df['Event'].str.extract(RE_PATTERN_EVENT, expand=True) @@ -119,52 +160,3 @@ def _bpod_trial_events_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) df['Value'] = pd.to_numeric(df['Value'], errors='coerce', downcast='unsigned', dtype_backend='numpy_nullable') return df - - -def bpod_session_states_to_dataframe(bpod_data: list[dict[str, Any]], trials: int | list[int] | slice | None = None): - """ - Convert Bpod session data into a single Pandas DataFrame. - - Parameters - ---------- - bpod_data : list of dict - A list of dictionaries as returned by load_task_jsonable, where each dictionary contains data for a single trial. - trials : int, list of int, slice, or None, optional - Specifies which trials to include in the DataFrame. All trials are included by default. - - Returns - ------- - pd.DataFrame - A Pandas DataFrame containing combined event data from the specified trials, with columns for time, trial, event, channel, - and value. - """ - # define trial index - if trials is None: - trials = range(len(bpod_data)) - elif isinstance(trials, slice): - trials = range(len(bpod_data))[trials] - - # loop over requested trials - dataframes = [] - for trial in trials: - dataframes.append(_bpod_trial_states_to_dataframe(bpod_data[trial], trial)) - - # combine trials into a single dataframe - categories_state = union_categoricals([df['State'] for df in dataframes]) - for df in dataframes: - df['State'] = df['State'].cat.set_categories(categories_state.categories) - return pd.concat(dataframes, ignore_index=True) - - -def _bpod_trial_states_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: - data = bpod_trial_data['States timestamps'] - trial_start = bpod_trial_data['Trial start timestamp'] - - state_list = sorted([(t0, t1, state) for state, times in data.items() for t0, t1 in times if not np.isnan(t0)]) - df = pd.DataFrame(data=state_list, columns=['Start Time', 'End Time', 'State']) - df['Start Time'] = pd.to_timedelta(df['Start Time'] + trial_start) - df['End Time'] = pd.to_timedelta(df['End Time'] + trial_start) - df['State'] = df['State'].astype('category') - df.insert(0, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) - - return df From 34e8fdaf1865b3bef8852297179d2b6572d8190b Mon Sep 17 00:00:00 2001 From: olivier Date: Thu, 20 Jun 2024 10:48:20 +0100 Subject: [PATCH 17/43] WIP fibrephotometry --- docs/source/usage_neurophotometrics.rst | 130 ++++++++++++++++++++++++ iblrig/commands.py | 11 +- iblrig/pydantic_definitions.py | 5 + iblrig/transfer_experiments.py | 13 +++ 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 docs/source/usage_neurophotometrics.rst diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst new file mode 100644 index 000000000..0ca36e5a8 --- /dev/null +++ b/docs/source/usage_neurophotometrics.rst @@ -0,0 +1,130 @@ +Neurophotometrics recording with iblrigv8 +========================================= + +This document describes how to use the iblrigv8 software to record Photometry using Neurophotometrics FP3002 system. + +Setup +----- + +Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer. + +.. code:: yaml + + device_neurophotometrics: + BONSAI_WORKFLOW: devices/neurophotometrics/photometry_NP3002.bonsai + + + +Starting a task +--------------- + +Below shows how to start the electrophysiology for the subject 'example' with 2 probes: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_ephys_session example 2 + + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag ephys + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + + +Look at the raw data +-------------------- + +This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display. + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + viewephys + +.. image:: img/viewephys.png + :width: 800 + :alt: Alternative text + + +More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephysNeuropixel recording with iblrigv8 +================================== + +This document describes how to use the iblrigv8 software to record from the Neuropixel computer. + +Setup +----- + +Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer. + +To get access to the viewephys visualizer: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + pip install viewephys + +Starting a task +--------------- + +Below shows how to start the electrophysiology for the subject 'example' with 2 probes: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_ephys_session example 2 + + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag ephys + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + + +Look at the raw data +-------------------- + +This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display. + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + viewephys + +.. image:: img/viewephys.png + :width: 800 + :alt: Alternative text + + +More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys \ No newline at end of file diff --git a/iblrig/commands.py b/iblrig/commands.py index 18e50223c..37c2298d2 100644 --- a/iblrig/commands.py +++ b/iblrig/commands.py @@ -12,13 +12,18 @@ from iblrig.hardware import Bpod from iblrig.online_plots import OnlinePlots from iblrig.path_helper import get_local_and_remote_paths -from iblrig.transfer_experiments import BehaviorCopier, EphysCopier, SessionCopier, VideoCopier +from iblrig.transfer_experiments import BehaviorCopier, EphysCopier, NeurophotometricsCopier, SessionCopier, VideoCopier from iblutil.util import setup_logger logger = logging.getLogger(__name__) -tag2copier = {'behavior': BehaviorCopier, 'video': VideoCopier, 'ephys': EphysCopier} +tag2copier = { + 'behavior': BehaviorCopier, + 'video': VideoCopier, + 'ephys': EphysCopier, + 'neurophotometrics': NeurophotometricsCopier, +} def _transfer_parser(description: str) -> argparse.ArgumentParser: @@ -102,7 +107,7 @@ def transfer_video_data_cli(): setup_logger('iblrig', level='INFO') warnings.warn( 'transfer_video_data will be removed in the future. Use "transfer_data video" instead.', FutureWarning, stacklevel=2 - ) + ) # see transfer_data_cli above args = _transfer_parser('Copy video data to the local server.').parse_args() transfer_data(**{**vars(args), 'tag': 'video'}, interactive=True) diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index f1d4c5eea..0d8549cb9 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -163,6 +163,10 @@ class HardwareSettingsCamera(BunchModel): ) +class HardwareSettingsNeurophotometrics(BunchModel): + BONSAI_WORKFLOW: Path + + class HardwareSettingsCameraWorkflow(BunchModel): setup: ExistingFilePath | None = Field( title='Optional camera setup workflow', @@ -201,6 +205,7 @@ class HardwareSettings(BunchModel): device_scale: HardwareSettingsScale = HardwareSettingsScale() device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None device_microphone: HardwareSettingsMicrophone | None = None + device_neurophotometrics: HardwareSettingsNeurophotometrics | None = None VERSION: str diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index c4d3ef266..891bfbbed 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -580,3 +580,16 @@ def _copy_collections(self): remote_folder=self.remote_session_path.joinpath('raw_ephys_data'), overwrite=True, ) + + +class NeurophotometricsCopier(SessionCopier): + tag = 'neurophotometrics' + assert_connect_on_init = True + + def initialize_experiment(self, acquisition_description=None, **kwargs): + if not acquisition_description: + acquisition_description = dict(devices={'neurophotometrics': {'NP3002': None}}) + # TODO add the sync file with DAQami + # sync_file = Path(iblrig.__file__).parent.joinpath('device_descriptions', 'sync', 'daqami.yaml') + self._experiment_description = acquisition_description + super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) From 259e380a3717562e96bdbbb9c231ac91320fc318 Mon Sep 17 00:00:00 2001 From: owinter Date: Thu, 20 Jun 2024 14:37:51 +0100 Subject: [PATCH 18/43] WIP photometry copiers / starters --- docs/source/usage_neurophotometrics.rst | 7 ++-- iblrig/neurophotometrics.py | 52 +++++++++++++++++++++++++ iblrig/pydantic_definitions.py | 12 +++--- pyproject.toml | 1 + 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 iblrig/neurophotometrics.py diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index 0ca36e5a8..cea20a5bb 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -10,10 +10,11 @@ Just make sure iblrigv8 is installed according to the instructions and that the file is configured with the local folder and remote folder for the data transfer. .. code:: yaml - + RIG_NAME: photometry + MAIN_SYNC: False device_neurophotometrics: - BONSAI_WORKFLOW: devices/neurophotometrics/photometry_NP3002.bonsai - + BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai + VERSION: 1.0.0 Starting a task diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py new file mode 100644 index 000000000..1e5df98a0 --- /dev/null +++ b/iblrig/neurophotometrics.py @@ -0,0 +1,52 @@ +import argparse +import datetime +import logging +from pathlib import Path + +from iblutil.util import setup_logger +import iblrig +from iblrig.tools import call_bonsai +import iblrig.path_helper + +from iblrig.pydantic_definitions import HardwareSettings + +_logger = logging.getLogger(__name__) + + +def start_workflow(debug: bool = False): + # TODO docstring + # format the current date and time as a standard string + datestr = datetime.datetime.now().strftime('%Y-%m-%d') + timestr = datetime.datetime.now().strftime('T%H%M%S') + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) + _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') + bonsai_params = { + 'FilenamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), + 'FilenameDO0': str(folder_neurophotometrics.joinpath('bonsai_DO0.csv')), + 'FilenameDO1': str(folder_neurophotometrics.joinpath('bonsai_DO1.csv')), + 'FilenameDI0': str(folder_neurophotometrics.joinpath('bonsai_DI0.csv')), + } + hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai(workflow_file, debug=debug, parameters=bonsai_params) + + +def init_neurophotometrics_session(): + # TODO this needs to link the session (subject/date/number) to a photometry recording + # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) + # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) + pass + + +def start_workflow_cmd(): + """ + Command line interface for preparing a neurophotometrics session on the photometry computer + :return: + """ + parser = argparse.ArgumentParser(prog='start_photometry_recording', + description='Prepare photometry computer PC for recording session.') + parser.add_argument('--debug', action='store_true', help='enable debugging mode') + args = parser.parse_args() + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') + start_workflow(debug=args.debug) diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index 0d8549cb9..c950f0092 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -196,12 +196,12 @@ class HardwareSettings(BunchModel): model_config = ConfigDict(title='hardware_settings.yaml') RIG_NAME: str MAIN_SYNC: bool - device_bpod: HardwareSettingsBpod - device_frame2ttl: HardwareSettingsFrame2TTL - device_rotary_encoder: HardwareSettingsRotaryEncoder - device_screen: HardwareSettingsScreen - device_sound: HardwareSettingsSound - device_valve: HardwareSettingsValve + device_bpod: HardwareSettingsBpod | None = None + device_frame2ttl: HardwareSettingsFrame2TTL | None = None + device_rotary_encoder: HardwareSettingsRotaryEncoder | None = None + device_screen: HardwareSettingsScreen | None = None + device_sound: HardwareSettingsSound | None = None + device_valve: HardwareSettingsValve | None = None device_scale: HardwareSettingsScale = HardwareSettingsScale() device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None device_microphone: HardwareSettingsMicrophone | None = None diff --git a/pyproject.toml b/pyproject.toml index bfbff02cb..5efd740fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ install_spinnaker = "iblrig.video:install_spinnaker" install_pyspin = "iblrig.video:install_pyspin" start_video_session = "iblrig.video:prepare_video_session_cmd" start_ephys_session = "iblrig.ephys:prepare_ephys_session_cmd" +start_neurophotometrics = 'iblrig.neurophotometrics:start_workflow_cmd' convert_uis = "iblrig.gui.tools:convert_uis" validate_iblrig = "iblrig.hardware_validation:run_all_validators_cli" validate_video = "iblrig.video:validate_video_cmd" From ac18ce8ff99598d1f07b58f2ba0559759d223689 Mon Sep 17 00:00:00 2001 From: owinter Date: Mon, 24 Jun 2024 12:32:50 +0100 Subject: [PATCH 19/43] Start photometry workflow --- iblrig/neurophotometrics.py | 13 +++++++------ iblrig/tools.py | 12 ++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 1e5df98a0..a1705b7e6 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -22,14 +22,15 @@ def start_workflow(debug: bool = False): folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') bonsai_params = { - 'FilenamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), - 'FilenameDO0': str(folder_neurophotometrics.joinpath('bonsai_DO0.csv')), - 'FilenameDO1': str(folder_neurophotometrics.joinpath('bonsai_DO1.csv')), - 'FilenameDI0': str(folder_neurophotometrics.joinpath('bonsai_DI0.csv')), + 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), } hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) - call_bonsai(workflow_file, debug=debug, parameters=bonsai_params) + # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai( + workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002.bonsai'), + parameters=bonsai_params, + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), + ) def init_neurophotometrics_session(): diff --git a/iblrig/tools.py b/iblrig/tools.py index 99ab066f4..429dbb6bd 100644 --- a/iblrig/tools.py +++ b/iblrig/tools.py @@ -201,7 +201,10 @@ def _build_bonsai_cmd( debug: bool = False, bootstrap: bool = True, editor: bool = True, -) -> list[str]: + wait: bool = True, + check: bool = False, + bonsai_executable: str | Path = None, +) -> subprocess.Popen[bytes] | subprocess.Popen[str | bytes | Any] | subprocess.CompletedProcess: """ Execute a Bonsai workflow within a subprocess call. @@ -232,14 +235,15 @@ def _build_bonsai_cmd( If the Bonsai executable does not exist. If the specified workflow file does not exist. """ - if not BONSAI_EXE.exists(): - raise FileNotFoundError(BONSAI_EXE) + bonsai_executable = BONSAI_EXE if bonsai_executable is None else bonsai_executable + if not bonsai_executable.exists(): + raise FileNotFoundError(bonsai_executable) workflow_file = Path(workflow_file) if not workflow_file.exists(): raise FileNotFoundError(workflow_file) create_bonsai_layout_from_template(workflow_file) - cmd = [str(BONSAI_EXE), str(workflow_file)] + cmd = [str(bonsai_executable), str(workflow_file)] if start: cmd.append('--start' if debug else '--start-no-debug') if not editor: From 6ca90f2f914a35b4ee622d83a1211ef674efe022 Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 28 Jun 2024 13:06:20 +0100 Subject: [PATCH 20/43] photometry: start bonsai workflow script --- .../FP3002_digital_inputs.bonsai | 102 ++++++++++++++ .../FP3002_digital_inputs.bonsai.layout | 101 ++++++++++++++ iblrig/neurophotometrics.py | 127 ++++++++++-------- 3 files changed, 277 insertions(+), 53 deletions(-) create mode 100644 devices/neurophotometrics/FP3002_digital_inputs.bonsai create mode 100644 devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai b/devices/neurophotometrics/FP3002_digital_inputs.bonsai new file mode 100644 index 000000000..39d58619c --- /dev/null +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai @@ -0,0 +1,102 @@ + + + + + + + + + + StartPhotometry + COM3 + + + 0 + Green + + + 928 + 224 + + + 194 + 194 + + 928 + 224 + 194 + 194 + + G0 + + + 1 + Green + + + 900 + 417 + + + 194 + 188 + + 900 + 417 + 194 + 188 + + G1 + + + + + + + + + + + + + false + false + false + D:\iblrigv8_data\neurophotometrics\2024-06-25\T115602\raw_photometry.csv + None + + + + + true + true + false + false + + + + + + + D:\iblrigv8_data\neurophotometrics\2024-06-25\T114558\digitial_input_1.csv + false + false + None + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout b/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout new file mode 100644 index 000000000..2e84050a0 --- /dev/null +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai.layout @@ -0,0 +1,101 @@ + + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + + false + + 0 + 0 + + + 0 + 0 + + Normal + + \ No newline at end of file diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index a1705b7e6..876230aca 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -1,53 +1,74 @@ -import argparse -import datetime -import logging -from pathlib import Path - -from iblutil.util import setup_logger -import iblrig -from iblrig.tools import call_bonsai -import iblrig.path_helper - -from iblrig.pydantic_definitions import HardwareSettings - -_logger = logging.getLogger(__name__) - - -def start_workflow(debug: bool = False): - # TODO docstring - # format the current date and time as a standard string - datestr = datetime.datetime.now().strftime('%Y-%m-%d') - timestr = datetime.datetime.now().strftime('T%H%M%S') - dict_paths = iblrig.path_helper.get_local_and_remote_paths() - folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) - _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') - bonsai_params = { - 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), - } - hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) - call_bonsai( - workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002.bonsai'), - parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), - ) - - -def init_neurophotometrics_session(): - # TODO this needs to link the session (subject/date/number) to a photometry recording - # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) - # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) - pass - - -def start_workflow_cmd(): - """ - Command line interface for preparing a neurophotometrics session on the photometry computer - :return: - """ - parser = argparse.ArgumentParser(prog='start_photometry_recording', - description='Prepare photometry computer PC for recording session.') - parser.add_argument('--debug', action='store_true', help='enable debugging mode') - args = parser.parse_args() - setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(debug=args.debug) +import argparse +import datetime +import logging +from pathlib import Path + +from iblutil.util import setup_logger, rrmdir +import iblrig +from iblrig.tools import call_bonsai +import iblrig.path_helper + +from iblrig.pydantic_definitions import HardwareSettings + +_logger = logging.getLogger(__name__) + + +def start_workflow(debug: bool = False): + # TODO docstring + # format the current date and time as a standard string + datestr = datetime.datetime.now().strftime('%Y-%m-%d') + timestr = datetime.datetime.now().strftime('T%H%M%S') + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + folder_neurophotometrics = dict_paths['local_data_folder'].joinpath('neurophotometrics', datestr, timestr) + bonsai_params = { + 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), + 'FileNameDigitalInput': str(folder_neurophotometrics.joinpath('digital_inputs.csv')), + 'PortName': 'COM3' # TODO: hardware settings + } + _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') + rrmdir(folder_neurophotometrics) + folder_neurophotometrics.mkdir(parents=True, exist_ok=True) + hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + call_bonsai( + workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002_digital_inputs.bonsai'), + parameters=bonsai_params, + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + start=False, + ) + rrmdir(folder_neurophotometrics) + # TODO we call the init sessions here + +def init_neurophotometrics_session(): + # TODO this needs to link the session (subject/date/number) to a photometry recording + # this means + # 1) link from one session to possibly several regions (ie. columns of the datafile) + # 2) link one session to a digital input number + # we use a single entry point for both modes of acquisition (ie. with or without a daq) + + # first read in the columns name from the photometry file + # then locate the sessions acquired from the same day on the local server + # for the case without a DAQ + # at last the digital input is hardcoded from input1 input0 + # for the case with a DAQ + # we need a hardware setting linking the rig name to a daq channel + # we get the rig name from the stub file on the server / UDP or ask for it in the GUI + + # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) + # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) + + + pass + + +def start_workflow_cmd(): + """ + Command line interface for preparing a neurophotometrics session on the photometry computer + :return: + """ + parser = argparse.ArgumentParser(prog='start_photometry_recording', + description='Prepare photometry computer PC for recording session.') + parser.add_argument('--debug', action='store_true', help='enable debugging mode') + args = parser.parse_args() + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') + start_workflow(debug=args.debug) From abd161bf1fcf84522260b73f8ea0dfe4d54140df Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:04:03 +0100 Subject: [PATCH 21/43] minimal set of parameters to start a photometry session --- docs/source/usage_neurophotometrics.rst | 94 ++----------------------- iblrig/neurophotometrics.py | 17 ++--- iblrig/pydantic_definitions.py | 1 + 3 files changed, 16 insertions(+), 96 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index cea20a5bb..27761dc7d 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -6,14 +6,16 @@ This document describes how to use the iblrigv8 software to record Photometry us Setup ----- -Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py -file is configured with the local folder and remote folder for the data transfer. +- iblrigv8 is installed according to the instructions +- `settings/iblrig_settings.yaml` file is configured with the local folder and remote folder for the data transfer. +- `settings/hardware_settings.yaml` file is configured with the neurophotometrics device .. code:: yaml RIG_NAME: photometry MAIN_SYNC: False device_neurophotometrics: BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai + COM_NEUROPHOTOMETRY: 'COM3' VERSION: 1.0.0 @@ -26,7 +28,7 @@ Below shows how to start the electrophysiology for the subject 'example' with 2 cd C:\iblrigv8\ venv\scripts\Activate.ps1 - start_ephys_session example 2 + start_neurophotometrics Copy command @@ -40,92 +42,8 @@ To initiate the data transfer from the local server to the remote server, open a .. code:: powershell C:\iblrigv8\venv\scripts\Activate.ps1 - transfer_data --tag ephys + transfer_data --tag photometry The transfer local and remote directories are set in the ``iblrig/settings/iblrig_settings.py`` file. - -Look at the raw data --------------------- - -This will launch the viewephys GUI, you can then use file -> open and navigate -to open the raw data file you wish to display. - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - viewephys - -.. image:: img/viewephys.png - :width: 800 - :alt: Alternative text - - -More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephysNeuropixel recording with iblrigv8 -================================== - -This document describes how to use the iblrigv8 software to record from the Neuropixel computer. - -Setup ------ - -Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py -file is configured with the local folder and remote folder for the data transfer. - -To get access to the viewephys visualizer: - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - pip install viewephys - -Starting a task ---------------- - -Below shows how to start the electrophysiology for the subject 'example' with 2 probes: - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - start_ephys_session example 2 - - -Copy command ------------- - -Usage -~~~~~ - -To initiate the data transfer from the local server to the remote server, open a terminal and type. - -.. code:: powershell - - C:\iblrigv8\venv\scripts\Activate.ps1 - transfer_data --tag ephys - -The transfer local and remote directories are set in the -``iblrig/settings/iblrig_settings.py`` file. - - -Look at the raw data --------------------- - -This will launch the viewephys GUI, you can then use file -> open and navigate -to open the raw data file you wish to display. - -.. code:: powershell - - cd C:\iblrigv8\ - venv\scripts\Activate.ps1 - viewephys - -.. image:: img/viewephys.png - :width: 800 - :alt: Alternative text - - -More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys \ No newline at end of file diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 876230aca..512f8a456 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,9 +13,11 @@ _logger = logging.getLogger(__name__) -def start_workflow(debug: bool = False): +def start_workflow(): # TODO docstring # format the current date and time as a standard string + hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) + settings = hardware_settings['device_neurophotometrics'] datestr = datetime.datetime.now().strftime('%Y-%m-%d') timestr = datetime.datetime.now().strftime('T%H%M%S') dict_paths = iblrig.path_helper.get_local_and_remote_paths() @@ -23,20 +25,19 @@ def start_workflow(debug: bool = False): bonsai_params = { 'FileNamePhotometry': str(folder_neurophotometrics.joinpath('raw_photometry.csv')), 'FileNameDigitalInput': str(folder_neurophotometrics.joinpath('digital_inputs.csv')), - 'PortName': 'COM3' # TODO: hardware settings + 'PortName': settings.COM_NEUROPHOTOMETRY, } _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') - rrmdir(folder_neurophotometrics) folder_neurophotometrics.mkdir(parents=True, exist_ok=True) - hardware_settings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - # workflow_file = Path(iblrig.__file__).parents[1].joinpath(hardware_settings['device_neurophotometrics']['BONSAI_WORKFLOW']) + + workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) call_bonsai( - workflow_file=Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', 'FP3002_digital_inputs.bonsai'), + workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings start=False, ) - rrmdir(folder_neurophotometrics) + # TODO we call the init sessions here def init_neurophotometrics_session(): diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index c950f0092..9fa20fbff 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -165,6 +165,7 @@ class HardwareSettingsCamera(BunchModel): class HardwareSettingsNeurophotometrics(BunchModel): BONSAI_WORKFLOW: Path + COM_NEUROPHOTOMETRY: str | None = None class HardwareSettingsCameraWorkflow(BunchModel): From 0e9120fcf45f4101884bc6ef0e076a15cc84529d Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:25:26 +0100 Subject: [PATCH 22/43] add the default bonsai path relative to home --- iblrig/neurophotometrics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 512f8a456..5d072a83d 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -31,10 +31,11 @@ def start_workflow(): folder_neurophotometrics.mkdir(parents=True, exist_ok=True) workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) + call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(r"C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe"), # TODO: hardware settings + bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), # TODO: hardware settings start=False, ) From e3d02b8886e746e4b2c366c09ea8f1711c227e88 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:33:15 +0100 Subject: [PATCH 23/43] debug arguement --- iblrig/neurophotometrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 5d072a83d..d7a10392c 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,7 +13,7 @@ _logger = logging.getLogger(__name__) -def start_workflow(): +def start_workflow(debug=False): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) From 649a1928f3b7bdb420c7430d2b6dbe66db4743a5 Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 10:36:55 +0100 Subject: [PATCH 24/43] bonsai executable --- iblrig/neurophotometrics.py | 2 +- iblrig/tools.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index d7a10392c..3e6e48f10 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -13,7 +13,7 @@ _logger = logging.getLogger(__name__) -def start_workflow(debug=False): +def start_workflow(debug=False, ): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) diff --git a/iblrig/tools.py b/iblrig/tools.py index 429dbb6bd..701f33d3c 100644 --- a/iblrig/tools.py +++ b/iblrig/tools.py @@ -265,6 +265,7 @@ def call_bonsai( editor: bool = True, wait: bool = True, check: bool = False, + bonsai_executable: str | Path = None, ) -> subprocess.Popen[bytes] | subprocess.Popen[str | bytes | Any] | subprocess.CompletedProcess: """ Execute a Bonsai workflow within a subprocess call. @@ -302,7 +303,7 @@ def call_bonsai( If the specified workflow file does not exist. """ - cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor) + cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor, bonsai_executable=bonsai_executable) cwd = Path(workflow_file).parent log.info(f'Starting Bonsai workflow `{workflow_file.name}`') log.debug(' '.join(map(str, cmd))) From 545152ef3edbcb3fd08b37748e967b27da7e95bf Mon Sep 17 00:00:00 2001 From: owinter Date: Tue, 17 Sep 2024 11:36:21 +0100 Subject: [PATCH 25/43] add documentation --- docs/source/usage_neurophotometrics.rst | 10 +++++++--- iblrig/neurophotometrics.py | 5 +---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index 27761dc7d..b98bb086a 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -16,19 +16,23 @@ Setup device_neurophotometrics: BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai COM_NEUROPHOTOMETRY: 'COM3' - VERSION: 1.0.0 Starting a task --------------- -Below shows how to start the electrophysiology for the subject 'example' with 2 probes: - +- Start the Bonsai workflow by running the following command in powershell: .. code:: powershell cd C:\iblrigv8\ venv\scripts\Activate.ps1 start_neurophotometrics +- in Bonsai click on the FP3002 node and load the desired photometry settings file +- start the task + +The task will start and the photometry data will be saved in the data local folder with the following stucture: +- {local_data_folder}\neurophotometrics\yyyy-mm-dd\THHMMSS +Where yyyy-mm-dd is the date of the recording and HHMMSS is the time of the recording. Copy command diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 3e6e48f10..0f49e5e07 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -35,10 +35,9 @@ def start_workflow(debug=False, ): call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), # TODO: hardware settings + bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), start=False, ) - # TODO we call the init sessions here def init_neurophotometrics_session(): @@ -58,8 +57,6 @@ def init_neurophotometrics_session(): # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) - - pass From 14a220573b1232790a3e9f8d897d69ad12a7c9a3 Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 11 Oct 2024 16:37:52 +0100 Subject: [PATCH 26/43] WIP copier photometry --- docs/source/usage_neurophotometrics.rst | 33 ++++++++++++++++++------- iblrig/graphic.py | 7 ++---- iblrig/neurophotometrics.py | 3 ++- iblrig/pydantic_definitions.py | 4 ++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/docs/source/usage_neurophotometrics.rst b/docs/source/usage_neurophotometrics.rst index b98bb086a..4c7a1e23d 100644 --- a/docs/source/usage_neurophotometrics.rst +++ b/docs/source/usage_neurophotometrics.rst @@ -10,16 +10,18 @@ Setup - `settings/iblrig_settings.yaml` file is configured with the local folder and remote folder for the data transfer. - `settings/hardware_settings.yaml` file is configured with the neurophotometrics device -.. code:: yaml - RIG_NAME: photometry - MAIN_SYNC: False - device_neurophotometrics: - BONSAI_WORKFLOW: devices/neurophotometrics/FP3002.bonsai - COM_NEUROPHOTOMETRY: 'COM3' + .. code:: yaml + RIG_NAME: photometry + MAIN_SYNC: False + device_neurophotometrics: + DEVICE_MODEL: NP3002 + BONSAI_EXECUTABLE: C:\Users\IBLuser\AppData\Local\Bonsai\Bonsai.exe + BONSAI_WORKFLOW: devices\neurophotometrics\FP3002.bonsai + COM_NEUROPHOTOMETRY: COM3 -Starting a task ---------------- +Starting a photometry recording +-------------------------------- - Start the Bonsai workflow by running the following command in powershell: .. code:: powershell @@ -30,11 +32,24 @@ Starting a task - in Bonsai click on the FP3002 node and load the desired photometry settings file - start the task -The task will start and the photometry data will be saved in the data local folder with the following stucture: +The photometry recording will start and the photometry data will be saved in the data local folder with the following stucture: - {local_data_folder}\neurophotometrics\yyyy-mm-dd\THHMMSS Where yyyy-mm-dd is the date of the recording and HHMMSS is the time of the recording. + +Starting a photometry session +-------------------------------- + +- Start the Bonsai workflow by running the following command in powershell: +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_photometry_session --subject=Mickey --roi G0 G1 --location NBM SI + + + Copy command ------------ diff --git a/iblrig/graphic.py b/iblrig/graphic.py index 9301bbeb2..16e19bc12 100644 --- a/iblrig/graphic.py +++ b/iblrig/graphic.py @@ -1,10 +1,7 @@ """Popup and string input prompts""" - -import tkinter as tk -from tkinter import simpledialog - - def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): + import tkinter as tk + from tkinter import simpledialog root = tk.Tk() root.withdraw() ask = simpledialog.askinteger if askint else simpledialog.askfloat diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 0f49e5e07..88aa6eb57 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -17,7 +17,7 @@ def start_workflow(debug=False, ): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) - settings = hardware_settings['device_neurophotometrics'] + settings = hardware_settings.device_neurophotometrics datestr = datetime.datetime.now().strftime('%Y-%m-%d') timestr = datetime.datetime.now().strftime('T%H%M%S') dict_paths = iblrig.path_helper.get_local_and_remote_paths() @@ -40,6 +40,7 @@ def start_workflow(debug=False, ): ) # TODO we call the init sessions here + def init_neurophotometrics_session(): # TODO this needs to link the session (subject/date/number) to a photometry recording # this means diff --git a/iblrig/pydantic_definitions.py b/iblrig/pydantic_definitions.py index 9fa20fbff..c0009efa3 100644 --- a/iblrig/pydantic_definitions.py +++ b/iblrig/pydantic_definitions.py @@ -164,7 +164,9 @@ class HardwareSettingsCamera(BunchModel): class HardwareSettingsNeurophotometrics(BunchModel): - BONSAI_WORKFLOW: Path + DEVICE_MODEL: Literal['NP3002'] = 'NP3002' + BONSAI_EXECUTABLE: ExistingFilePath = Path(Path.home().joinpath('AppData', 'Local', 'Bonsai', 'Bonsai.exe')) + BONSAI_WORKFLOW: Path = Path('devices', 'neurophotometrics', 'FP3002.bonsai') COM_NEUROPHOTOMETRY: str | None = None From 3c2b4f5e96d9393e183a3b09f2d084c748ae75ac Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 11 Oct 2024 17:04:58 +0100 Subject: [PATCH 27/43] add argument parser --- iblrig/graphic.py | 3 +++ iblrig/neurophotometrics.py | 36 ++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/iblrig/graphic.py b/iblrig/graphic.py index 16e19bc12..afc0cfcfa 100644 --- a/iblrig/graphic.py +++ b/iblrig/graphic.py @@ -1,7 +1,10 @@ """Popup and string input prompts""" + + def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): import tkinter as tk from tkinter import simpledialog + root = tk.Tk() root.withdraw() ask = simpledialog.askinteger if askint else simpledialog.askfloat diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 88aa6eb57..cce46e46c 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -1,19 +1,19 @@ import argparse import datetime import logging +from collections.abc import Iterable from pathlib import Path -from iblutil.util import setup_logger, rrmdir import iblrig -from iblrig.tools import call_bonsai import iblrig.path_helper - from iblrig.pydantic_definitions import HardwareSettings +from iblrig.tools import call_bonsai +from iblutil.util import setup_logger _logger = logging.getLogger(__name__) -def start_workflow(debug=False, ): +def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], debug: bool = False): # TODO docstring # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) @@ -35,7 +35,7 @@ def start_workflow(debug=False, ): call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r"AppData\Local\Bonsai\Bonsai.exe")), + bonsai_executable=Path(Path.home().joinpath(r'AppData\Local\Bonsai\Bonsai.exe')), start=False, ) # TODO we call the init sessions here @@ -43,7 +43,7 @@ def start_workflow(debug=False, ): def init_neurophotometrics_session(): # TODO this needs to link the session (subject/date/number) to a photometry recording - # this means + # this means # 1) link from one session to possibly several regions (ie. columns of the datafile) # 2) link one session to a digital input number # we use a single entry point for both modes of acquisition (ie. with or without a daq) @@ -66,9 +66,25 @@ def start_workflow_cmd(): Command line interface for preparing a neurophotometrics session on the photometry computer :return: """ - parser = argparse.ArgumentParser(prog='start_photometry_recording', - description='Prepare photometry computer PC for recording session.') - parser.add_argument('--debug', action='store_true', help='enable debugging mode') + parser = argparse.ArgumentParser( + prog='start_photometry_recording', description='Prepare photometry computer PC for recording session.' + ) + parser.add_argument('-s', '--subject', type=str, required=True, help='Subject name') + parser.add_argument( + '-r', '--rois', nargs='+', type=str, required=True, help='Define ROI(s). Separate multiple values by spaces.' + ) + parser.add_argument( + '-l', + '--locations', + nargs='+', + type=str, + required=True, + help='Location of Fiber(s). Separate multiple values by spaces.', + ) + parser.add_argument('-d', '--debug', action='store_true', help='Enable debugging mode') args = parser.parse_args() + + assert len(args.roi) == len(args.location), 'The number of ROIs and locations must be the same.' + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(debug=args.debug) + start_workflow(subject=args.subject, rois=args.roi, locations=args.location, debug=args.debug) From 5a5d93911262948631bdfd7e68d846d291a30c68 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 16:54:02 +0100 Subject: [PATCH 28/43] save changes to the bonsai workflow --- .../FP3002_digital_inputs.bonsai | 76 ++++++++++++++----- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/devices/neurophotometrics/FP3002_digital_inputs.bonsai b/devices/neurophotometrics/FP3002_digital_inputs.bonsai index 39d58619c..0f6ba23bc 100644 --- a/devices/neurophotometrics/FP3002_digital_inputs.bonsai +++ b/devices/neurophotometrics/FP3002_digital_inputs.bonsai @@ -12,24 +12,24 @@ StartPhotometry - COM3 + COM4 0 Green - 928 - 224 + 824 + 492 - 194 - 194 + 166 + 180 - 928 - 224 - 194 - 194 + 824 + 492 + 166 + 180 G0 @@ -38,20 +38,58 @@ Green - 900 - 417 + 703 + 353 - 194 - 188 + 154 + 180 - 900 - 417 - 194 - 188 + 703 + 353 + 154 + 180 G1 + + 2 + Green + + + 943 + 134 + + + 180 + 176 + + 943 + 134 + 180 + 176 + + G2 + + + 3 + Green + + + 767 + 180 + + + 176 + 182 + + 767 + 180 + 176 + 182 + + G3 + @@ -66,7 +104,7 @@ false false false - D:\iblrigv8_data\neurophotometrics\2024-06-25\T115602\raw_photometry.csv + D:\iblrigv8_data\neurophotometrics\2024-10-10\T142948\raw_photometry.csv None @@ -82,7 +120,7 @@ - D:\iblrigv8_data\neurophotometrics\2024-06-25\T114558\digitial_input_1.csv + D:\iblrigv8_data\neurophotometrics\2024-10-10\T142948\digital_inputs.csv false false None From fdcf2f6f11abeae9f92c527684c9bb252fd90657 Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 11 Oct 2024 17:26:42 +0100 Subject: [PATCH 29/43] start_photometry_task_cmd --- iblrig/neurophotometrics.py | 28 ++++++++++++++-------------- pyproject.toml | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index cce46e46c..ac24ba66d 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -2,10 +2,9 @@ import datetime import logging from collections.abc import Iterable -from pathlib import Path -import iblrig import iblrig.path_helper +from iblrig.constants import BASE_PATH from iblrig.pydantic_definitions import HardwareSettings from iblrig.tools import call_bonsai from iblutil.util import setup_logger @@ -13,8 +12,10 @@ _logger = logging.getLogger(__name__) -def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], debug: bool = False): - # TODO docstring +def start_workflow_cmd(debug: bool = False): + """ + Start a photometry recording regardless of behaviour. + """ # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) settings = hardware_settings.device_neurophotometrics @@ -29,19 +30,16 @@ def start_workflow(subject: str, rois: Iterable[str], locations: Iterable[str], } _logger.info(f'Creating folder for neurophotometrics data: {folder_neurophotometrics}') folder_neurophotometrics.mkdir(parents=True, exist_ok=True) - - workflow_file = Path(iblrig.__file__).parents[1].joinpath(settings.BONSAI_WORKFLOW) - + workflow_file = BASE_PATH.joinpath(settings.BONSAI_WORKFLOW) call_bonsai( workflow_file=workflow_file, parameters=bonsai_params, - bonsai_executable=Path(Path.home().joinpath(r'AppData\Local\Bonsai\Bonsai.exe')), + bonsai_executable=settings.BONSAI_EXECUTABLE, start=False, ) - # TODO we call the init sessions here -def init_neurophotometrics_session(): +def init_neurophotometrics_session(subject: str, rois: Iterable[str], locations: Iterable[str], sync_channel: int = 1): # TODO this needs to link the session (subject/date/number) to a photometry recording # this means # 1) link from one session to possibly several regions (ie. columns of the datafile) @@ -61,9 +59,10 @@ def init_neurophotometrics_session(): pass -def start_workflow_cmd(): +def start_photometry_task_cmd(): """ - Command line interface for preparing a neurophotometrics session on the photometry computer + Command line interface for preparing a neurophotometrics session on the photometry computer. + start_photometry_recording -s Algernon --rois G0 G1 --locations :return: """ parser = argparse.ArgumentParser( @@ -79,12 +78,13 @@ def start_workflow_cmd(): nargs='+', type=str, required=True, - help='Location of Fiber(s). Separate multiple values by spaces.', + help='Location of Fiber(s). Separate multiple values by spaces. Usually Allen brain acronyms.', ) parser.add_argument('-d', '--debug', action='store_true', help='Enable debugging mode') + parser.add_argument('-c', '--sync-channel', type=int, default=1, help='Sync channel') args = parser.parse_args() assert len(args.roi) == len(args.location), 'The number of ROIs and locations must be the same.' setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - start_workflow(subject=args.subject, rois=args.roi, locations=args.location, debug=args.debug) + init_neurophotometrics_session(subject=args.subject, rois=args.roi, locations=args.location, sync_channel=args.sync_channel) diff --git a/pyproject.toml b/pyproject.toml index 5efd740fe..5380c5149 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ install_pyspin = "iblrig.video:install_pyspin" start_video_session = "iblrig.video:prepare_video_session_cmd" start_ephys_session = "iblrig.ephys:prepare_ephys_session_cmd" start_neurophotometrics = 'iblrig.neurophotometrics:start_workflow_cmd' +start_photometry_task = 'iblrig.neurophotometrics:start_photometry_task_cmd' convert_uis = "iblrig.gui.tools:convert_uis" validate_iblrig = "iblrig.hardware_validation:run_all_validators_cli" validate_video = "iblrig.video:validate_video_cmd" From 9fc2755f83d9a16d4ed12a085fc1b6ea61e9e9fc Mon Sep 17 00:00:00 2001 From: owinter Date: Fri, 8 Nov 2024 19:23:52 +0000 Subject: [PATCH 30/43] wip photometry UCL extraction --- iblrig/neurophotometrics.py | 58 ++++++++++++----- iblrig/test/test_neurophotometrics.py | 23 +++++++ iblrig/transfer_experiments.py | 90 ++++++++++++++++++++++++--- pyproject.toml | 1 + 4 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 iblrig/test/test_neurophotometrics.py diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index ac24ba66d..2528883e7 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -2,11 +2,16 @@ import datetime import logging from collections.abc import Iterable +from typing import Union +from pathlib import Path + +from iblatlas.atlas import BrainRegions import iblrig.path_helper from iblrig.constants import BASE_PATH from iblrig.pydantic_definitions import HardwareSettings from iblrig.tools import call_bonsai +from iblrig.transfer_experiments import NeurophotometricsCopier from iblutil.util import setup_logger _logger = logging.getLogger(__name__) @@ -16,9 +21,9 @@ def start_workflow_cmd(debug: bool = False): """ Start a photometry recording regardless of behaviour. """ - # format the current date and time as a standard string hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) settings = hardware_settings.device_neurophotometrics + # format the current date and time as a standard string datestr = datetime.datetime.now().strftime('%Y-%m-%d') timestr = datetime.datetime.now().strftime('T%H%M%S') dict_paths = iblrig.path_helper.get_local_and_remote_paths() @@ -39,24 +44,43 @@ def start_workflow_cmd(debug: bool = False): ) -def init_neurophotometrics_session(subject: str, rois: Iterable[str], locations: Iterable[str], sync_channel: int = 1): - # TODO this needs to link the session (subject/date/number) to a photometry recording - # this means - # 1) link from one session to possibly several regions (ie. columns of the datafile) - # 2) link one session to a digital input number - # we use a single entry point for both modes of acquisition (ie. with or without a daq) +def init_neurophotometrics_session( + session_stub: str, rois: Iterable[str], locations: Iterable[str], sync_channel: int = 1, **kwargs +) -> NeurophotometricsCopier: + """ + Initialize a neurophotometrics session: + - Creates a new folder for the session on the photometry computer. + - Creates a new experiment description file in the session folder. + - Copies the experiment description stub to the server - # first read in the columns name from the photometry file - # then locate the sessions acquired from the same day on the local server - # for the case without a DAQ - # at last the digital input is hardcoded from input1 input0 - # for the case with a DAQ - # we need a hardware setting linking the rig name to a daq channel - # we get the rig name from the stub file on the server / UDP or ask for it in the GUI + Parameters + ---------- + session_stub : str + The name of the subject for this session. + rois : Iterable[str] + List of ROIs to be recorded. + locations : Iterable[str] + List of brain locations to be recorded. + sync_channel : int, optional + Channel to use for syncing photometry and digital inputs, by default 1 + kwargs : dict, optional + Additional keyword arguments to be passed to the NeurophotometricsCopier.neurophotometrics_description method. - # copier = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) - # copier.initialize_experiment(acquisition_description=copier.config2stub(config, raw_data_folder.name)) - pass + Returns + ------- + NeurophotometricsCopier + An instance of the NeurophotometricsCopier class initialized with the provided session details. + """ + # I put the import here as it may slow down + regions = BrainRegions() + if not all(map(lambda x: x in regions.acronym, locations)): + _logger.warning(f'Brain regions {locations} not found in BrainRegions acronyms') + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + session_path = dict_paths['local_subjects_folder'].joinpath(session_stub) + description = NeurophotometricsCopier.neurophotometrics_description(rois, locations, sync_channel, **kwargs) + npc = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=dict_paths['remote_subjects_folder']) + npc.initialize_experiment(acquisition_description=description) + return npc def start_photometry_task_cmd(): diff --git a/iblrig/test/test_neurophotometrics.py b/iblrig/test/test_neurophotometrics.py new file mode 100644 index 000000000..3123c971a --- /dev/null +++ b/iblrig/test/test_neurophotometrics.py @@ -0,0 +1,23 @@ +import datetime +import unittest + + +from iblrig.transfer_experiments import NeurophotometricsCopier + + +class TestExperimentDescription(unittest.TestCase): + def test_neurophotometrics_description(self): + dt = datetime.datetime.fromisoformat('2024-10-11T11:11:00') + d = NeurophotometricsCopier.neurophotometrics_description( + rois=['G0', 'G1'], + locations=['SI', 'VTA'], + sync_channel=3, + start_time=dt, + ) + dexpected = { + 'sync_channel': 3, + 'datetime': '2024-10-11T11:11:00', + 'G0': {'collection': 'raw_photometry_data', 'location': 'SI'}, + 'G1': {'collection': 'raw_photometry_data', 'location': 'VTA'}, + } + self.assertEqual(dexpected, d) diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index 891bfbbed..c426600ec 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -7,17 +7,18 @@ import traceback import uuid from enum import IntEnum +from typing import Iterable from os.path import samestat from pathlib import Path import ibllib.pipes.misc import iblrig -import one.alf.files as alfiles +import one.alf.path as alfiles from ibllib.io import raw_data_loaders, session_params from ibllib.pipes.misc import sleepless from iblrig.raw_data_loaders import load_task_jsonable from iblutil.io import hashfile -from one.util import ensure_list +from iblutil.util import ensure_list log = logging.getLogger(__name__) @@ -587,9 +588,82 @@ class NeurophotometricsCopier(SessionCopier): assert_connect_on_init = True def initialize_experiment(self, acquisition_description=None, **kwargs): - if not acquisition_description: - acquisition_description = dict(devices={'neurophotometrics': {'NP3002': None}}) - # TODO add the sync file with DAQami - # sync_file = Path(iblrig.__file__).parent.joinpath('device_descriptions', 'sync', 'daqami.yaml') - self._experiment_description = acquisition_description - super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) + assert acquisition_description is not None, 'No acquisition description provided' + self._experiment_description = acquisition_description + super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) + + @staticmethod + def neurophotometrics_description( + rois: Iterable[str], + locations: Iterable[str], + sync_channel: int, + start_time: datetime.datetime = None, + sync_label: str = None, + collection: str = 'raw_photometry_data', + ) -> dict: + """ + This function creates the `neurophotometrics` description part for the specified parameters. + + Parameters + ---------- + rois: list of strings + List of ROIs + locations: list of strings + List of brain regions + sync_channel: int + Channel number for sync + start_time: datetime.datetime, optional + Date and time of the recording + sync_label: str, optional + Label for the sync channel + + Returns + ------- + dict + Description of the neurophotometrics data + {neurophotometrics': ...}, see below for the yaml rendition of dictionaries + + + Example where bpod sends sync to the neurophotometrics: + ------- + neurophotometrics: + G0: + collection: raw_photometry_data + location: VTA + G1: + collection: raw_photometry_data + location: DR + sync_label: bnc1out + sync_channel: 1 + datetime: 2024-09-19T14:13:18.749259 + sync: + bpod + + Here MAIN_SYNC=True on behaviour + + Example where a DAQ records frame times and sync: + ------- + neurophotometrics: + G0: + collection: raw_photometry_data + location: VTA + G1: + collection: raw_photometry_data + location: DR + sync_channel: 5 + datetime: 2024-09-19T14:13:18.749259 + sync: + daqami: + acquisition_software: daqami + collection: raw_sync_data + extension: bin + """ + date_time = datetime.datetime.now() if start_time is None else start_time + description = { + 'sync_channel': sync_channel, + 'datetime': date_time.isoformat(), + } + if sync_label is not None: + description['sync_label'] = sync_label + description.update({roi: {'collection': collection, 'location': location} for roi, location in zip(rois, locations)}) + return description diff --git a/pyproject.toml b/pyproject.toml index 5380c5149..bfb95cbfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ dependencies = [ "PyQtWebEngine-Qt5==5.15.2", # # IBL packages + "iblatlas>=0.5.4", "ibllib>=2.39.1", "iblpybpod @ git+https://github.com/int-brain-lab/iblpybpod.git@no-gui", "iblutil>=1.13.0", From cff3a9e459301d216d5c27718cbf928321d01fb9 Mon Sep 17 00:00:00 2001 From: Olivier Winter Date: Sun, 10 Nov 2024 20:45:52 +0000 Subject: [PATCH 31/43] neurophotometrics copier init/copy collections --- .../_neurophotometrics_fpData.channels.csv | 13 +++ iblrig/neurophotometrics.py | 35 ++++++-- iblrig/test/test_neurophotometrics.py | 4 +- iblrig/transfer_experiments.py | 85 ++++++++++++++++--- 4 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 devices/neurophotometrics/_neurophotometrics_fpData.channels.csv diff --git a/devices/neurophotometrics/_neurophotometrics_fpData.channels.csv b/devices/neurophotometrics/_neurophotometrics_fpData.channels.csv new file mode 100644 index 000000000..9ef2a9752 --- /dev/null +++ b/devices/neurophotometrics/_neurophotometrics_fpData.channels.csv @@ -0,0 +1,13 @@ +Condition,No LED ON,L415,L470,L560 +No additional signal,0,1,2,4 +Output 1 signal HIGH,8,9,10,12 +Output 0 signal HIGH,16,17,18,20 +Stimulation ON,32,33,34,36 +GPIO Line 2 HIGH,64,65,66,68 +GPIO Line 3 HIGH,128,129,130,132 +Input 1 HIGH,256,257,258,260 +Input 0 HIGH,512,513,514,516 +Output 0 signal HIGH + Stimulation,48,49,50,52 +Output 0 signal HIGH + Input 0 signal HIGH,528,529,530,532 +Input 0 signal HIGH + Stimulation,544,545,546,548 +Output 0 HIGH + Input 0 HIGH + Stimulation,560,561,562,564 diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index 2528883e7..a44851474 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -1,25 +1,37 @@ import argparse +from collections.abc import Iterable import datetime import logging -from collections.abc import Iterable -from typing import Union from pathlib import Path +import shutil + +import numpy as np +import pandas as pd +import pandera from iblatlas.atlas import BrainRegions +from iblutil.util import setup_logger import iblrig.path_helper from iblrig.constants import BASE_PATH from iblrig.pydantic_definitions import HardwareSettings from iblrig.tools import call_bonsai from iblrig.transfer_experiments import NeurophotometricsCopier -from iblutil.util import setup_logger _logger = logging.getLogger(__name__) +def _get_neurophotometrics_copier(session_stub: str) -> tuple[NeurophotometricsCopier, dict]: + dict_paths = iblrig.path_helper.get_local_and_remote_paths() + session_path = dict_paths['local_subjects_folder'].joinpath(session_stub) + npc = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=dict_paths['remote_subjects_folder']) + return npc, dict_paths + + def start_workflow_cmd(debug: bool = False): """ Start a photometry recording regardless of behaviour. + This should happen before the neurophotometrics recording has been started. """ hardware_settings: HardwareSettings = iblrig.path_helper.load_pydantic_yaml(HardwareSettings) settings = hardware_settings.device_neurophotometrics @@ -44,11 +56,12 @@ def start_workflow_cmd(debug: bool = False): ) -def init_neurophotometrics_session( +def init_neurophotometrics_subject( session_stub: str, rois: Iterable[str], locations: Iterable[str], sync_channel: int = 1, **kwargs ) -> NeurophotometricsCopier: """ - Initialize a neurophotometrics session: + Initialize a neurophotometrics behavior session. + This should happen after the neurophotometrics recording has been started. - Creates a new folder for the session on the photometry computer. - Creates a new experiment description file in the session folder. - Copies the experiment description stub to the server @@ -75,14 +88,18 @@ def init_neurophotometrics_session( regions = BrainRegions() if not all(map(lambda x: x in regions.acronym, locations)): _logger.warning(f'Brain regions {locations} not found in BrainRegions acronyms') - dict_paths = iblrig.path_helper.get_local_and_remote_paths() - session_path = dict_paths['local_subjects_folder'].joinpath(session_stub) + npc, dict_paths = _get_neurophotometrics_copier(session_stub) description = NeurophotometricsCopier.neurophotometrics_description(rois, locations, sync_channel, **kwargs) - npc = NeurophotometricsCopier(session_path=session_path, remote_subjects_folder=dict_paths['remote_subjects_folder']) npc.initialize_experiment(acquisition_description=description) return npc +def copy_photometry_subject(session_stub: str) -> None: + npc, dict_paths = _get_neurophotometrics_copier(session_stub) + folder_neurophotometric = dict_paths['local_data_folder'].joinpath('neurophotometrics') + status = npc.copy_collections(folder_neurophotometric=folder_neurophotometric) + + def start_photometry_task_cmd(): """ Command line interface for preparing a neurophotometrics session on the photometry computer. @@ -111,4 +128,4 @@ def start_photometry_task_cmd(): assert len(args.roi) == len(args.location), 'The number of ROIs and locations must be the same.' setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') - init_neurophotometrics_session(subject=args.subject, rois=args.roi, locations=args.location, sync_channel=args.sync_channel) + init_neurophotometrics_subject(subject=args.subject, rois=args.roi, locations=args.location, sync_channel=args.sync_channel) diff --git a/iblrig/test/test_neurophotometrics.py b/iblrig/test/test_neurophotometrics.py index 3123c971a..1c030bd51 100644 --- a/iblrig/test/test_neurophotometrics.py +++ b/iblrig/test/test_neurophotometrics.py @@ -17,7 +17,7 @@ def test_neurophotometrics_description(self): dexpected = { 'sync_channel': 3, 'datetime': '2024-10-11T11:11:00', - 'G0': {'collection': 'raw_photometry_data', 'location': 'SI'}, - 'G1': {'collection': 'raw_photometry_data', 'location': 'VTA'}, + 'collection': 'raw_photometry_data', + 'fibers': {'G0': {'location': 'SI'}, 'G1': {'location': 'VTA'}}, } self.assertEqual(dexpected, d) diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index c426600ec..fcc323f31 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -317,7 +317,7 @@ def copy_snapshots(self): # We've already checked that filenames don't conflict. return copy_folders(snapshots, remote_snapshots, overwrite=True) - def copy_collections(self): + def copy_collections(self, *args, **kwargs): """ Recursively copies the collection folders into the remote session path. @@ -329,7 +329,7 @@ def copy_collections(self): f' remove {self.glob_file_remote_copy_status("complete")} to force' ) return True - status = self._copy_collections() + status = self._copy_collections(*args, **kwargs) # post copy stuff: rename the pending flag to complete if status: pending_file = self.glob_file_remote_copy_status('pending') @@ -587,10 +587,16 @@ class NeurophotometricsCopier(SessionCopier): tag = 'neurophotometrics' assert_connect_on_init = True + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.file_experiment_description.exists() and self.experiment_description is None: + self._experiment_description = session_params.read_params(self.file_experiment_description) + def initialize_experiment(self, acquisition_description=None, **kwargs): assert acquisition_description is not None, 'No acquisition description provided' self._experiment_description = acquisition_description super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) + self.session_path.joinpath('transfer_me.flag').touch() @staticmethod def neurophotometrics_description( @@ -627,12 +633,12 @@ def neurophotometrics_description( Example where bpod sends sync to the neurophotometrics: ------- neurophotometrics: - G0: - collection: raw_photometry_data + fibers: + - roi: G0 location: VTA - G1: - collection: raw_photometry_data + - roi: G1 location: DR + collection: raw_photometry_data sync_label: bnc1out sync_channel: 1 datetime: 2024-09-19T14:13:18.749259 @@ -644,12 +650,12 @@ def neurophotometrics_description( Example where a DAQ records frame times and sync: ------- neurophotometrics: - G0: - collection: raw_photometry_data + fibers: + - roi: G0 location: VTA - G1: - collection: raw_photometry_data + - roi: G1 location: DR + collection: raw_photometry_data sync_channel: 5 datetime: 2024-09-19T14:13:18.749259 sync: @@ -662,8 +668,65 @@ def neurophotometrics_description( description = { 'sync_channel': sync_channel, 'datetime': date_time.isoformat(), + 'collection': collection, } if sync_label is not None: description['sync_label'] = sync_label - description.update({roi: {'collection': collection, 'location': location} for roi, location in zip(rois, locations)}) + description['fibers'] = {roi: {'location': location} for roi, location in zip(rois, locations)} return description + + def _copy_collections(self, folder_neurophotometric: Path) -> bool: + import pandera + import pandas as pd + import numpy as np + + ed = self.experiment_description + dt = datetime.datetime.fromisoformat(ed['datetime']) + # Here we find the first photometry folder after the start_time. In case this is failing + # we can feed a custom start_time to go to the desired folder, or just rename the folder + folder_day = next(folder_neurophotometric.glob(ed['datetime'][:10]), None) + assert folder_day.exists(), f'Neurophotometrics folder {folder_neurophotometric} not found' + folder_times = list(folder_day.glob('T*')) + assert len(folder_times) >= 1, f'No neurophotometrics acquisition files found in {folder_day}' + hhmmss = sorted([int(stem[1:]) for stem in [f.stem for f in folder_times]]) + i = np.searchsorted(hhmmss, int(dt.strftime('%H%M%S'))) - 1 + csv_raw_photometry = folder_day.joinpath(f'T{hhmmss[i]}', 'raw_photometry.csv') + csv_digital_inputs = folder_day.joinpath(f'T{hhmmss[i]}', 'digital_inputs.csv') + assert csv_raw_photometry.exists(), f'Raw photometry file {csv_raw_photometry} not found' + assert csv_digital_inputs.exists(), f'Digital inputs file {csv_digital_inputs} not found' + # Copy the raw and digital inputs files to the server + # TODO move this into a data loader ? Especially the schemas will apply to both the csv and parquet format + df_raw_photometry = pd.read_csv(csv_raw_photometry) + df_digital_inputs = pd.read_csv(csv_digital_inputs, header=None) + df_digital_inputs.columns = ['ChannelName', 'Channel', 'AlwaysTrue', 'SystemTimestamp', 'ComputerTimestamp'] + # this will ensure the columns are present, and that there was no magic new format on a new Bonsai version + schema_raw_data = pandera.DataFrameSchema( + columns=dict( + FrameCounter=pandera.Column(pandera.Int64), + SystemTimestamp=pandera.Column(pandera.Float64), + LedState=pandera.Column(pandera.Int16, coerce=True), + ComputerTimestamp=pandera.Column(pandera.Float64), + **{k: pandera.Column(pandera.Float64) for k in ed['fibers'].keys()}, + ) + ) + schema_digital_inputs = pandera.DataFrameSchema( + columns=dict( + ChannelName=pandera.Column(str, coerce=True), + Channel=pandera.Column(pandera.Int8, coerce=True), + AlwaysTrue=pandera.Column(bool, coerce=True), + SystemTimestamp=pandera.Column(pandera.Float64), + ComputerTimestamp=pandera.Column(pandera.Float64), + ) + ) + df_raw_photometry = schema_raw_data.validate(df_raw_photometry) + df_digital_inputs = schema_digital_inputs.validate(df_digital_inputs) + remote_photometry_path = self.remote_session_path.joinpath(ed['collection']) + remote_photometry_path.mkdir(parents=True, exist_ok=True) + df_raw_photometry.to_parquet(remote_photometry_path.joinpath('_neurophotometrics_fpData.raw.pqt')) + df_digital_inputs.to_parquet(remote_photometry_path.joinpath('_neurophotometrics_fpData.digitalIntputs.pqt')) + shutil.copy( + Path(iblrig.__file__).parents[1].joinpath('devices', 'neurophotometrics', '_neurophotometrics_fpData.channels.csv'), + remote_photometry_path.joinpath('_neurophotometrics_fpData.channels.csv'), + ) + + return True From 4746be573d0a7506030914fa59108f62d6e72c53 Mon Sep 17 00:00:00 2001 From: Olivier Winter Date: Mon, 11 Nov 2024 09:14:21 +0000 Subject: [PATCH 32/43] completed copy for UCL neurophotometrics --- iblrig/neurophotometrics.py | 9 ++------- iblrig/transfer_experiments.py | 12 ++++++------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/iblrig/neurophotometrics.py b/iblrig/neurophotometrics.py index a44851474..63ea0243a 100644 --- a/iblrig/neurophotometrics.py +++ b/iblrig/neurophotometrics.py @@ -2,12 +2,6 @@ from collections.abc import Iterable import datetime import logging -from pathlib import Path -import shutil - -import numpy as np -import pandas as pd -import pandera from iblatlas.atlas import BrainRegions from iblutil.util import setup_logger @@ -94,10 +88,11 @@ def init_neurophotometrics_subject( return npc -def copy_photometry_subject(session_stub: str) -> None: +def copy_photometry_subject(session_stub: str) -> bool: npc, dict_paths = _get_neurophotometrics_copier(session_stub) folder_neurophotometric = dict_paths['local_data_folder'].joinpath('neurophotometrics') status = npc.copy_collections(folder_neurophotometric=folder_neurophotometric) + return status def start_photometry_task_cmd(): diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index fcc323f31..0fe1bfb3a 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -11,6 +11,10 @@ from os.path import samestat from pathlib import Path +import pandera +import pandas as pd +import numpy as np + import ibllib.pipes.misc import iblrig import one.alf.path as alfiles @@ -676,16 +680,12 @@ def neurophotometrics_description( return description def _copy_collections(self, folder_neurophotometric: Path) -> bool: - import pandera - import pandas as pd - import numpy as np - ed = self.experiment_description dt = datetime.datetime.fromisoformat(ed['datetime']) # Here we find the first photometry folder after the start_time. In case this is failing # we can feed a custom start_time to go to the desired folder, or just rename the folder folder_day = next(folder_neurophotometric.glob(ed['datetime'][:10]), None) - assert folder_day.exists(), f'Neurophotometrics folder {folder_neurophotometric} not found' + assert folder_day is not None, f"Neurophotometrics folder {folder_neurophotometric} doesn't contain data" folder_times = list(folder_day.glob('T*')) assert len(folder_times) >= 1, f'No neurophotometrics acquisition files found in {folder_day}' hhmmss = sorted([int(stem[1:]) for stem in [f.stem for f in folder_times]]) @@ -706,7 +706,7 @@ def _copy_collections(self, folder_neurophotometric: Path) -> bool: SystemTimestamp=pandera.Column(pandera.Float64), LedState=pandera.Column(pandera.Int16, coerce=True), ComputerTimestamp=pandera.Column(pandera.Float64), - **{k: pandera.Column(pandera.Float64) for k in ed['fibers'].keys()}, + **{k: pandera.Column(pandera.Float64) for k in ed['fibers']}, ) ) schema_digital_inputs = pandera.DataFrameSchema( From db9cd249d15a35ad486eb4ff8982af618b71c56c Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Mon, 11 Nov 2024 10:21:47 +0000 Subject: [PATCH 33/43] Update test_neurophotometrics.py --- iblrig/test/test_neurophotometrics.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iblrig/test/test_neurophotometrics.py b/iblrig/test/test_neurophotometrics.py index 1c030bd51..29b36f67c 100644 --- a/iblrig/test/test_neurophotometrics.py +++ b/iblrig/test/test_neurophotometrics.py @@ -1,7 +1,6 @@ import datetime import unittest - from iblrig.transfer_experiments import NeurophotometricsCopier From 347c705eb7d2769c2b01f16a11edec8680ebecbd Mon Sep 17 00:00:00 2001 From: Olivier Winter Date: Mon, 11 Nov 2024 20:28:51 +0000 Subject: [PATCH 34/43] make sure the description starts with device name --- iblrig/transfer_experiments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index c7db422a7..52361941c 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -677,10 +677,10 @@ def neurophotometrics_description( if sync_label is not None: description['sync_label'] = sync_label description['fibers'] = {roi: {'location': location} for roi, location in zip(rois, locations, strict=False)} - return description + return {'neurophotometrics': description} def _copy_collections(self, folder_neurophotometric: Path) -> bool: - ed = self.experiment_description + ed = self.experiment_description['neurophotometrics'] dt = datetime.datetime.fromisoformat(ed['datetime']) # Here we find the first photometry folder after the start_time. In case this is failing # we can feed a custom start_time to go to the desired folder, or just rename the folder From 6da07ff511c78d1d448ab02cf84ff19450e11cc1 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Tue, 12 Nov 2024 09:39:21 +0000 Subject: [PATCH 35/43] update dependencies / add pandera --- pdm.lock | 781 +++++++++++++++++++++++++++---------------------- pyproject.toml | 21 +- 2 files changed, 436 insertions(+), 366 deletions(-) diff --git a/pdm.lock b/pdm.lock index c3a06439d..1d7197a65 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "ci", "dev", "doc", "project-extraction", "test", "typing"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:60948b73e6c0cf6b0e4e0fd3ce6557231ad52be77ce8672a875515b803095306" +content_hash = "sha256:c97e968e3767f865a7e85a77876985818811a72c4a8bbe9d81b4d44b06a5c7f8" [[metadata.targets]] requires_python = "==3.10.*" @@ -132,23 +132,23 @@ files = [ [[package]] name = "boto3" -version = "1.35.42" +version = "1.35.58" requires_python = ">=3.8" summary = "The AWS SDK for Python" groups = ["default"] dependencies = [ - "botocore<1.36.0,>=1.35.42", + "botocore<1.36.0,>=1.35.58", "jmespath<2.0.0,>=0.7.1", "s3transfer<0.11.0,>=0.10.0", ] files = [ - {file = "boto3-1.35.42-py3-none-any.whl", hash = "sha256:e1f36f8be453505cebcc3da178ea081b2a06c0e5e1cdee774f1067599b8d9c3e"}, - {file = "boto3-1.35.42.tar.gz", hash = "sha256:a5b00f8b82dce62870759f04861747944da834d64a64355970120c475efdafc0"}, + {file = "boto3-1.35.58-py3-none-any.whl", hash = "sha256:856896fd5fc5871758eb04b27bad5bbbf0fdb6143a923f9e8d10125351efdf98"}, + {file = "boto3-1.35.58.tar.gz", hash = "sha256:1ee139e63f1545ee0192914cfe422b68360b8c344a94e4612ac657dd7ece93de"}, ] [[package]] name = "botocore" -version = "1.35.42" +version = "1.35.58" requires_python = ">=3.8" summary = "Low-level, data-driven core of boto 3." groups = ["default"] @@ -159,8 +159,8 @@ dependencies = [ "urllib3<1.27,>=1.25.4; python_version < \"3.10\"", ] files = [ - {file = "botocore-1.35.42-py3-none-any.whl", hash = "sha256:05af0bb8b9cea7ce7bc589c332348d338a21b784e9d088a588fd10ec145007ff"}, - {file = "botocore-1.35.42.tar.gz", hash = "sha256:af348636f73dc24b7e2dc760a34d08c8f2f94366e9b4c78d877307b128abecef"}, + {file = "botocore-1.35.58-py3-none-any.whl", hash = "sha256:647b8706ae6484ee4c2208235f38976d9f0e52f80143e81d7941075215e96111"}, + {file = "botocore-1.35.58.tar.gz", hash = "sha256:8303309c7b59ddf04b11d79813530809d6b10b411ac9f93916d2032c283d6881"}, ] [[package]] @@ -180,6 +180,10 @@ files = [ {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec"}, {file = "Brotli-1.1.0-cp310-cp310-win32.whl", hash = "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2"}, {file = "Brotli-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128"}, {file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"}, @@ -322,7 +326,7 @@ files = [ [[package]] name = "colorlog" -version = "6.8.2" +version = "6.9.0" requires_python = ">=3.6" summary = "Add colours to the output of Python's logging module." groups = ["default"] @@ -330,8 +334,8 @@ dependencies = [ "colorama; sys_platform == \"win32\"", ] files = [ - {file = "colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33"}, - {file = "colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44"}, + {file = "colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"}, + {file = "colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2"}, ] [[package]] @@ -386,54 +390,54 @@ files = [ [[package]] name = "coverage" -version = "7.6.3" +version = "7.6.4" requires_python = ">=3.9" summary = "Code coverage measurement for Python" groups = ["dev", "test"] files = [ - {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, - {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, - {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, - {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, - {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, - {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [[package]] name = "coverage" -version = "7.6.3" +version = "7.6.4" extras = ["toml"] requires_python = ">=3.9" summary = "Code coverage measurement for Python" groups = ["dev", "test"] dependencies = [ - "coverage==7.6.3", + "coverage==7.6.4", "tomli; python_full_version <= \"3.11.0a6\"", ] files = [ - {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, - {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, - {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, - {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, - {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, - {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" requires_python = ">=3.7" summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." groups = ["default"] @@ -441,29 +445,29 @@ dependencies = [ "cffi>=1.12; platform_python_implementation != \"PyPy\"", ] files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [[package]] @@ -494,7 +498,7 @@ files = [ [[package]] name = "dask" -version = "2024.10.0" +version = "2024.11.1" requires_python = ">=3.10" summary = "Parallel PyData with Task Scheduling" groups = ["default"] @@ -509,8 +513,8 @@ dependencies = [ "toolz>=0.10.0", ] files = [ - {file = "dask-2024.10.0-py3-none-any.whl", hash = "sha256:1ddc27c7967e134b4f8296a488521485a5ac4927cc63e2abfa0b24227b93217f"}, - {file = "dask-2024.10.0.tar.gz", hash = "sha256:dfd3efec5d8d8340fb647d0347637133030cad261b714623cc27de286e9db037"}, + {file = "dask-2024.11.1-py3-none-any.whl", hash = "sha256:749eb85ca16982bd0d754694afa3c2ac9dbcb11a598f25a47155ca12f562db5c"}, + {file = "dask-2024.11.1.tar.gz", hash = "sha256:6d8013304d97660ce802ccc9570aae8b0a00d8d3b041c125463611db14b93177"}, ] [[package]] @@ -529,17 +533,17 @@ files = [ [[package]] name = "debugpy" -version = "1.8.7" +version = "1.8.8" requires_python = ">=3.8" summary = "An implementation of the Debug Adapter Protocol for Python" groups = ["dev", "doc"] files = [ - {file = "debugpy-1.8.7-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:95fe04a573b8b22896c404365e03f4eda0ce0ba135b7667a1e57bd079793b96b"}, - {file = "debugpy-1.8.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:628a11f4b295ffb4141d8242a9bb52b77ad4a63a2ad19217a93be0f77f2c28c9"}, - {file = "debugpy-1.8.7-cp310-cp310-win32.whl", hash = "sha256:85ce9c1d0eebf622f86cc68618ad64bf66c4fc3197d88f74bb695a416837dd55"}, - {file = "debugpy-1.8.7-cp310-cp310-win_amd64.whl", hash = "sha256:29e1571c276d643757ea126d014abda081eb5ea4c851628b33de0c2b6245b037"}, - {file = "debugpy-1.8.7-py2.py3-none-any.whl", hash = "sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae"}, - {file = "debugpy-1.8.7.zip", hash = "sha256:18b8f731ed3e2e1df8e9cdaa23fb1fc9c24e570cd0081625308ec51c82efe42e"}, + {file = "debugpy-1.8.8-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:e59b1607c51b71545cb3496876544f7186a7a27c00b436a62f285603cc68d1c6"}, + {file = "debugpy-1.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6531d952b565b7cb2fbd1ef5df3d333cf160b44f37547a4e7cf73666aca5d8d"}, + {file = "debugpy-1.8.8-cp310-cp310-win32.whl", hash = "sha256:b01f4a5e5c5fb1d34f4ccba99a20ed01eabc45a4684f4948b5db17a319dfb23f"}, + {file = "debugpy-1.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:535f4fb1c024ddca5913bb0eb17880c8f24ba28aa2c225059db145ee557035e9"}, + {file = "debugpy-1.8.8-py2.py3-none-any.whl", hash = "sha256:ec684553aba5b4066d4de510859922419febc710df7bba04fe9e7ef3de15d34f"}, + {file = "debugpy-1.8.8.zip", hash = "sha256:e6355385db85cbd666be703a96ab7351bc9e6c61d694893206f8001e22aee091"}, ] [[package]] @@ -660,18 +664,18 @@ files = [ [[package]] name = "fsspec" -version = "2024.9.0" +version = "2024.10.0" requires_python = ">=3.8" summary = "File-system specification" groups = ["default"] files = [ - {file = "fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b"}, - {file = "fsspec-2024.9.0.tar.gz", hash = "sha256:4b0afb90c2f21832df142f292649035d80b421f60a9e1c027802e5a0da2b04e8"}, + {file = "fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871"}, + {file = "fsspec-2024.10.0.tar.gz", hash = "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493"}, ] [[package]] name = "globus-sdk" -version = "3.46.0" +version = "3.47.0" requires_python = ">=3.8" summary = "Globus SDK for Python" groups = ["default"] @@ -683,8 +687,8 @@ dependencies = [ "typing-extensions>=4.0; python_version < \"3.11\"", ] files = [ - {file = "globus_sdk-3.46.0-py3-none-any.whl", hash = "sha256:3e97ba898f410e7618314c7cc41b4c7afe5b551614f6f2255e15cf9aaca50954"}, - {file = "globus_sdk-3.46.0.tar.gz", hash = "sha256:eb5e1a3e724b6afe89277f2e3aed6d4959d7d3c4b05ed51f084eaa60ee6a4d25"}, + {file = "globus_sdk-3.47.0-py3-none-any.whl", hash = "sha256:c7a7af7646daf1ae8db9844c0de3964360ac7f48da4c7b528d0117d2a00dbe80"}, + {file = "globus_sdk-3.47.0.tar.gz", hash = "sha256:1c860c5115100a2cce1ef9cf1e053bea51393bcfd899f7f33050a29da9ec6198"}, ] [[package]] @@ -732,25 +736,10 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] -[[package]] -name = "html5lib" -version = "1.1" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -summary = "HTML parser based on the WHATWG HTML specification" -groups = ["dev", "doc"] -dependencies = [ - "six>=1.9", - "webencodings", -] -files = [ - {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, - {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, -] - [[package]] name = "ibl-neuropixel" -version = "1.4.0" -requires_python = ">=3.8" +version = "1.5.0" +requires_python = ">=3.10" summary = "Collection of tools for Neuropixel 1.0 and 2.0 probes data" groups = ["default"] dependencies = [ @@ -764,8 +753,8 @@ dependencies = [ "scipy>=1.11", ] files = [ - {file = "ibl_neuropixel-1.4.0-py3-none-any.whl", hash = "sha256:c5e529662fcf0040078e1746bc90304b80b107b2e91030a3b2d381f3b7b9c84f"}, - {file = "ibl_neuropixel-1.4.0.tar.gz", hash = "sha256:78f46b3174f8e3ed1307ed805673419ea4973d8497152f774c1f582fe891720c"}, + {file = "ibl_neuropixel-1.5.0-py3-none-any.whl", hash = "sha256:5e37a62098802c89088ddad846c1a1f1805341e271ac6be46f8f2a39118ae921"}, + {file = "ibl_neuropixel-1.5.0.tar.gz", hash = "sha256:4c4a5e08dc4a21209a79b0c0044cbab32e0602efe25ec23b2fbf175d2ad44e66"}, ] [[package]] @@ -789,21 +778,21 @@ files = [ [[package]] name = "ibllib" -version = "2.39.1" +version = "2.40.1" requires_python = ">=3.8" summary = "IBL libraries" groups = ["default"] dependencies = [ - "ONE-api~=2.9.rc0", + "ONE-api>=2.10", "boto3", "click>=7.0.0", "colorlog>=4.0.2", "flake8>=3.7.8", "globus-sdk", "graphviz", - "ibl-neuropixel>=1.0.1", + "ibl-neuropixel>=1.5.0", "iblatlas>=0.5.3", - "iblutil>=1.11.0", + "iblutil>=1.13.0", "imagecodecs", "matplotlib>=3.0.3", "mtscomp>=1.0.1", @@ -828,8 +817,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "ibllib-2.39.1-py3-none-any.whl", hash = "sha256:261e7798befb5daed08d70f10918a9739003e38026357875ea2d6dcc912fcc4e"}, - {file = "ibllib-2.39.1.tar.gz", hash = "sha256:79ede021deb02b98810efc0d70b10913db7c53109c4cfe2c18028d5d214a449b"}, + {file = "ibllib-2.40.1-py3-none-any.whl", hash = "sha256:1eab186949395f4a660bad1f20a1e32893ea0cf4d83f90a6d7146e6bc3d31a44"}, + {file = "ibllib-2.40.1.tar.gz", hash = "sha256:8dbb2b70d3bf07b05eeb0b6cc32abd01192fc31fc6fe45832b191e5333eaff58"}, ] [[package]] @@ -871,7 +860,7 @@ files = [ [[package]] name = "iblutil" -version = "1.13.0" +version = "1.14.0" requires_python = ">=3.8" summary = "IBL utilities" groups = ["default"] @@ -885,8 +874,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "iblutil-1.13.0-py3-none-any.whl", hash = "sha256:14a1d3bef30564d633433b3f9dbf8c3ec7c2bb3dfea2d1cd077107f31a986209"}, - {file = "iblutil-1.13.0.tar.gz", hash = "sha256:cc16a1fcc3e82fe2d6425e2b24fc2952e1d49824bfbf6a7a7d7feb502fdae7f1"}, + {file = "iblutil-1.14.0-py3-none-any.whl", hash = "sha256:b402e834a0e719c315b989f538e34b99d9c46430c2c2f5e6606f6951063c938e"}, + {file = "iblutil-1.14.0.tar.gz", hash = "sha256:1b2214d7e1b4b3e47c0d296a2a7181ca98592383648d032eca5d949b538e694c"}, ] [[package]] @@ -1000,7 +989,7 @@ files = [ [[package]] name = "ipython" -version = "8.28.0" +version = "8.29.0" requires_python = ">=3.10" summary = "IPython: Productive Interactive Computing" groups = ["default", "dev", "doc"] @@ -1018,22 +1007,22 @@ dependencies = [ "typing-extensions>=4.6; python_version < \"3.12\"", ] files = [ - {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, - {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, + {file = "ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8"}, + {file = "ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"}, ] [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" requires_python = ">=3.6" summary = "An autocompletion tool for Python that can be used for text editors." groups = ["default", "dev", "doc"] dependencies = [ - "parso<0.9.0,>=0.8.3", + "parso<0.9.0,>=0.8.4", ] files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [[package]] @@ -1265,22 +1254,22 @@ files = [ [[package]] name = "markupsafe" -version = "3.0.1" +version = "3.0.2" requires_python = ">=3.9" summary = "Safely add untrusted strings to HTML/XML markup." groups = ["dev", "doc"] files = [ - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win32.whl", hash = "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97"}, - {file = "MarkupSafe-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9"}, - {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -1371,9 +1360,20 @@ files = [ {file = "mtscomp-1.0.2.tar.gz", hash = "sha256:609c4fe5a0d00532c1452b10318a74e04add8e47c562aca216e7b40de0e4bf73"}, ] +[[package]] +name = "multimethod" +version = "1.10" +requires_python = ">=3.8" +summary = "Multiple argument dispatching." +groups = ["default"] +files = [ + {file = "multimethod-1.10-py3-none-any.whl", hash = "sha256:afd84da9c3d0445c84f827e4d63ad42d17c6d29b122427c6dee9032ac2d2a0d4"}, + {file = "multimethod-1.10.tar.gz", hash = "sha256:daa45af3fe257f73abb69673fd54ddeaf31df0eb7363ad6e1251b7c9b192d8c5"}, +] + [[package]] name = "mypy" -version = "1.12.0" +version = "1.13.0" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["dev", "typing"] @@ -1383,13 +1383,13 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4397081e620dc4dc18e2f124d5e1d2c288194c2c08df6bdb1db31c38cd1fe1ed"}, - {file = "mypy-1.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:684a9c508a283f324804fea3f0effeb7858eb03f85c4402a967d187f64562469"}, - {file = "mypy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cabe4cda2fa5eca7ac94854c6c37039324baaa428ecbf4de4567279e9810f9e"}, - {file = "mypy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:060a07b10e999ac9e7fa249ce2bdcfa9183ca2b70756f3bce9df7a92f78a3c0a"}, - {file = "mypy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0eff042d7257f39ba4ca06641d110ca7d2ad98c9c1fb52200fe6b1c865d360ff"}, - {file = "mypy-1.12.0-py3-none-any.whl", hash = "sha256:fd313226af375d52e1e36c383f39bf3836e1f192801116b31b090dfcd3ec5266"}, - {file = "mypy-1.12.0.tar.gz", hash = "sha256:65a22d87e757ccd95cbbf6f7e181e6caa87128255eb2b6be901bb71b26d8a99d"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [[package]] @@ -1397,7 +1397,7 @@ name = "mypy-extensions" version = "1.0.0" requires_python = ">=3.5" summary = "Type system extensions for programs checked with the mypy type checker." -groups = ["dev", "typing"] +groups = ["default", "dev", "typing"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1492,13 +1492,13 @@ files = [ [[package]] name = "networkx" -version = "3.4.1" +version = "3.4.2" requires_python = ">=3.10" summary = "Python package for creating and manipulating graphs and networks" groups = ["default"] files = [ - {file = "networkx-3.4.1-py3-none-any.whl", hash = "sha256:e30a87b48c9a6a7cc220e732bffefaee585bdb166d13377734446ce1a0620eed"}, - {file = "networkx-3.4.1.tar.gz", hash = "sha256:f9df45e85b78f5bd010993e897b4f1fdb242c11e015b101bd951e5c0e29982d8"}, + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, ] [[package]] @@ -1513,22 +1513,6 @@ files = [ {file = "npTDMS-1.9.0.tar.gz", hash = "sha256:0e65c237e9d50b9b8e162b9c34171353a5ea05f4019c99c3e8ebc00722361cbc"}, ] -[[package]] -name = "nptyping" -version = "2.5.0" -requires_python = ">=3.7" -summary = "Type hints for NumPy." -groups = ["default"] -dependencies = [ - "numpy<2.0.0,>=1.20.0; python_version >= \"3.8\"", - "numpy==1.21.5; python_version < \"3.8\"", - "typing-extensions<5.0.0,>=4.0.0; python_version < \"3.10\"", -] -files = [ - {file = "nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8"}, - {file = "nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a"}, -] - [[package]] name = "numba" version = "0.60.0" @@ -1550,32 +1534,34 @@ files = [ [[package]] name = "numpy" -version = "1.26.4" +version = "2.0.2" requires_python = ">=3.9" summary = "Fundamental package for array computing in Python" groups = ["default"] files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, ] [[package]] name = "one-api" -version = "2.9.1" +version = "2.11.1" requires_python = ">=3.7" summary = "Open Neurophysiology Environment" groups = ["default"] dependencies = [ "boto3", "flake8>=3.7.8", - "iblutil>=1.1.0", + "iblutil>=1.13.0", "numpy>=1.18", "packaging", "pandas>=1.5.0", @@ -1584,8 +1570,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "ONE_api-2.9.1-py3-none-any.whl", hash = "sha256:d1249e33967edbbd5cc853be2fecc16074fed804418b22940b32b1341fdac36c"}, - {file = "one_api-2.9.1.tar.gz", hash = "sha256:31e8f72a542ab0a1207003dc631a3251a86e12f72c9107d5754b3ba9a5bd33b3"}, + {file = "ONE_api-2.11.1-py3-none-any.whl", hash = "sha256:a5a69d3e6324781f8bd46a3c697a68f6ce286ca25f9c9ffb8175a2747a57aa66"}, + {file = "one_api-2.11.1.tar.gz", hash = "sha256:cb1773f3a06fbf80222d2ea366673a961318951aaf3b640c1fbebbe3ea806a2b"}, ] [[package]] @@ -1618,13 +1604,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" groups = ["default", "ci", "dev", "doc", "test"] files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -1652,6 +1638,28 @@ files = [ {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, ] +[[package]] +name = "pandera" +version = "0.20.4" +requires_python = ">=3.7" +summary = "A light-weight and flexible data validation and testing tool for statistical data objects." +groups = ["default"] +dependencies = [ + "multimethod<=1.10.0", + "numpy>=1.19.0", + "packaging>=20.0", + "pandas>=1.2.0", + "pydantic", + "typeguard", + "typing-extensions>=3.7.4.3; python_version < \"3.8\"", + "typing-inspect>=0.6.0", + "wrapt", +] +files = [ + {file = "pandera-0.20.4-py3-none-any.whl", hash = "sha256:40368d9162938f304ce4ce6ad41ce4b57991b88f7de1bb4574aeb5a1ecf2dc8c"}, + {file = "pandera-0.20.4.tar.gz", hash = "sha256:ccf6178293ef9d4393dc4776e47477e3d2dd51c800ecdfedec67fff50f4ad3c2"}, +] + [[package]] name = "parso" version = "0.8.4" @@ -1680,16 +1688,16 @@ files = [ [[package]] name = "patsy" -version = "0.5.6" +version = "1.0.0" +requires_python = ">=3.6" summary = "A Python package for describing statistical models and for building design matrices." groups = ["default"] dependencies = [ "numpy>=1.4", - "six", ] files = [ - {file = "patsy-0.5.6-py2.py3-none-any.whl", hash = "sha256:19056886fd8fa71863fa32f0eb090267f21fb74be00f19f5c70b2e9d76c883c6"}, - {file = "patsy-0.5.6.tar.gz", hash = "sha256:95c6d47a7222535f84bff7f63d7303f2e297747a598db89cf5c67f0c0c7d2cdb"}, + {file = "patsy-1.0.0-py2.py3-none-any.whl", hash = "sha256:290ca9aa81b1821f705f86ab3f89cce3f898cdc020ab0304ee6e1f0f42513ef0"}, + {file = "patsy-1.0.0.tar.gz", hash = "sha256:787d2a5d15333fb1e4dc11331b2e7fd17d92f9a815db2fbca29b50c0e6c0159d"}, ] [[package]] @@ -1728,30 +1736,30 @@ files = [ [[package]] name = "pillow" -version = "11.0.0" -requires_python = ">=3.9" +version = "10.4.0" +requires_python = ">=3.8" summary = "Python Imaging Library (Fork)" groups = ["default", "dev", "doc"] files = [ - {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, - {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, - {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, - {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, - {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, - {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, - {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, - {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, ] [[package]] @@ -1778,10 +1786,10 @@ files = [ [[package]] name = "project-extraction" -version = "0.3.0" +version = "0.4.0" requires_python = "~=3.10" git = "https://github.com/int-brain-lab/project_extraction.git" -revision = "f9b5a45c6a812bf736b6fd5237bfc8d5f3768e2e" +revision = "c3ae3e2e54072e273cb31d16b04cb264a03ee6f4" summary = "Custom extractors for satellite tasks" groups = ["project-extraction"] @@ -1801,19 +1809,19 @@ files = [ [[package]] name = "psutil" -version = "6.0.0" +version = "6.1.0" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" summary = "Cross-platform lib for process and system monitoring in Python." groups = ["dev", "doc"] files = [ - {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, - {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, - {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, - {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, - {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, + {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, + {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, + {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, ] [[package]] @@ -1854,22 +1862,19 @@ files = [ [[package]] name = "pyarrow" -version = "17.0.0" -requires_python = ">=3.8" +version = "18.0.0" +requires_python = ">=3.9" summary = "Python library for Apache Arrow" groups = ["default"] -dependencies = [ - "numpy>=1.16.6", -] files = [ - {file = "pyarrow-17.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a5c8b238d47e48812ee577ee20c9a2779e6a5904f1708ae240f53ecbee7c9f07"}, - {file = "pyarrow-17.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db023dc4c6cae1015de9e198d41250688383c3f9af8f565370ab2b4cb5f62655"}, - {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da1e060b3876faa11cee287839f9cc7cdc00649f475714b8680a05fd9071d545"}, - {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c06d4624c0ad6674364bb46ef38c3132768139ddec1c56582dbac54f2663e2"}, - {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fa3c246cc58cb5a4a5cb407a18f193354ea47dd0648194e6265bd24177982fe8"}, - {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:f7ae2de664e0b158d1607699a16a488de3d008ba99b3a7aa5de1cbc13574d047"}, - {file = "pyarrow-17.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5984f416552eea15fd9cee03da53542bf4cddaef5afecefb9aa8d1010c335087"}, - {file = "pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28"}, + {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2333f93260674e185cfbf208d2da3007132572e56871f451ba1a556b45dae6e2"}, + {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4c381857754da44326f3a49b8b199f7f87a51c2faacd5114352fc78de30d3aba"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:603cd8ad4976568954598ef0a6d4ed3dfb78aff3d57fa8d6271f470f0ce7d34f"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58a62549a3e0bc9e03df32f350e10e1efb94ec6cf63e3920c3385b26663948ce"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bc97316840a349485fbb137eb8d0f4d7057e1b2c1272b1a20eebbbe1848f5122"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:2e549a748fa8b8715e734919923f69318c953e077e9c02140ada13e59d043310"}, + {file = "pyarrow-18.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:606e9a3dcb0f52307c5040698ea962685fb1c852d72379ee9412be7de9c5f9e2"}, + {file = "pyarrow-18.0.0.tar.gz", hash = "sha256:a6aa027b1a9d2970cf328ccd6dbe4a996bc13c39fd427f502782f5bdb9ca20f5"}, ] [[package]] @@ -2006,18 +2011,17 @@ files = [ [[package]] name = "pynrrd" -version = "1.0.0" +version = "1.1.1" requires_python = ">=3.7" summary = "Pure python module for reading and writing NRRD files." groups = ["default"] dependencies = [ - "nptyping", - "numpy>=1.11.1", + "numpy>=1.21", "typing-extensions", ] files = [ - {file = "pynrrd-1.0.0-py2.py3-none-any.whl", hash = "sha256:65e5a61920d2f01ecf321eb41b0472940e181e4ba5e8a32f01ef5499d4192db5"}, - {file = "pynrrd-1.0.0.tar.gz", hash = "sha256:4eb4caba03fbca1b832114515e748336cb67bce70c7f3ae36bfa2e135fc990d2"}, + {file = "pynrrd-1.1.1-py3-none-any.whl", hash = "sha256:e65ae7ac53583ad5d71a03845c9247ff2238415b91980f1fd9486d4ec3d62c43"}, + {file = "pynrrd-1.1.1.tar.gz", hash = "sha256:dafd98d778263b1c90eac1d42779886153daa97a4577dea9590f74dab18b4ca2"}, ] [[package]] @@ -2033,13 +2037,13 @@ files = [ [[package]] name = "pyphen" -version = "0.16.0" +version = "0.15.0" requires_python = ">=3.8" summary = "Pure Python module to hyphenate text" groups = ["dev", "doc"] files = [ - {file = "pyphen-0.16.0-py3-none-any.whl", hash = "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c"}, - {file = "pyphen-0.16.0.tar.gz", hash = "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413"}, + {file = "pyphen-0.15.0-py3-none-any.whl", hash = "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858"}, + {file = "pyphen-0.15.0.tar.gz", hash = "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2"}, ] [[package]] @@ -2175,17 +2179,17 @@ files = [ [[package]] name = "pytest-cov" -version = "5.0.0" -requires_python = ">=3.8" +version = "6.0.0" +requires_python = ">=3.9" summary = "Pytest plugin for measuring coverage." groups = ["dev", "test"] dependencies = [ - "coverage[toml]>=5.2.1", + "coverage[toml]>=7.5", "pytest>=4.6", ] files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, ] [[package]] @@ -2311,7 +2315,7 @@ files = [ [[package]] name = "qtpy" -version = "2.4.1" +version = "2.4.2" requires_python = ">=3.7" summary = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." groups = ["default"] @@ -2319,8 +2323,8 @@ dependencies = [ "packaging", ] files = [ - {file = "QtPy-2.4.1-py3-none-any.whl", hash = "sha256:1c1d8c4fa2c884ae742b069151b0abe15b3f70491f3972698c683b8e38de839b"}, - {file = "QtPy-2.4.1.tar.gz", hash = "sha256:a5a15ffd519550a1361bdc56ffc07fda56a6af7292f17c7b395d4083af632987"}, + {file = "QtPy-2.4.2-py3-none-any.whl", hash = "sha256:5a696b1dd7a354cb330657da1d17c20c2190c72d4888ba923f8461da67aa1a1c"}, + {file = "qtpy-2.4.2.tar.gz", hash = "sha256:9d6ec91a587cc1495eaebd23130f7619afa5cdd34a277acb87735b4ad7c65156"}, ] [[package]] @@ -2357,64 +2361,64 @@ files = [ [[package]] name = "rpds-py" -version = "0.20.0" -requires_python = ">=3.8" +version = "0.21.0" +requires_python = ">=3.9" summary = "Python bindings to Rust's persistent data structures (rpds)" groups = ["dev", "doc"] files = [ - {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, - {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, - {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, - {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, - {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, + {file = "rpds_py-0.21.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590"}, + {file = "rpds_py-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664"}, + {file = "rpds_py-0.21.0-cp310-none-win32.whl", hash = "sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682"}, + {file = "rpds_py-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677"}, + {file = "rpds_py-0.21.0.tar.gz", hash = "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db"}, ] [[package]] name = "ruff" -version = "0.7.0" +version = "0.7.3" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev", "test"] files = [ - {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"}, - {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"}, - {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"}, - {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"}, - {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"}, - {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"}, - {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"}, + {file = "ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344"}, + {file = "ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0"}, + {file = "ruff-0.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16"}, + {file = "ruff-0.7.3-py3-none-win32.whl", hash = "sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc"}, + {file = "ruff-0.7.3-py3-none-win_amd64.whl", hash = "sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088"}, + {file = "ruff-0.7.3-py3-none-win_arm64.whl", hash = "sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c"}, + {file = "ruff-0.7.3.tar.gz", hash = "sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313"}, ] [[package]] @@ -2516,13 +2520,13 @@ files = [ [[package]] name = "setuptools" -version = "75.2.0" -requires_python = ">=3.8" +version = "75.4.0" +requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" groups = ["dev", "doc"] files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.4.0-py3-none-any.whl", hash = "sha256:b3c5d862f98500b06ffdf7cc4499b48c46c317d8d56cb30b5c8bce4d88f5c216"}, + {file = "setuptools-75.4.0.tar.gz", hash = "sha256:1dc484f5cf56fd3fe7216d7b8df820802e7246cfb534a1db2aa64f14fcb9cdcb"}, ] [[package]] @@ -2685,7 +2689,7 @@ files = [ [[package]] name = "sphinx-lesson" -version = "0.8.18" +version = "0.8.19" requires_python = ">=3.3" summary = "Sphinx extension for CodeRefinery lessons" groups = ["dev", "doc"] @@ -2701,8 +2705,8 @@ dependencies = [ "sphinx<8", ] files = [ - {file = "sphinx_lesson-0.8.18-py3-none-any.whl", hash = "sha256:359df9ec81ae5802d35ea7f18b4ef548e0489942ca61d4560392a8e0c0493c89"}, - {file = "sphinx_lesson-0.8.18.tar.gz", hash = "sha256:9cb755befd90e1836dc7798113959e86fe7296048a6d88924076cd8215ab1829"}, + {file = "sphinx_lesson-0.8.19-py3-none-any.whl", hash = "sha256:9f8fe51a61cbcfc3a9b57916abe15dbd4654cb5f0d9d1e7492a37fec27fe95ff"}, + {file = "sphinx_lesson-0.8.19.tar.gz", hash = "sha256:acf1a75fa38c21cd6e479465e17766f64beb482e4c3874fe8415c44e36261029"}, ] [[package]] @@ -2913,7 +2917,7 @@ files = [ [[package]] name = "starlette" -version = "0.41.0" +version = "0.41.2" requires_python = ">=3.8" summary = "The little ASGI library that shines." groups = ["dev", "doc"] @@ -2922,8 +2926,8 @@ dependencies = [ "typing-extensions>=3.10.0; python_version < \"3.10\"", ] files = [ - {file = "starlette-0.41.0-py3-none-any.whl", hash = "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a"}, - {file = "starlette-0.41.0.tar.gz", hash = "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a"}, + {file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"}, + {file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"}, ] [[package]] @@ -2987,7 +2991,7 @@ files = [ [[package]] name = "tinycss2" -version = "1.3.0" +version = "1.4.0" requires_python = ">=3.8" summary = "A tiny CSS parser" groups = ["dev", "doc"] @@ -2995,19 +2999,33 @@ dependencies = [ "webencodings>=0.4", ] files = [ - {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, - {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, + {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, + {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, +] + +[[package]] +name = "tinyhtml5" +version = "2.0.0" +requires_python = ">=3.9" +summary = "HTML parser based on the WHATWG HTML specification" +groups = ["dev", "doc"] +dependencies = [ + "webencodings>=0.5.1", +] +files = [ + {file = "tinyhtml5-2.0.0-py3-none-any.whl", hash = "sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e"}, + {file = "tinyhtml5-2.0.0.tar.gz", hash = "sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc"}, ] [[package]] name = "tomli" -version = "2.0.2" +version = "2.1.0" requires_python = ">=3.8" summary = "A lil' TOML parser" groups = ["default", "ci", "dev", "doc", "test", "typing"] files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -3043,7 +3061,7 @@ files = [ [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.0" requires_python = ">=3.7" summary = "Fast, Extensible Progress Meter" groups = ["default"] @@ -3051,8 +3069,8 @@ dependencies = [ "colorama; platform_system == \"Windows\"", ] files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be"}, + {file = "tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a"}, ] [[package]] @@ -3078,6 +3096,21 @@ files = [ {file = "tycmd_wrapper-0.2.1-py3-none-win_amd64.whl", hash = "sha256:73c17d7c6d073d7dd2b050731988a5fabb3be69ec339c3ef5fcfaae42eefe090"}, ] +[[package]] +name = "typeguard" +version = "4.4.1" +requires_python = ">=3.9" +summary = "Run-time type checker for Python" +groups = ["default"] +dependencies = [ + "importlib-metadata>=3.6; python_version < \"3.10\"", + "typing-extensions>=4.10.0", +] +files = [ + {file = "typeguard-4.4.1-py3-none-any.whl", hash = "sha256:9324ec07a27ec67fc54a9c063020ca4c0ae6abad5e9f0f9804ca59aee68c6e21"}, + {file = "typeguard-4.4.1.tar.gz", hash = "sha256:0d22a89d00b453b47c49875f42b6601b961757541a2e1e0ef517b6e24213c21b"}, +] + [[package]] name = "types-pyserial" version = "3.5.0.20240826" @@ -3136,6 +3169,21 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "typing-inspect" +version = "0.9.0" +summary = "Runtime inspection utilities for typing module." +groups = ["default"] +dependencies = [ + "mypy-extensions>=0.3.0", + "typing-extensions>=3.7.4", + "typing>=3.7.4; python_version < \"3.5\"", +] +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + [[package]] name = "tzdata" version = "2024.2" @@ -3218,23 +3266,23 @@ files = [ [[package]] name = "weasyprint" -version = "62.3" +version = "63.0" requires_python = ">=3.9" summary = "The Awesome Document Factory" groups = ["dev", "doc"] dependencies = [ - "Pillow>=9.1.0", - "Pyphen>=0.9.1", - "cffi>=0.6", - "cssselect2>=0.1", - "fonttools[woff]>=4.0.0", - "html5lib>=1.1", - "pydyf>=0.10.0", - "tinycss2>=1.3.0", + "Pillow<11,>=9.1.0", + "Pyphen<0.16,>=0.9.1", + "cffi<2,>=0.6", + "cssselect2<0.8,>=0.1", + "fonttools[woff]<5,>=4.0.0", + "pydyf<0.12,>=0.11.0", + "tinycss2<2,>=1.4.0", + "tinyhtml5<3,>=2.0.0b1", ] files = [ - {file = "weasyprint-62.3-py3-none-any.whl", hash = "sha256:d31048646ce15084e135b33e334a61f526aa68d2f679fcc109ed0e0f5edaed21"}, - {file = "weasyprint-62.3.tar.gz", hash = "sha256:8d8680d732f7fa0fcbc587692a5a5cb095c3525627066918d6e203cbf42b7fcd"}, + {file = "weasyprint-63.0-py3-none-any.whl", hash = "sha256:57d02dcfd06811a1299730c01dcc0e14eb81e990c8c51844a7fc0351fd71ed83"}, + {file = "weasyprint-63.0.tar.gz", hash = "sha256:ec24c64fdcc63e4168b2c24eb89b1ee8a711281a7d7fdb3eed3f54995489c9d1"}, ] [[package]] @@ -3249,74 +3297,95 @@ files = [ [[package]] name = "websockets" -version = "13.1" -requires_python = ">=3.8" +version = "14.0" +requires_python = ">=3.9" summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" groups = ["dev", "doc"] files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {file = "websockets-14.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:064a72c0602c2d2c2586143561e0f179ef9b98e0825dc4a3d5cdf55a81898ed6"}, + {file = "websockets-14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9dc5a2726fd16c266d35838db086fa4e621bb049e3bbe498ab9d54ad5068f726"}, + {file = "websockets-14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e541e4c8983b118a584c306070878e7f9670b7781e04184b6e05f9fc92e8a0e"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23b13edb4df2d4e5d6dc747d83e6b244e267a6615ede90f18ef13dfb2b6feb87"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:288365a33049dae3065cdb2c2dd4b48df4b64839c565761c4f3f0c360460a561"}, + {file = "websockets-14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79e2494047826a56f2951b2ada9dc139d2c3aff63122e86953cafe64ac0fde75"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5a5b76b47b62de16d26439d362b18d71394ca4376eb2c8838352be64b27ba8af"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7ed4111f305770e35070e49fbb9fbf757a9b6c9a31bb86d352eb4031d4aa976f"}, + {file = "websockets-14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9af48a2f4cc5e2e34cf69969079865100e418c27caa26c1e3369efcc20c81e17"}, + {file = "websockets-14.0-cp310-cp310-win32.whl", hash = "sha256:a97c10043bf74d7667be69383312007d54a507fac8fa101be492cc91e279d94d"}, + {file = "websockets-14.0-cp310-cp310-win_amd64.whl", hash = "sha256:5f86250ee98f6098479936b7d596418b6e4c919dfa156508e9d6ac5f8bfbe764"}, + {file = "websockets-14.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3f1a697262e28682222f18fae70eb0800dfa50c6eb96b0561c6beb83d6cf78ca"}, + {file = "websockets-14.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e0e543e0e81c55e68552bd3c081282721c710a6379a2a78e1ec793853479b25"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2786c74cbcb0263fd541e4a075aa8c932bdcaa91e5bbb8649c65304799acdd64"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:176b39547950ff3520728bd1eadd0fa02c68492a1fabca636bab7883dd390905"}, + {file = "websockets-14.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86626d560ceb9d846d128b9c7bd2d0f247dbb62fb49c386762d109583140bf48"}, + {file = "websockets-14.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ca447967131023e98fcb4867f05cf8584adb424b9108180b2414745a6ff41c31"}, + {file = "websockets-14.0-py3-none-any.whl", hash = "sha256:1a3bca8cfb66614e23a65aa5d6b87190876ec6f3247094939f9db877db55319c"}, + {file = "websockets-14.0.tar.gz", hash = "sha256:be90aa6dab180fed523c0c10a6729ad16c9ba79067402d01a4d8aa7ce48d4084"}, ] [[package]] name = "wheel" -version = "0.44.0" +version = "0.45.0" requires_python = ">=3.8" summary = "A built-package format for Python" groups = ["dev", "doc"] files = [ - {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, - {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, + {file = "wheel-0.45.0-py3-none-any.whl", hash = "sha256:52f0baa5e6522155090a09c6bd95718cc46956d1b51d537ea5454249edb671c7"}, + {file = "wheel-0.45.0.tar.gz", hash = "sha256:a57353941a3183b3d5365346b567a260a0602a0f8a635926a7dede41b94c674a"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +requires_python = ">=3.6" +summary = "Module for decorators, wrappers and monkey patching." +groups = ["default"] +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [[package]] name = "zipp" -version = "3.20.2" -requires_python = ">=3.8" +version = "3.21.0" +requires_python = ">=3.9" summary = "Backport of pathlib-compatible object wrapper for zip files" groups = ["default", "dev", "doc"] files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [[package]] name = "zopfli" -version = "0.2.3" +version = "0.2.3.post1" requires_python = ">=3.8" summary = "Zopfli module for python" groups = ["dev", "doc"] files = [ - {file = "zopfli-0.2.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52438999888715a378fc6fe1477ab7813e9e9b58a27a38d2ad7be0e396b1ab2e"}, - {file = "zopfli-0.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6020a3533c6c7be09db9e59c2a8f3f894bf5d8e95cc01890d82114c923317c57"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:72349c78da402e6784bd9c5f4aff5cc7017bd969016ec07b656722f7f29fc975"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:711d4fde9cb99e1a9158978e9d1624a37cdd170ff057f6340059514fcf38e808"}, - {file = "zopfli-0.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae890df6e5f1e8fa0697cafd848826decce0ac53e54e5a018fd97775e3a354c0"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40b830244e6458ef982b4a5ebb0f228986d481408bae557a95eeece2c5ede4e6"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bc89b71d1c4677f708cc162f40a4560f78f5f4c6aa6d884b423df7d38e8ba0b"}, - {file = "zopfli-0.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f07997453e7777e19ef0a2445cc1b90e1bb90c623dd77554325932dea6350fee"}, - {file = "zopfli-0.2.3-cp310-cp310-win32.whl", hash = "sha256:978395a4ce5cc46db29a36cdb80549b564dc7706237abaca5aac328dd5842f65"}, - {file = "zopfli-0.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:61a2fcc624e8b038d4fca84ba927dc3f31df53a7284692d46aa44d16fb3f47b2"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:09ad5f8d7e0fe1975ca6d9fd5ad61c74233ae277982d3bc8814b599bbeb92f44"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78022777139ac973286219e9e085d9496fb6c935502d93a52bd1bed01dfc2002"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13d151d5c83980f384439c87a5511853890182c05d93444f3cb05e5ceed37d82"}, - {file = "zopfli-0.2.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c1afe5ba0d957e462afbd3da116ac1a2a6d23e8a94436a95b692c5c324694a16"}, - {file = "zopfli-0.2.3.zip", hash = "sha256:dbc9841bedd736041eb5e6982cd92da93bee145745f5422f3795f6f258cdc6ef"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0137dd64a493ba6a4be37405cfd6febe650a98cc1e9dca8f6b8c63b1db11b41"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aa588b21044f8a74e423d8c8a4c7fc9988501878aacced793467010039c50734"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f4a7ec2770e6af05f5a02733fd3900f30a9cd58e5d6d3727e14c5bcd6e7d587"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f7d69c1a7168ad0e9cb864e8663acb232986a0c9c9cb9801f56bf6214f53a54d"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2d2bc8129707e34c51f9352c4636ca313b52350bbb7e04637c46c1818a2a70"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39e576f93576c5c223b41d9c780bbb91fd6db4babf3223d2a4fe7bf568e2b5a8"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cbe6df25807227519debd1a57ab236f5f6bad441500e85b13903e51f93a43214"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7cce242b5df12b2b172489daf19c32e5577dd2fac659eb4b17f6a6efb446fd5c"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-win32.whl", hash = "sha256:f815fcc2b2a457977724bad97fb4854022980f51ce7b136925e336b530545ae1"}, + {file = "zopfli-0.2.3.post1-cp310-cp310-win_amd64.whl", hash = "sha256:0cc20b02a9531559945324c38302fd4ba763311632d0ec8a1a0aa9c10ea363e6"}, + {file = "zopfli-0.2.3.post1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4c1226a7e2c7105ac31503a9bb97454743f55d88164d6d46bc138051b77f609b"}, + {file = "zopfli-0.2.3.post1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48dba9251060289101343110ab47c0756f66f809bb4d1ddbb6d5c7e7752115c5"}, + {file = "zopfli-0.2.3.post1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89899641d4de97dbad8e0cde690040d078b6aea04066dacaab98e0b5a23573f2"}, + {file = "zopfli-0.2.3.post1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3654bfc927bc478b1c3f3ff5056ed7b20a1a37fa108ca503256d0a699c03bbb1"}, + {file = "zopfli-0.2.3.post1.tar.gz", hash = "sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99"}, ] diff --git a/pyproject.toml b/pyproject.toml index bfb95cbfd..1260dd11e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,11 +22,11 @@ dependencies = [ # # IBL packages "iblatlas>=0.5.4", - "ibllib>=2.39.1", + "ibllib>=2.40.1", "iblpybpod @ git+https://github.com/int-brain-lab/iblpybpod.git@no-gui", - "iblutil>=1.13.0", + "iblutil>=1.14.0", "iblqt>=0.2.0", - "ONE-api>=2.9.1", + "ONE-api>=2.11.1", "tycmd-wrapper>=0.2.1", # # Everything else @@ -36,13 +36,14 @@ dependencies = [ "matplotlib>=3.9.2", "numpy>=1.26.4", "packaging>=24.1", - "pandas>=2.2.2", - "pydantic>=2.9.1", + "pandas>=2.2.3", + "pandera>=0.20.4", + "pydantic>=2.9.2", "pyqtgraph>=0.13.7", "python-osc>=1.8.3", "pyusb>=1.2.1", "PyYAML>=6.0.2", - "scipy>=1.14.0", + "scipy>=1.14.1", "sounddevice>=0.5.0", ] [project.optional-dependencies] @@ -84,18 +85,18 @@ dev = [ ] test = [ "pytest>=8.3.2", - "pytest-cov>=5.0.0", - "ruff>=0.6.0", + "pytest-cov>=6.0.0", + "ruff>=0.7.3", ] doc = [ "sphinx>=7.4.7", "sphinx-autobuild>=2024.4.16", - "sphinx-lesson>=0.8.18", + "sphinx-lesson>=0.8.19", "sphinx-simplepdf>=1.6.0", "myst-parser>=4.0.0", ] typing = [ - "mypy>=1.11.1", + "mypy>=1.13.0", "PyQt5-stubs>=5.15.6.0", "types-PyYAML>=6.0.12.20240808", "types-requests>=2.32.0.20240712", From 3c43c888b0f60373bc42ce85c6870a4638b7fc06 Mon Sep 17 00:00:00 2001 From: Olivier Winter Date: Tue, 12 Nov 2024 09:54:06 +0000 Subject: [PATCH 36/43] fix tests --- iblrig/test/test_neurophotometrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/test/test_neurophotometrics.py b/iblrig/test/test_neurophotometrics.py index 29b36f67c..78ce9131d 100644 --- a/iblrig/test/test_neurophotometrics.py +++ b/iblrig/test/test_neurophotometrics.py @@ -19,4 +19,4 @@ def test_neurophotometrics_description(self): 'collection': 'raw_photometry_data', 'fibers': {'G0': {'location': 'SI'}, 'G1': {'location': 'VTA'}}, } - self.assertEqual(dexpected, d) + self.assertEqual(dexpected, d['neurophotometrics']) From e05594ec3936efdf4866b4a29f5ff53902097dce Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Tue, 12 Nov 2024 12:36:01 +0000 Subject: [PATCH 37/43] pin to numpy < 2.0 --- pdm.lock | 56 ++++++++++++++++++++++++-------------------------- pyproject.toml | 2 +- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/pdm.lock b/pdm.lock index 1d7197a65..e6ff918ec 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "ci", "dev", "doc", "project-extraction", "test", "typing"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:c97e968e3767f865a7e85a77876985818811a72c4a8bbe9d81b4d44b06a5c7f8" +content_hash = "sha256:ca343d4cc1ca61beab39d6df14b533795100124a87d61f5935a2edb3de2f5028" [[metadata.targets]] requires_python = "==3.10.*" @@ -364,28 +364,28 @@ files = [ [[package]] name = "contourpy" -version = "1.3.0" -requires_python = ">=3.9" +version = "1.3.1" +requires_python = ">=3.10" summary = "Python library for calculating contours of 2D quadrilateral grids" groups = ["default"] dependencies = [ "numpy>=1.23", ] files = [ - {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, - {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, - {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, - {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, - {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, - {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, - {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, - {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, - {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, - {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, - {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, - {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, - {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, - {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, + {file = "contourpy-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab"}, + {file = "contourpy-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124"}, + {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1"}, + {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b"}, + {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453"}, + {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3"}, + {file = "contourpy-1.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277"}, + {file = "contourpy-1.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595"}, + {file = "contourpy-1.3.1-cp310-cp310-win32.whl", hash = "sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697"}, + {file = "contourpy-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e"}, + {file = "contourpy-1.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6"}, + {file = "contourpy-1.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750"}, + {file = "contourpy-1.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53"}, + {file = "contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699"}, ] [[package]] @@ -1534,22 +1534,20 @@ files = [ [[package]] name = "numpy" -version = "2.0.2" +version = "1.26.4" requires_python = ">=3.9" summary = "Fundamental package for array computing in Python" groups = ["default"] files = [ - {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, - {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, - {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, - {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, - {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, - {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, - {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, - {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 1260dd11e..2890ca58a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "graphviz>=0.20.3", "ipython>=8.26.0", "matplotlib>=3.9.2", - "numpy>=1.26.4", + "numpy<2.0.0", "packaging>=24.1", "pandas>=2.2.3", "pandera>=0.20.4", From 7938783b23f8b94914b886d4698db0120c0a1863 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Tue, 12 Nov 2024 12:47:37 +0000 Subject: [PATCH 38/43] Replace tkinter dialogs with CLI input prompt --- iblrig/base_choice_world.py | 1 - iblrig/base_tasks.py | 16 +++++++------- iblrig/graphic.py | 16 -------------- iblrig/test/test_base_tasks.py | 3 +-- iblrig/tools.py | 40 ++++++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 27 deletions(-) delete mode 100644 iblrig/graphic.py diff --git a/iblrig/base_choice_world.py b/iblrig/base_choice_world.py index 2bfa6c22d..82cc6c475 100644 --- a/iblrig/base_choice_world.py +++ b/iblrig/base_choice_world.py @@ -16,7 +16,6 @@ from pydantic import NonNegativeFloat, NonNegativeInt import iblrig.base_tasks -import iblrig.graphic from iblrig import choiceworld, misc from iblrig.hardware import SOFTCODE from iblrig.pydantic_definitions import TrialDataModel diff --git a/iblrig/base_tasks.py b/iblrig/base_tasks.py index 3582003d1..263844f09 100644 --- a/iblrig/base_tasks.py +++ b/iblrig/base_tasks.py @@ -28,7 +28,6 @@ from pythonosc import udp_client import ibllib.io.session_params as ses_params -import iblrig.graphic as graph import iblrig.path_helper import pybpodapi from ibllib.oneibl.registration import IBLRegistrationClient @@ -39,7 +38,7 @@ from iblrig.hifi import HiFi from iblrig.path_helper import load_pydantic_yaml from iblrig.pydantic_definitions import HardwareSettings, RigSettings, TrialDataModel -from iblrig.tools import call_bonsai +from iblrig.tools import call_bonsai, get_number from iblrig.transfer_experiments import BehaviorCopier, VideoCopier from iblrig.valve import Valve from iblutil.io.net.base import ExpMessage @@ -617,10 +616,10 @@ def run(self): self.create_session() # When not running the first chained protocol, we can skip the weighing dialog first_protocol = int(self.paths.SESSION_RAW_DATA_FOLDER.name.split('_')[-1]) == 0 + + # get subject weight if self.session_info.SUBJECT_WEIGHT is None and self.interactive and first_protocol: - self.session_info.SUBJECT_WEIGHT = graph.numinput( - 'Subject weighing (gr)', f'{self.session_info.SUBJECT_NAME} weight (gr):', nullable=False - ) + self.session_info.SUBJECT_WEIGHT = get_number('Subject weight (g): ', float, lambda x: x > 0) def sigint_handler(*args, **kwargs): # create a signal handler for a graceful exit: create a stop flag in the session folder @@ -637,10 +636,11 @@ def sigint_handler(*args, **kwargs): log.critical('Graceful exit') log.info(f'Session {self.paths.SESSION_RAW_DATA_FOLDER}') self.session_info.SESSION_END_TIME = datetime.datetime.now().isoformat() + + # get poop count if self.interactive and not self.wizard: - self.session_info.POOP_COUNT = graph.numinput( - 'Poop count', f'{self.session_info.SUBJECT_NAME} droppings count:', nullable=True, askint=True - ) + self.session_info.POOP_COUNT = get_number('Droppings count: ', int, lambda x: x >= 0) + self.save_task_parameters_to_json_file() self.register_to_alyx() self._execute_mixins_shared_function('stop_mixin') diff --git a/iblrig/graphic.py b/iblrig/graphic.py deleted file mode 100644 index afc0cfcfa..000000000 --- a/iblrig/graphic.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Popup and string input prompts""" - - -def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): - import tkinter as tk - from tkinter import simpledialog - - root = tk.Tk() - root.withdraw() - ask = simpledialog.askinteger if askint else simpledialog.askfloat - ans = ask(title, prompt, initialvalue=default, minvalue=minval, maxvalue=maxval) - if ans == 0: - return ans - elif not ans and not nullable: - return numinput(title, prompt, default=default, minval=minval, maxval=maxval, nullable=nullable, askint=askint) - return ans diff --git a/iblrig/test/test_base_tasks.py b/iblrig/test/test_base_tasks.py index cc2417273..19f9e82b6 100644 --- a/iblrig/test/test_base_tasks.py +++ b/iblrig/test/test_base_tasks.py @@ -227,12 +227,11 @@ def setUp(self): self.task_kwargs['interactive'] = True self.task_kwargs['task_parameter_file'] = ChoiceWorldSession.base_parameters_file - @mock.patch('iblrig.base_tasks.graph.numinput', side_effect=(23.5, 20, 35)) + @mock.patch('iblrig.base_tasks.get_number', side_effect=(23.5, 20, 35)) def test_dialogs(self, input_mock): """Test that weighing dialog used only on first of chained protocols.""" self.task_kwargs.pop('subject_weight_grams') self.task = EmptyHardwareSession(**self.task_kwargs) - # Check that weighing GUI created self.task.run() input_mock.assert_called() self.assertEqual(23.5, self.task.session_info['SUBJECT_WEIGHT']) diff --git a/iblrig/tools.py b/iblrig/tools.py index 701f33d3c..b00a009c6 100644 --- a/iblrig/tools.py +++ b/iblrig/tools.py @@ -419,3 +419,43 @@ def get_lab_location_dict(hardware_settings: HardwareSettings, iblrig_settings: # TODO: add validation errors/warnings return lab_location + + +def get_number( + prompt: str = 'Enter number: ', + numeric_type: type(int) | type(float) = int, + validation: Callable[[int | float], bool] = lambda _: True, +) -> int | float: + """ + Prompt the user for a number input of a specified numeric type and validate it. + + Parameters + ---------- + prompt : str, optional + The message displayed to the user when asking for input. + Defaults to 'Enter number: '. + numeric_type : type, optional + The type of the number to be returned. Can be either `int` or `float`. + Defaults to `int`. + validation : callable, optional + A function that takes a number as input and returns a boolean + indicating whether the number is valid. Defaults to a function + that always returns True. + + Returns + ------- + int or float + The validated number input by the user, converted to the specified type. + + Notes + ----- + The function will continue to prompt the user until a valid number + is entered that passes the validation function. + """ + value = None + while not isinstance(value, numeric_type) or validation(value) is False: + try: + value = numeric_type(input(prompt).strip()) + except ValueError: + value = None + return value From 55e3dc63f7a46ab1915b44b9734f0bc74eb8cd68 Mon Sep 17 00:00:00 2001 From: Miles Wells Date: Fri, 1 Nov 2024 18:37:18 +0200 Subject: [PATCH 39/43] one.alf.files -> one.alf.path --- iblrig/online_plots.py | 3 +- iblrig/transfer_experiments.py | 2 +- pdm.lock | 122 ++++++++++++++++----------------- pyproject.toml | 2 +- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/iblrig/online_plots.py b/iblrig/online_plots.py index 64296ea2a..7183a2974 100644 --- a/iblrig/online_plots.py +++ b/iblrig/online_plots.py @@ -11,6 +11,7 @@ from pandas.api.types import CategoricalDtype import one.alf.io +import one.alf.path from iblrig.choiceworld import get_subject_training_info from iblrig.misc import online_std from iblrig.raw_data_loaders import load_task_jsonable @@ -50,7 +51,7 @@ class DataModel: time_elapsed = 0.0 def __init__(self, settings_file: Path | None): - self.session_path = one.alf.files.get_session_path(settings_file) or '' + self.session_path = one.alf.path.get_session_path(settings_file) or '' self.last_trials = pd.DataFrame( columns=['correct', 'signed_contrast', 'stim_on', 'play_tone', 'reward_time', 'error_time', 'response_time'], index=np.arange(NTRIALS_PLOT), diff --git a/iblrig/transfer_experiments.py b/iblrig/transfer_experiments.py index c4d3ef266..a908ad223 100644 --- a/iblrig/transfer_experiments.py +++ b/iblrig/transfer_experiments.py @@ -12,7 +12,7 @@ import ibllib.pipes.misc import iblrig -import one.alf.files as alfiles +import one.alf.path as alfiles from ibllib.io import raw_data_loaders, session_params from ibllib.pipes.misc import sleepless from iblrig.raw_data_loaders import load_task_jsonable diff --git a/pdm.lock b/pdm.lock index c3a06439d..207043b71 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "ci", "dev", "doc", "project-extraction", "test", "typing"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:60948b73e6c0cf6b0e4e0fd3ce6557231ad52be77ce8672a875515b803095306" +content_hash = "sha256:3a5034cf2aa96d697c83513a939bfe568e77f33147059f5c4d8a0bf58b397f61" [[metadata.targets]] requires_python = "==3.10.*" @@ -749,8 +749,8 @@ files = [ [[package]] name = "ibl-neuropixel" -version = "1.4.0" -requires_python = ">=3.8" +version = "1.5.0" +requires_python = ">=3.10" summary = "Collection of tools for Neuropixel 1.0 and 2.0 probes data" groups = ["default"] dependencies = [ @@ -764,8 +764,8 @@ dependencies = [ "scipy>=1.11", ] files = [ - {file = "ibl_neuropixel-1.4.0-py3-none-any.whl", hash = "sha256:c5e529662fcf0040078e1746bc90304b80b107b2e91030a3b2d381f3b7b9c84f"}, - {file = "ibl_neuropixel-1.4.0.tar.gz", hash = "sha256:78f46b3174f8e3ed1307ed805673419ea4973d8497152f774c1f582fe891720c"}, + {file = "ibl_neuropixel-1.5.0-py3-none-any.whl", hash = "sha256:5e37a62098802c89088ddad846c1a1f1805341e271ac6be46f8f2a39118ae921"}, + {file = "ibl_neuropixel-1.5.0.tar.gz", hash = "sha256:4c4a5e08dc4a21209a79b0c0044cbab32e0602efe25ec23b2fbf175d2ad44e66"}, ] [[package]] @@ -789,21 +789,21 @@ files = [ [[package]] name = "ibllib" -version = "2.39.1" +version = "2.40.1" requires_python = ">=3.8" summary = "IBL libraries" groups = ["default"] dependencies = [ - "ONE-api~=2.9.rc0", + "ONE-api>=2.10", "boto3", "click>=7.0.0", "colorlog>=4.0.2", "flake8>=3.7.8", "globus-sdk", "graphviz", - "ibl-neuropixel>=1.0.1", + "ibl-neuropixel>=1.5.0", "iblatlas>=0.5.3", - "iblutil>=1.11.0", + "iblutil>=1.13.0", "imagecodecs", "matplotlib>=3.0.3", "mtscomp>=1.0.1", @@ -828,8 +828,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "ibllib-2.39.1-py3-none-any.whl", hash = "sha256:261e7798befb5daed08d70f10918a9739003e38026357875ea2d6dcc912fcc4e"}, - {file = "ibllib-2.39.1.tar.gz", hash = "sha256:79ede021deb02b98810efc0d70b10913db7c53109c4cfe2c18028d5d214a449b"}, + {file = "ibllib-2.40.1-py3-none-any.whl", hash = "sha256:1eab186949395f4a660bad1f20a1e32893ea0cf4d83f90a6d7146e6bc3d31a44"}, + {file = "ibllib-2.40.1.tar.gz", hash = "sha256:8dbb2b70d3bf07b05eeb0b6cc32abd01192fc31fc6fe45832b191e5333eaff58"}, ] [[package]] @@ -871,7 +871,7 @@ files = [ [[package]] name = "iblutil" -version = "1.13.0" +version = "1.14.0" requires_python = ">=3.8" summary = "IBL utilities" groups = ["default"] @@ -885,8 +885,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "iblutil-1.13.0-py3-none-any.whl", hash = "sha256:14a1d3bef30564d633433b3f9dbf8c3ec7c2bb3dfea2d1cd077107f31a986209"}, - {file = "iblutil-1.13.0.tar.gz", hash = "sha256:cc16a1fcc3e82fe2d6425e2b24fc2952e1d49824bfbf6a7a7d7feb502fdae7f1"}, + {file = "iblutil-1.14.0-py3-none-any.whl", hash = "sha256:b402e834a0e719c315b989f538e34b99d9c46430c2c2f5e6606f6951063c938e"}, + {file = "iblutil-1.14.0.tar.gz", hash = "sha256:1b2214d7e1b4b3e47c0d296a2a7181ca98592383648d032eca5d949b538e694c"}, ] [[package]] @@ -1000,7 +1000,7 @@ files = [ [[package]] name = "ipython" -version = "8.28.0" +version = "8.29.0" requires_python = ">=3.10" summary = "IPython: Productive Interactive Computing" groups = ["default", "dev", "doc"] @@ -1018,8 +1018,8 @@ dependencies = [ "typing-extensions>=4.6; python_version < \"3.12\"", ] files = [ - {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, - {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, + {file = "ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8"}, + {file = "ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"}, ] [[package]] @@ -1373,7 +1373,7 @@ files = [ [[package]] name = "mypy" -version = "1.12.0" +version = "1.13.0" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["dev", "typing"] @@ -1383,13 +1383,13 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4397081e620dc4dc18e2f124d5e1d2c288194c2c08df6bdb1db31c38cd1fe1ed"}, - {file = "mypy-1.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:684a9c508a283f324804fea3f0effeb7858eb03f85c4402a967d187f64562469"}, - {file = "mypy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cabe4cda2fa5eca7ac94854c6c37039324baaa428ecbf4de4567279e9810f9e"}, - {file = "mypy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:060a07b10e999ac9e7fa249ce2bdcfa9183ca2b70756f3bce9df7a92f78a3c0a"}, - {file = "mypy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0eff042d7257f39ba4ca06641d110ca7d2ad98c9c1fb52200fe6b1c865d360ff"}, - {file = "mypy-1.12.0-py3-none-any.whl", hash = "sha256:fd313226af375d52e1e36c383f39bf3836e1f192801116b31b090dfcd3ec5266"}, - {file = "mypy-1.12.0.tar.gz", hash = "sha256:65a22d87e757ccd95cbbf6f7e181e6caa87128255eb2b6be901bb71b26d8a99d"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [[package]] @@ -1568,14 +1568,14 @@ files = [ [[package]] name = "one-api" -version = "2.9.1" +version = "2.11.1" requires_python = ">=3.7" summary = "Open Neurophysiology Environment" groups = ["default"] dependencies = [ "boto3", "flake8>=3.7.8", - "iblutil>=1.1.0", + "iblutil>=1.13.0", "numpy>=1.18", "packaging", "pandas>=1.5.0", @@ -1584,8 +1584,8 @@ dependencies = [ "tqdm>=4.32.1", ] files = [ - {file = "ONE_api-2.9.1-py3-none-any.whl", hash = "sha256:d1249e33967edbbd5cc853be2fecc16074fed804418b22940b32b1341fdac36c"}, - {file = "one_api-2.9.1.tar.gz", hash = "sha256:31e8f72a542ab0a1207003dc631a3251a86e12f72c9107d5754b3ba9a5bd33b3"}, + {file = "ONE_api-2.11.1-py3-none-any.whl", hash = "sha256:a5a69d3e6324781f8bd46a3c697a68f6ce286ca25f9c9ffb8175a2747a57aa66"}, + {file = "one_api-2.11.1.tar.gz", hash = "sha256:cb1773f3a06fbf80222d2ea366673a961318951aaf3b640c1fbebbe3ea806a2b"}, ] [[package]] @@ -1618,13 +1618,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" groups = ["default", "ci", "dev", "doc", "test"] files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -1778,10 +1778,10 @@ files = [ [[package]] name = "project-extraction" -version = "0.3.0" +version = "0.4.0" requires_python = "~=3.10" git = "https://github.com/int-brain-lab/project_extraction.git" -revision = "f9b5a45c6a812bf736b6fd5237bfc8d5f3768e2e" +revision = "c3ae3e2e54072e273cb31d16b04cb264a03ee6f4" summary = "Custom extractors for satellite tasks" groups = ["project-extraction"] @@ -2175,17 +2175,17 @@ files = [ [[package]] name = "pytest-cov" -version = "5.0.0" -requires_python = ">=3.8" +version = "6.0.0" +requires_python = ">=3.9" summary = "Pytest plugin for measuring coverage." groups = ["dev", "test"] dependencies = [ - "coverage[toml]>=5.2.1", + "coverage[toml]>=7.5", "pytest>=4.6", ] files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, ] [[package]] @@ -2392,29 +2392,29 @@ files = [ [[package]] name = "ruff" -version = "0.7.0" +version = "0.7.3" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev", "test"] files = [ - {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"}, - {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"}, - {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"}, - {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"}, - {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"}, - {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"}, - {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"}, + {file = "ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344"}, + {file = "ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0"}, + {file = "ruff-0.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67"}, + {file = "ruff-0.7.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2"}, + {file = "ruff-0.7.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16"}, + {file = "ruff-0.7.3-py3-none-win32.whl", hash = "sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc"}, + {file = "ruff-0.7.3-py3-none-win_amd64.whl", hash = "sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088"}, + {file = "ruff-0.7.3-py3-none-win_arm64.whl", hash = "sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c"}, + {file = "ruff-0.7.3.tar.gz", hash = "sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313"}, ] [[package]] @@ -2685,7 +2685,7 @@ files = [ [[package]] name = "sphinx-lesson" -version = "0.8.18" +version = "0.8.19" requires_python = ">=3.3" summary = "Sphinx extension for CodeRefinery lessons" groups = ["dev", "doc"] @@ -2701,8 +2701,8 @@ dependencies = [ "sphinx<8", ] files = [ - {file = "sphinx_lesson-0.8.18-py3-none-any.whl", hash = "sha256:359df9ec81ae5802d35ea7f18b4ef548e0489942ca61d4560392a8e0c0493c89"}, - {file = "sphinx_lesson-0.8.18.tar.gz", hash = "sha256:9cb755befd90e1836dc7798113959e86fe7296048a6d88924076cd8215ab1829"}, + {file = "sphinx_lesson-0.8.19-py3-none-any.whl", hash = "sha256:9f8fe51a61cbcfc3a9b57916abe15dbd4654cb5f0d9d1e7492a37fec27fe95ff"}, + {file = "sphinx_lesson-0.8.19.tar.gz", hash = "sha256:acf1a75fa38c21cd6e479465e17766f64beb482e4c3874fe8415c44e36261029"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index bfbff02cb..9f8dc0fb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ "iblpybpod @ git+https://github.com/int-brain-lab/iblpybpod.git@no-gui", "iblutil>=1.13.0", "iblqt>=0.2.0", - "ONE-api>=2.9.1", + "ONE-api>=2.11.0", "tycmd-wrapper>=0.2.1", # # Everything else From 0095512b4bb1c955e309ca60a4dbd101653c8e73 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 13 Nov 2024 11:37:36 +0000 Subject: [PATCH 40/43] use TimedeltaIndex and drop 'Time' column --- iblrig/raw_data_loaders.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index 4a2cb091d..34e3db162 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -97,7 +97,7 @@ def bpod_session_data_to_dataframe(bpod_data: list[dict[str, Any]], trials: int df['State'] = df['State'].cat.set_categories(categories_state.categories) df['Event'] = df['Event'].cat.set_categories(categories_event.categories) df['Channel'] = df['Channel'].cat.set_categories(categories_channel.categories) - return pd.concat(dataframes, ignore_index=True) + return pd.concat(dataframes) def bpod_trial_data_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> pd.DataFrame: @@ -145,9 +145,13 @@ def bpod_trial_data_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> event_list += [(trial_end - trial_start, 'TrialEnd', pd.NA, pd.NA)] event_list = sorted(event_list) - # create dataframe + # create dataframe with TimedeltaIndex df = pd.DataFrame(data=event_list, columns=['Time', 'Type', 'State', 'Event']) - df['Time'] = pd.to_timedelta(df['Time'] + trial_start, unit='seconds') + df.Time = pd.to_timedelta(df.Time + trial_start, unit='seconds') + df.set_index('Time', inplace=True) + df.rename_axis(index=None, inplace=True) + + # cast types df['Type'] = df['Type'].astype('category') df['State'] = df['State'].astype('category') df['Event'] = df['Event'].astype('category') From 686361eedca4d4d8dda01746eddf026bf42fd93b Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 13 Nov 2024 14:14:36 +0000 Subject: [PATCH 41/43] propagate state-names using ffill --- iblrig/raw_data_loaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index 34e3db162..92f680f31 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -153,7 +153,7 @@ def bpod_trial_data_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> # cast types df['Type'] = df['Type'].astype('category') - df['State'] = df['State'].astype('category') + df['State'] = df['State'].astype('category').ffill() df['Event'] = df['Event'].astype('category') df.insert(2, 'Trial', pd.to_numeric(pd.Series(trial, index=df.index), downcast='unsigned')) From 1b7c8895c5004692fbed04dda73e5d8edaf659d2 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 15 Nov 2024 15:54:45 +0000 Subject: [PATCH 42/43] Merge branch 'online-plots' into iblrigv8dev --- iblrig/raw_data_loaders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iblrig/raw_data_loaders.py b/iblrig/raw_data_loaders.py index 92f680f31..823201bcf 100644 --- a/iblrig/raw_data_loaders.py +++ b/iblrig/raw_data_loaders.py @@ -66,7 +66,7 @@ def bpod_session_data_to_dataframe(bpod_data: list[dict[str, Any]], trials: int * Trial : int index of the trial, zero-based * State : str (categorical) - name of the state (only for types StateStart and StateEnd) + name of the state * Event : str (categorical) name of the event (only for type InputEvent) * Channel : str (categorical) @@ -123,7 +123,7 @@ def bpod_trial_data_to_dataframe(bpod_trial_data: dict[str, Any], trial: int) -> * Trial : int index of the trial, zero-based * State : str (categorical) - name of the state (only for types StateStart and StateEnd) + name of the state * Event : str (categorical) name of the event (only for type InputEvent) * Channel : str (categorical) From 5ad937d05ea256036bb644e275369093b3012d27 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 15 Nov 2024 16:01:25 +0000 Subject: [PATCH 43/43] prepare release --- CHANGELOG.md | 6 ++++++ iblrig/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61b35d1bb..a61f213b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Changelog ========= +8.25.0 +------ +* feature: fiber photometry loader +* feature: dataframe converter for Bpod session data +* removed: remaining tkinter dialogs + 8.24.7 ------ * fix: debiasing not working in trainingCW diff --git a/iblrig/__init__.py b/iblrig/__init__.py index 284995df0..4f2a3a678 100644 --- a/iblrig/__init__.py +++ b/iblrig/__init__.py @@ -6,7 +6,7 @@ # 5) git tag the release in accordance to the version number below (after merge!) # >>> git tag 8.15.6 # >>> git push origin --tags -__version__ = '8.24.7' +__version__ = '8.25.0' from iblrig.version_management import get_detailed_version_string