diff --git a/doc_template/source/conf.py b/doc_template/source/conf.py index 71305d5b..1df279ae 100644 --- a/doc_template/source/conf.py +++ b/doc_template/source/conf.py @@ -1,4 +1,5 @@ """Configuration file for the Sphinx documentation builder.""" + # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html diff --git a/examples/bergamo_session.py b/examples/bergamo_session.py index 8a00178d..ed438b0d 100644 --- a/examples/bergamo_session.py +++ b/examples/bergamo_session.py @@ -1,4 +1,5 @@ """Example of how to use the bergamo session module""" + from datetime import datetime from pathlib import Path diff --git a/src/aind_metadata_mapper/__init__.py b/src/aind_metadata_mapper/__init__.py index 813576a5..b52c5385 100644 --- a/src/aind_metadata_mapper/__init__.py +++ b/src/aind_metadata_mapper/__init__.py @@ -1,2 +1,3 @@ """Init package""" + __version__ = "0.6.0" diff --git a/src/aind_metadata_mapper/bergamo/session.py b/src/aind_metadata_mapper/bergamo/session.py index d9e044d9..1914875a 100644 --- a/src/aind_metadata_mapper/bergamo/session.py +++ b/src/aind_metadata_mapper/bergamo/session.py @@ -18,9 +18,9 @@ LaserConfig, Modality, Session, - Stream, StimulusEpoch, - StimulusModality + StimulusModality, + Stream, ) from aind_data_schema.models.stimulus import ( PhotoStimulation, @@ -466,87 +466,90 @@ def _transform(self, extracted_source: RawImageInfo) -> Session: stimulus_modalities=[ StimulusModality.OPTOGENETICS, ], - stimulus_parameters=[PhotoStimulation( - stimulus_name="PhotoStimulation", - number_groups=( - self.job_settings.num_of_photo_stim_groups - ), - groups=[ - PhotoStimulationGroup( - group_index=( - self.job_settings.photo_stim_groups[0][ - "group_index" - ] - ), - number_of_neurons=int( - np.array( + stimulus_parameters=[ + PhotoStimulation( + stimulus_name="PhotoStimulation", + number_groups=( + self.job_settings.num_of_photo_stim_groups + ), + groups=[ + PhotoStimulationGroup( + group_index=( + self.job_settings.photo_stim_groups[0][ + "group_index" + ] + ), + number_of_neurons=int( + np.array( + photostim_groups[0]["rois"][1][ + "scanfields" + ]["slmPattern"] + ).shape[0] + ), + stimulation_laser_power=int( photostim_groups[0]["rois"][1][ "scanfields" - ]["slmPattern"] - ).shape[0] - ), - stimulation_laser_power=int( - photostim_groups[0]["rois"][1][ - "scanfields" - ]["powers"] - ), - number_trials=( - self.job_settings.photo_stim_groups[0][ - "number_trials" - ] - ), - number_spirals=int( - photostim_groups[0]["rois"][1][ - "scanfields" - ]["repetitions"] - ), - spiral_duration=photostim_groups[0]["rois"][1][ - "scanfields" - ]["duration"], - inter_spiral_interval=photostim_groups[0][ - "rois" - ][2]["scanfields"]["duration"], - ), - PhotoStimulationGroup( - group_index=( - self.job_settings.photo_stim_groups[1][ - "group_index" - ] - ), - number_of_neurons=int( - np.array( + ]["powers"] + ), + number_trials=( + self.job_settings.photo_stim_groups[0][ + "number_trials" + ] + ), + number_spirals=int( photostim_groups[0]["rois"][1][ "scanfields" - ]["slmPattern"] - ).shape[0] - ), - stimulation_laser_power=int( - photostim_groups[0]["rois"][1][ - "scanfields" - ]["powers"] + ]["repetitions"] + ), + spiral_duration=photostim_groups[0][ + "rois" + ][1]["scanfields"]["duration"], + inter_spiral_interval=photostim_groups[0][ + "rois" + ][2]["scanfields"]["duration"], ), - number_trials=( - self.job_settings.photo_stim_groups[1][ - "number_trials" - ] - ), - number_spirals=int( - photostim_groups[0]["rois"][1][ - "scanfields" - ]["repetitions"] + PhotoStimulationGroup( + group_index=( + self.job_settings.photo_stim_groups[1][ + "group_index" + ] + ), + number_of_neurons=int( + np.array( + photostim_groups[0]["rois"][1][ + "scanfields" + ]["slmPattern"] + ).shape[0] + ), + stimulation_laser_power=int( + photostim_groups[0]["rois"][1][ + "scanfields" + ]["powers"] + ), + number_trials=( + self.job_settings.photo_stim_groups[1][ + "number_trials" + ] + ), + number_spirals=int( + photostim_groups[0]["rois"][1][ + "scanfields" + ]["repetitions"] + ), + spiral_duration=photostim_groups[0][ + "rois" + ][1]["scanfields"]["duration"], + inter_spiral_interval=photostim_groups[0][ + "rois" + ][2]["scanfields"]["duration"], ), - spiral_duration=photostim_groups[0]["rois"][1][ - "scanfields" - ]["duration"], - inter_spiral_interval=photostim_groups[0][ - "rois" - ][2]["scanfields"]["duration"], + ], + inter_trial_interval=( + self.job_settings. + photo_stim_inter_trial_interval ), - ], - inter_trial_interval=( - self.job_settings.photo_stim_inter_trial_interval - ), - )], + ) + ], stimulus_start_time=( self.job_settings.stimulus_start_time ), diff --git a/src/aind_metadata_mapper/fib/session.py b/src/aind_metadata_mapper/fib/session.py index 7ca9ac25..c413af1d 100644 --- a/src/aind_metadata_mapper/fib/session.py +++ b/src/aind_metadata_mapper/fib/session.py @@ -11,15 +11,12 @@ FiberConnectionConfig, LightEmittingDiodeConfig, Session, - Stream, StimulusEpoch, StimulusModality, + Stream, ) from aind_data_schema.models.modalities import Modality -from aind_data_schema.models.stimulus import ( - OptoStimulation, - PulseShape, -) +from aind_data_schema.models.stimulus import OptoStimulation, PulseShape from pydantic import Field from pydantic_settings import BaseSettings @@ -149,10 +146,18 @@ def _transform(self, extracted_source: ParsedMetadata) -> Session: opto_stim = OptoStimulation( stimulus_name=stimulus_name, pulse_shape=PulseShape.SQUARE, - pulse_frequency=[frequency,], - number_pulse_trains=[trial_num, ], - pulse_width=[pulse_width, ], - pulse_train_duration=[opto_duration, ], + pulse_frequency=[ + frequency, + ], + number_pulse_trains=[ + trial_num, + ], + pulse_width=[ + pulse_width, + ], + pulse_train_duration=[ + opto_duration, + ], pulse_train_interval=opto_interval, baseline_duration=opto_base, fixed_pulse_train_interval=True, # TODO: Check this is right @@ -168,7 +173,9 @@ def _transform(self, extracted_source: ParsedMetadata) -> Session: stimulus_epochs = StimulusEpoch( stimulus_name=stimulus_name, stimulus_modalities=[StimulusModality.OPTOGENETICS], - stimulus_parameters=[opto_stim, ], + stimulus_parameters=[ + opto_stim, + ], stimulus_start_time=session_start_time, stimulus_end_time=end_datetime, ) diff --git a/src/aind_metadata_mapper/mesoscope/session.py b/src/aind_metadata_mapper/mesoscope/session.py index 7ebd0fbe..b4eac941 100644 --- a/src/aind_metadata_mapper/mesoscope/session.py +++ b/src/aind_metadata_mapper/mesoscope/session.py @@ -1,4 +1,5 @@ """Mesoscope ETL""" + import argparse import json import sys diff --git a/src/aind_metadata_mapper/neuropixels/dynamic_routing_task.py b/src/aind_metadata_mapper/neuropixels/dynamic_routing_task.py index 91a2b67d..3c6c0cfb 100644 --- a/src/aind_metadata_mapper/neuropixels/dynamic_routing_task.py +++ b/src/aind_metadata_mapper/neuropixels/dynamic_routing_task.py @@ -1,19 +1,20 @@ """ETL for the dynamic routing task.""" -import typing -import logging + import datetime -import numpy as np +import logging import pathlib +import typing + +import numpy as np from aind_data_schema.core import rig # type: ignore from aind_data_schema.models import devices # type: ignore -from . import neuropixels_rig, utils +from . import neuropixels_rig, utils logger = logging.getLogger(__name__) class ExtractContext(neuropixels_rig.NeuropixelsRigContext): - """Extract context for DynamicRoutingTaskRigEtl.""" version: typing.Optional[str] @@ -33,15 +34,16 @@ class ExtractContext(neuropixels_rig.NeuropixelsRigContext): # dynamic routing task has two slashes before commit hash SUPPORTED_VERSIONS = [ - (b'https://raw.githubusercontent.com/samgale/DynamicRoutingTask' - b'//9ea009a6c787c0049648ab9a93eb8d9df46d3f7b/DynamicRouting1.py'), + ( + b"https://raw.githubusercontent.com/samgale/DynamicRoutingTask" + b"//9ea009a6c787c0049648ab9a93eb8d9df46d3f7b/DynamicRouting1.py" + ), ] class DynamicRoutingTaskRigEtl(neuropixels_rig.NeuropixelsRigEtl): - """DynamicRouting rig ETL class. Extracts information from task output - file. + file. """ def __init__( @@ -80,33 +82,39 @@ def _extract(self) -> ExtractContext: version=utils.extract_hdf5_value(task, ["githubTaskScript"]), reward_line=utils.extract_hdf5_value(task, ["rewardLine"]), reward_sound_line=utils.extract_hdf5_value( - task, ["rewardSoundLine"]), + task, ["rewardSoundLine"] + ), lick_line=utils.extract_hdf5_value(task, ["lickLine"]), frame_signal_line=utils.extract_hdf5_value( - task, ["frameSignalLine"]), + task, ["frameSignalLine"] + ), acquisition_signal_line=utils.extract_hdf5_value( - task, ["acquisitionSignalLine"]), + task, ["acquisitionSignalLine"] + ), opto_channels=utils.extract_hdf5_value(task, ["optoChannels"]), galvo_channels=utils.extract_hdf5_value(task, ["galvoChannels"]), monitor_distance=utils.extract_hdf5_value(task, ["monDistance"]), monitor_size=utils.extract_hdf5_value(task, ["monSizePix"]), wheel_radius=utils.extract_hdf5_value(task, ["wheelRadius"]), sound_calibration_fit=utils.extract_hdf5_value( - task, ["soundCalibrationFit"]), + task, ["soundCalibrationFit"] + ), solenoid_open_time=utils.extract_hdf5_value( - task, ["solenoidOpenTime"]), + task, ["solenoidOpenTime"] + ), ) def _transform_behavior_daq( - self, - extracted_source: ExtractContext + self, extracted_source: ExtractContext ) -> None: """Updates rig model with DynamicRouting-related behavior daq - information.""" + information.""" behavior_daq_channels = [] if extracted_source.reward_line is not None: - logger.debug("Extracted reward line port, channel: %s" % - self.behavior_daq_name) + logger.debug( + "Extracted reward line port, channel: %s" + % self.behavior_daq_name + ) behavior_daq_channels.append( devices.DAQChannel( device_name=self.behavior_daq_name, @@ -119,8 +127,9 @@ def _transform_behavior_daq( if extracted_source.reward_sound_line is not None: logger.debug( - "Extracted reward sound line port, channel: %s, %s" % - extracted_source.reward_sound_line) + "Extracted reward sound line port, channel: %s, %s" + % extracted_source.reward_sound_line + ) behavior_daq_channels.append( devices.DAQChannel( device_name=self.behavior_daq_name, @@ -133,8 +142,9 @@ def _transform_behavior_daq( if extracted_source.lick_line is not None: logger.debug( - "Extracted lick line on port, channel: %s, %s" % - extracted_source.lick_line) + "Extracted lick line on port, channel: %s, %s" + % extracted_source.lick_line + ) behavior_daq_channels.append( devices.DAQChannel( device_name=self.behavior_daq_name, @@ -152,16 +162,16 @@ def _transform_behavior_daq( daq.channels.extend(behavior_daq_channels) def _transform_behavior_sync_daq( - self, - extracted_source: ExtractContext + self, extracted_source: ExtractContext ) -> None: """Updates rig model with DynamicRouting-related behavior sync daq - information.""" + information.""" behavior_sync_daq_channels = [] if extracted_source.frame_signal_line is not None: logger.debug( - "Extracted frame signal port, channel: %s, %s" % - extracted_source.frame_signal_line) + "Extracted frame signal port, channel: %s, %s" + % extracted_source.frame_signal_line + ) behavior_sync_daq_channels.append( devices.DAQChannel( device_name=self.behavior_sync_daq_name, @@ -174,8 +184,9 @@ def _transform_behavior_sync_daq( if extracted_source.acquisition_signal_line is not None: logger.debug( - "Extracted aquisition port, channel: %s, %s" % - extracted_source.acquisition_signal_line) + "Extracted aquisition port, channel: %s, %s" + % extracted_source.acquisition_signal_line + ) behavior_sync_daq_channels.append( devices.DAQChannel( device_name=self.behavior_sync_daq_name, @@ -198,10 +209,12 @@ def _transform_opto_daq(self, extracted_source: ExtractContext) -> None: opto_daq_channels = [] if extracted_source.opto_channels is not None: logger.debug( - "Extracted opto channels: %s" % extracted_source.opto_channels) + "Extracted opto channels: %s" % extracted_source.opto_channels + ) if extracted_source.opto_channels: channels = [ - ch for dev in extracted_source.opto_channels + ch + for dev in extracted_source.opto_channels for ch in extracted_source.opto_channels[dev] if not np.isnan(ch) ] @@ -218,25 +231,27 @@ def _transform_opto_daq(self, extracted_source: ExtractContext) -> None: if extracted_source.galvo_channels is not None: logger.debug( - "Extracted galvo channels x,y: %s, %s" % - extracted_source.galvo_channels + "Extracted galvo channels x,y: %s, %s" + % extracted_source.galvo_channels + ) + opto_daq_channels.extend( + [ + devices.DAQChannel( + device_name=self.opto_daq_name, + channel_name=f"{self.opto_daq_name} galvo x", + channel_type=devices.DaqChannelType.AO, + port=0, + channel_index=extracted_source.galvo_channels[0], + ), + devices.DAQChannel( + device_name=self.opto_daq_name, + channel_name=f"{self.opto_daq_name} galvo y", + channel_type=devices.DaqChannelType.AO, + port=0, + channel_index=extracted_source.galvo_channels[1], + ), + ] ) - opto_daq_channels.extend([ - devices.DAQChannel( - device_name=self.opto_daq_name, - channel_name=f"{self.opto_daq_name} galvo x", - channel_type=devices.DaqChannelType.AO, - port=0, - channel_index=extracted_source.galvo_channels[0], - ), - devices.DAQChannel( - device_name=self.opto_daq_name, - channel_name=f"{self.opto_daq_name} galvo y", - channel_type=devices.DaqChannelType.AO, - port=0, - channel_index=extracted_source.galvo_channels[1], - ), - ]) if opto_daq_channels: logger.debug("Updating daq=%s." % self.opto_daq_name) @@ -245,11 +260,10 @@ def _transform_opto_daq(self, extracted_source: ExtractContext) -> None: daq.channels.extend(opto_daq_channels) def _transform_calibrations( - self, - extracted_source: ExtractContext + self, extracted_source: ExtractContext ) -> rig.Rig: """Updates rig model with DynamicRouting-related calibration - information.""" + information.""" default_calibration_date = datetime.datetime.now() # sound @@ -261,8 +275,8 @@ def _transform_calibrations( ("device_name", self.speaker_name), ], devices.Calibration( - calibration_date=self.sound_calibration_date or - default_calibration_date, + calibration_date=self.sound_calibration_date + or default_calibration_date, device_name=self.speaker_name, input={ "a": extracted_source.sound_calibration_fit[0], @@ -274,9 +288,7 @@ def _transform_calibrations( "sound_volume = log(1 - ((dB - c) / a)) / b;" "dB is sound pressure" ), - notes=( - "Calibration date is a placeholder. " - ), + notes=("Calibration date is a placeholder. "), ), ) @@ -289,27 +301,23 @@ def _transform_calibrations( ("device_name", self.reward_delivery_name), ], devices.Calibration( - calibration_date=self.reward_calibration_date or - default_calibration_date, + calibration_date=self.reward_calibration_date + or default_calibration_date, device_name=self.reward_delivery_name, input={}, output={ - "solenoid_open_time": - extracted_source.solenoid_open_time, + "solenoid_open_time": extracted_source. + solenoid_open_time, }, description=( "solenoid open time (ms) = slope * expected water " "volume (mL) + intercept" ), - notes=( - "Calibration date is a placeholder." - ), + notes=("Calibration date is a placeholder."), ), ) - def _transform( - self, - extracted_source: ExtractContext) -> rig.Rig: + def _transform(self, extracted_source: ExtractContext) -> rig.Rig: """Updates rig model with DynamicRouting-related task information.""" if extracted_source.version is not None: if extracted_source.version not in SUPPORTED_VERSIONS: @@ -318,15 +326,21 @@ def _transform( ) # monitor information - if extracted_source.monitor_distance is not None or \ - extracted_source.monitor_size is not None: - for idx, device in \ - enumerate(extracted_source.current.stimulus_devices): - if device.name == self.monitor_name and \ - device.device_type == "Monitor": + if ( + extracted_source.monitor_distance is not None + or extracted_source.monitor_size is not None + ): + for idx, device in enumerate( + extracted_source.current.stimulus_devices + ): + if ( + device.name == self.monitor_name + and device.device_type == "Monitor" + ): if extracted_source.monitor_distance is not None: - device.viewing_distance = \ - float(extracted_source.monitor_distance) + device.viewing_distance = float( + extracted_source.monitor_distance + ) device.viewing_distance_unit = devices.SizeUnit.CM if extracted_source.monitor_size is not None: @@ -336,23 +350,25 @@ def _transform( device.height = int(height) device.size_unit = devices.SizeUnit.PX - extracted_source.current.stimulus_devices[idx] = \ - devices.Monitor.model_validate( - device.__dict__ - ) + extracted_source.current.stimulus_devices[idx] = ( + devices.Monitor.model_validate(device.__dict__) + ) break # wheel info if extracted_source.wheel_radius is not None: logger.debug("Updating wheel information") - extracted_source.current.mouse_platform.radius = \ + extracted_source.current.mouse_platform.radius = ( extracted_source.wheel_radius - extracted_source.current.mouse_platform.radius_unit = \ + ) + extracted_source.current.mouse_platform.radius_unit = ( devices.SizeUnit.CM - extracted_source.current.mouse_platform = \ + ) + extracted_source.current.mouse_platform = ( devices.Disc.model_validate( extracted_source.current.mouse_platform.__dict__ ) + ) # daqs self._transform_behavior_daq(extracted_source) self._transform_behavior_sync_daq(extracted_source) diff --git a/src/aind_metadata_mapper/neuropixels/mvr_rig.py b/src/aind_metadata_mapper/neuropixels/mvr_rig.py index 8cb6711f..c7877de1 100644 --- a/src/aind_metadata_mapper/neuropixels/mvr_rig.py +++ b/src/aind_metadata_mapper/neuropixels/mvr_rig.py @@ -1,23 +1,23 @@ """ETL for the MVR config.""" + import logging import pathlib + from aind_data_schema.core import rig # type: ignore from aind_data_schema.models import devices # type: ignore -from . import neuropixels_rig, utils +from . import neuropixels_rig, utils logger = logging.getLogger(__name__) class ExtractContext(neuropixels_rig.NeuropixelsRigContext): - """Extract context for MVR rig etl.""" serial_numbers: list[tuple[str, str]] class MvrRigEtl(neuropixels_rig.NeuropixelsRigEtl): - """MVR rig ETL class. Extracts information from MVR-related config file.""" def __init__( @@ -26,7 +26,7 @@ def __init__( output_directory: pathlib.Path, mvr_config_source: pathlib.Path, mvr_mapping: dict[str, str], - **kwargs + **kwargs, ): """Class constructor for MVR rig etl class.""" super().__init__(input_source, output_directory, **kwargs) @@ -42,8 +42,7 @@ def _extract(self) -> ExtractContext: mvr_camera_config = mvr_config[mvr_name] except KeyError: logger.debug( - "No camera found for: %s in mvr config." % - mvr_name + "No camera found for: %s in mvr config." % mvr_name ) continue serial_numbers.append( @@ -57,15 +56,16 @@ def _extract(self) -> ExtractContext: serial_numbers=serial_numbers, ) - def _transform( - self, - extracted_source: ExtractContext) -> rig.Rig: + def _transform(self, extracted_source: ExtractContext) -> rig.Rig: """Updates rig model with MVR-related camera information.""" for assembly_name, serial_number in extracted_source.serial_numbers: utils.find_update( extracted_source.current.cameras, filters=[ - ("name", assembly_name, ), + ( + "name", + assembly_name, + ), ], setter=( lambda item, name, value: setattr(item.camera, name, value) @@ -74,7 +74,7 @@ def _transform( recording_software=devices.Software( name="MVR", version="Not detected/provided.", - ) + ), ) return super()._transform(extracted_source.current) diff --git a/src/aind_metadata_mapper/neuropixels/neuropixels_rig.py b/src/aind_metadata_mapper/neuropixels/neuropixels_rig.py index a939060e..c1a962a9 100644 --- a/src/aind_metadata_mapper/neuropixels/neuropixels_rig.py +++ b/src/aind_metadata_mapper/neuropixels/neuropixels_rig.py @@ -1,17 +1,17 @@ """Base ETL class for neuropixels rigs.""" + +import logging import pathlib + import pydantic -import logging from aind_data_schema.core import rig # type: ignore from ..core import BaseEtl - logger = logging.getLogger(__name__) class NeuropixelsRigContext(pydantic.BaseModel): - """Base context for neuropixels rig etl.""" current: rig.Rig @@ -40,8 +40,7 @@ def __init__( self.output_directory = output_directory def _extract(self) -> rig.Rig: - """Extracts rig-related information from config files. - """ + """Extracts rig-related information from config files.""" return rig.Rig.model_validate_json( self.input_source.read_text(), ) diff --git a/src/aind_metadata_mapper/neuropixels/open_ephys_rig.py b/src/aind_metadata_mapper/neuropixels/open_ephys_rig.py index d3205752..eaf7f988 100644 --- a/src/aind_metadata_mapper/neuropixels/open_ephys_rig.py +++ b/src/aind_metadata_mapper/neuropixels/open_ephys_rig.py @@ -1,19 +1,19 @@ """ETL for the Open Ephys config.""" -import typing + import logging import pathlib -import pydantic +import typing from xml.etree import ElementTree + +import pydantic from aind_data_schema.core import rig # type: ignore from . import neuropixels_rig, utils - logger = logging.getLogger(__name__) class ExtractedProbe(pydantic.BaseModel): - """Extracted probe information.""" name: typing.Optional[str] @@ -22,7 +22,6 @@ class ExtractedProbe(pydantic.BaseModel): class ExtractContext(neuropixels_rig.NeuropixelsRigContext): - """Extract context for Open Ephys rig etl.""" probes: list[ExtractedProbe] @@ -30,9 +29,8 @@ class ExtractContext(neuropixels_rig.NeuropixelsRigContext): class OpenEphysRigEtl(neuropixels_rig.NeuropixelsRigEtl): - """Open Ephys rig ETL class. Extracts information from Open Ephys-related - config files.""" + config files.""" def __init__( self, @@ -40,13 +38,14 @@ def __init__( output_directory: pathlib.Path, open_ephys_settings_sources: list[pathlib.Path], probe_manipulator_serial_numbers: list[tuple[str, str]] = [], - **kwargs + **kwargs, ): """Class constructor for Open Ephys rig etl class.""" super().__init__(input_source, output_directory, **kwargs) self.open_ephys_settings_sources = open_ephys_settings_sources - self.probe_manipulator_serial_numbers = \ + self.probe_manipulator_serial_numbers = ( probe_manipulator_serial_numbers + ) def _extract(self) -> ExtractContext: """Extracts Open Ephys-related probe information from config files.""" @@ -56,26 +55,27 @@ def _extract(self) -> ExtractContext: for source in self.open_ephys_settings_sources: parsed = utils.load_xml(source) versions.append(self._extract_version(parsed)) - probes.extend(self._extract_probes( - current, - parsed, - )) + probes.extend( + self._extract_probes( + current, + parsed, + ) + ) return ExtractContext( current=current, probes=probes, versions=versions, ) - def _extract_version(self, settings: ElementTree.Element) -> \ - typing.Union[str, None]: + def _extract_version( + self, settings: ElementTree.Element + ) -> typing.Union[str, None]: """Extracts the version from the Open Ephys settings file.""" version_elements = utils.find_elements(settings, "version") return next(version_elements).text def _extract_probes( - self, - current: rig.Rig, - settings: ElementTree.Element + self, current: rig.Rig, settings: ElementTree.Element ) -> list[ExtractedProbe]: """Extracts probe serial numbers from Open Ephys settings file. If extracted probe names do not match the rig, attempt to infer them from @@ -100,15 +100,17 @@ def _extract_probes( if not all(name in rig_probe_names for name in extracted_probe_names): logger.warning( "Mismatched probe names in open ephys settings. Attempting to " - "infer probe names. extracted: %s, rig: %s" % ( - extracted_probe_names, rig_probe_names) + "infer probe names. extracted: %s, rig: %s" + % (extracted_probe_names, rig_probe_names) ) if len(extracted_probe_names) != len(rig_probe_names): logger.warning( - "Probe count mismatch. Skipping probe inference.") + "Probe count mismatch. Skipping probe inference." + ) return [] - for extracted_probe, rig_probe_name in \ - zip(extracted_probes, rig_probe_names): + for extracted_probe, rig_probe_name in zip( + extracted_probes, rig_probe_names + ): extracted_probe.name = rig_probe_name return extracted_probes @@ -119,16 +121,19 @@ def _transform( ) -> rig.Rig: """Updates rig model with Open Ephys-related probe information.""" # update manipulator serial numbers - for ephys_assembly_name, serial_number in \ - self.probe_manipulator_serial_numbers: + for ( + ephys_assembly_name, + serial_number, + ) in self.probe_manipulator_serial_numbers: utils.find_update( extracted_source.current.ephys_assemblies, [ ("name", ephys_assembly_name), ], setter=( - lambda item, name, value: - setattr(item.manipulator, name, value) + lambda item, name, value: setattr( + item.manipulator, name, value + ) ), serial_number=serial_number, ) diff --git a/src/aind_metadata_mapper/neuropixels/sync_rig.py b/src/aind_metadata_mapper/neuropixels/sync_rig.py index 3963a32d..732880b4 100644 --- a/src/aind_metadata_mapper/neuropixels/sync_rig.py +++ b/src/aind_metadata_mapper/neuropixels/sync_rig.py @@ -1,5 +1,7 @@ """ETL for the Sync config.""" + import pathlib + import pydantic from aind_data_schema.core import rig # type: ignore from aind_data_schema.models import devices # type: ignore @@ -8,7 +10,6 @@ class SyncChannel(pydantic.BaseModel): - """Extracted Sync daq channel information.""" channel_name: str @@ -17,14 +18,12 @@ class SyncChannel(pydantic.BaseModel): class ExtractContext(neuropixels_rig.NeuropixelsRigContext): - """Extract context for Sync rig etl.""" channels: list[SyncChannel] class SyncRigEtl(neuropixels_rig.NeuropixelsRigEtl): - """Sync rig ETL class. Extracts information from Sync-related config file. """ @@ -34,7 +33,7 @@ def __init__( output_directory: pathlib.Path, config_source: pathlib.Path, sync_daq_name: str = "Sync", - **kwargs + **kwargs, ): """Class constructor for Sync rig etl class.""" super().__init__(input_source, output_directory, **kwargs) @@ -51,8 +50,7 @@ def _extract(self) -> ExtractContext: channel_index=line, sample_rate=sample_rate, ) - for line, name in - config["line_labels"].items() + for line, name in config["line_labels"].items() ] return ExtractContext( @@ -60,9 +58,7 @@ def _extract(self) -> ExtractContext: channels=channels, ) - def _transform( - self, - extracted_source: ExtractContext) -> rig.Rig: + def _transform(self, extracted_source: ExtractContext) -> rig.Rig: """Updates rig model with Sync-related daq information.""" utils.find_update( extracted_source.current.daqs, @@ -80,7 +76,7 @@ def _transform( sample_rate_unit="hertz", ) for sync_channel in extracted_source.channels - ] + ], ) return super()._transform(extracted_source.current) diff --git a/src/aind_metadata_mapper/neuropixels/utils.py b/src/aind_metadata_mapper/neuropixels/utils.py index 98647ce7..4f55f850 100644 --- a/src/aind_metadata_mapper/neuropixels/utils.py +++ b/src/aind_metadata_mapper/neuropixels/utils.py @@ -1,18 +1,20 @@ """Shared utilities""" + +import configparser import logging -import typing import pathlib -import configparser -import h5py # type: ignore -import yaml # type: ignore +import typing from xml.etree import ElementTree +import h5py # type: ignore +import yaml # type: ignore logger = logging.getLogger(__name__) -def find_elements(et: ElementTree.Element, name: str) -> \ - typing.Generator[ElementTree.Element, None, None]: +def find_elements( + et: ElementTree.Element, name: str +) -> typing.Generator[ElementTree.Element, None, None]: """Find elements in an ElementTree.Element that match a name. Notes @@ -47,11 +49,12 @@ def load_hdf5(h5_path: pathlib.Path) -> h5py.File: return h5py.File(h5_path, "r") -def extract_hdf5_value(h5_file: h5py.File, path: list[str]) -> \ - typing.Union[typing.Any, None]: +def extract_hdf5_value( + h5_file: h5py.File, path: list[str] +) -> typing.Union[typing.Any, None]: """Extract value from hdf5 file using a path. Path is a list of property - names that are used to traverse the hdf5 file. A path of length greater - than 1 is expected to point to a nested property. + names that are used to traverse the hdf5 file. A path of length greater + than 1 is expected to point to a nested property. """ try: value = None @@ -81,10 +84,12 @@ def find_update( - Filters are property name, property value pairs. """ for item in items: - if all([ - getattr(item, prop_name, None) == prop_value - for prop_name, prop_value in filters - ]): + if all( + [ + getattr(item, prop_name, None) == prop_value + for prop_name, prop_value in filters + ] + ): for prop_name, prop_value in updates.items(): setter(item, prop_name, prop_value) return item @@ -96,16 +101,18 @@ def find_update( def find_replace_or_append( iterable: list[typing.Any], filters: list[typing.Tuple[str, typing.Any]], - update: typing.Any + update: typing.Any, ): """Find an item in a list of items that matches the filters and replace it. - If no item is found, append. + If no item is found, append. """ for idx, obj in enumerate(iterable): - if all([ - getattr(obj, prop_name, None) == prop_value - for prop_name, prop_value in filters - ]): + if all( + [ + getattr(obj, prop_name, None) == prop_value + for prop_name, prop_value in filters + ] + ): iterable[idx] = update break else: diff --git a/tests/test_legacy_core.py b/tests/test_legacy_core.py index d582f42f..7602b003 100644 --- a/tests/test_legacy_core.py +++ b/tests/test_legacy_core.py @@ -1,5 +1,6 @@ """Tests legacy BaseEtl class methods. We can remove this once the other jobs are ported over.""" + from datetime import datetime from pathlib import Path from typing import Any diff --git a/tests/test_mesoscope.py b/tests/test_mesoscope.py index 69c979bf..c4a565ec 100644 --- a/tests/test_mesoscope.py +++ b/tests/test_mesoscope.py @@ -168,15 +168,15 @@ def test_transform(self, mock_open, mock_scanimage) -> None: # mock scanimage metadata mock_meta = [{}] - mock_meta[0][ - "SI.hRoiManager.linesPerFrame" - ] = self.example_scanimage_meta["lines_per_frame"] - mock_meta[0][ - "SI.hRoiManager.pixelsPerLine" - ] = self.example_scanimage_meta["pixels_per_line"] - mock_meta[0][ - "SI.hRoiManager.scanZoomFactor" - ] = self.example_scanimage_meta["fov_scale_factor"] + mock_meta[0]["SI.hRoiManager.linesPerFrame"] = ( + self.example_scanimage_meta["lines_per_frame"] + ) + mock_meta[0]["SI.hRoiManager.pixelsPerLine"] = ( + self.example_scanimage_meta["pixels_per_line"] + ) + mock_meta[0]["SI.hRoiManager.scanZoomFactor"] = ( + self.example_scanimage_meta["fov_scale_factor"] + ) mock_scanimage.return_value = mock_meta extract = etl._extract() diff --git a/tests/test_neuropixels/test_dynamic_routing_task_rig_supported.py b/tests/test_neuropixels/test_dynamic_routing_task_rig_supported.py index 61750006..566367f0 100644 --- a/tests/test_neuropixels/test_dynamic_routing_task_rig_supported.py +++ b/tests/test_neuropixels/test_dynamic_routing_task_rig_supported.py @@ -1,12 +1,12 @@ """Tests for neuropixels dynamic routing task rig ETL.""" -import unittest + import pathlib +import unittest from aind_metadata_mapper.neuropixels import ( # type: ignore - dynamic_routing_task + dynamic_routing_task, ) - from . import utils as test_utils @@ -49,19 +49,21 @@ def test_etl_supported(self): assert self.load_updated() == self.expected def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, self.load_updated, \ - self._cleanup = \ - test_utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/" - "dynamic-routing-task-rig.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = test_utils.setup_neuropixels_etl_dirs( + pathlib.Path( + "./tests/resources/neuropixels/" + "dynamic-routing-task-rig.json" + ), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_dynamic_routing_task_rig_unsupported.py b/tests/test_neuropixels/test_dynamic_routing_task_rig_unsupported.py index bbe18f43..e08339d4 100644 --- a/tests/test_neuropixels/test_dynamic_routing_task_rig_unsupported.py +++ b/tests/test_neuropixels/test_dynamic_routing_task_rig_unsupported.py @@ -1,9 +1,11 @@ """Tests for neuropixels dynamic routing task rig ETL. Uses an unsupported version of the dynamic routing task output file.""" -import unittest + import pathlib +import unittest + from aind_metadata_mapper.neuropixels import ( # type: ignore - dynamic_routing_task + dynamic_routing_task, ) from . import utils as test_utils @@ -37,19 +39,21 @@ def test_etl_unsupported(self): assert self.load_updated() == self.expected def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, self.load_updated, \ - self._cleanup = \ - test_utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/" - "dynamic-routing-task-rig-unsupported.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = test_utils.setup_neuropixels_etl_dirs( + pathlib.Path( + "./tests/resources/neuropixels/" + "dynamic-routing-task-rig-unsupported.json" + ), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_mvr_rig.py b/tests/test_neuropixels/test_mvr_rig.py index fb036df0..666e3d75 100644 --- a/tests/test_neuropixels/test_mvr_rig.py +++ b/tests/test_neuropixels/test_mvr_rig.py @@ -1,6 +1,7 @@ """Tests for the MVR rig ETL.""" -import unittest + import pathlib +import unittest from aind_metadata_mapper.neuropixels import mvr_rig # type: ignore @@ -45,18 +46,18 @@ def test_etl_bad_mapping(self): etl.run_job() def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, self.load_updated, \ - self._cleanup = \ - test_utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/mvr-rig.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = test_utils.setup_neuropixels_etl_dirs( + pathlib.Path("./tests/resources/neuropixels/mvr-rig.json"), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_open_ephys_rig.py b/tests/test_neuropixels/test_open_ephys_rig.py index 7bdc91e3..4ad34176 100644 --- a/tests/test_neuropixels/test_open_ephys_rig.py +++ b/tests/test_neuropixels/test_open_ephys_rig.py @@ -1,6 +1,7 @@ """Tests for the neuropixels open ephys rig ETL.""" -import unittest + import pathlib +import unittest from aind_metadata_mapper.neuropixels import open_ephys_rig # type: ignore @@ -19,12 +20,30 @@ def test_etl(self): pathlib.Path("./tests/resources/neuropixels/settings.xml"), ], probe_manipulator_serial_numbers=[ - ('Ephys Assembly A', 'SN45356',), - ('Ephys Assembly B', 'SN45484', ), - ('Ephys Assembly C', 'SN45485', ), - ('Ephys Assembly D', 'SN45359', ), - ('Ephys Assembly E', 'SN45482', ), - ('Ephys Assembly F', 'SN45361', ), + ( + "Ephys Assembly A", + "SN45356", + ), + ( + "Ephys Assembly B", + "SN45484", + ), + ( + "Ephys Assembly C", + "SN45485", + ), + ( + "Ephys Assembly D", + "SN45359", + ), + ( + "Ephys Assembly E", + "SN45482", + ), + ( + "Ephys Assembly F", + "SN45361", + ), ], ) etl.run_job() @@ -32,18 +51,18 @@ def test_etl(self): assert self.load_updated() == self.expected def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, \ - self.load_updated, self._cleanup = \ - test_utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/open-ephys-rig.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = test_utils.setup_neuropixels_etl_dirs( + pathlib.Path("./tests/resources/neuropixels/open-ephys-rig.json"), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_open_ephys_rig_inferrred.py b/tests/test_neuropixels/test_open_ephys_rig_inferrred.py index 3b6f90a8..0e507901 100644 --- a/tests/test_neuropixels/test_open_ephys_rig_inferrred.py +++ b/tests/test_neuropixels/test_open_ephys_rig_inferrred.py @@ -1,7 +1,10 @@ """Tests for the neuropixels open ephys rig ETL with inferred probe mapping.""" -import unittest + import pathlib +import unittest + from aind_data_schema.core import rig # type: ignore + from aind_metadata_mapper.neuropixels import open_ephys_rig # type: ignore from . import utils as test_utils @@ -26,12 +29,30 @@ def test_etl(self): ), ], probe_manipulator_serial_numbers=[ - ('Ephys Assembly A', 'SN45356', ), - ('Ephys Assembly B', 'SN45484', ), - ('Ephys Assembly C', 'SN45485', ), - ('Ephys Assembly D', 'SN45359', ), - ('Ephys Assembly E', 'SN45482', ), - ('Ephys Assembly F', 'SN45361', ), + ( + "Ephys Assembly A", + "SN45356", + ), + ( + "Ephys Assembly B", + "SN45484", + ), + ( + "Ephys Assembly C", + "SN45485", + ), + ( + "Ephys Assembly D", + "SN45359", + ), + ( + "Ephys Assembly E", + "SN45482", + ), + ( + "Ephys Assembly F", + "SN45361", + ), ], ) etl.run_job() @@ -43,7 +64,8 @@ def test_etl_mismatched_probe_count(self): base_rig = rig.Rig.model_validate_json(self.input_source.read_text()) base_rig.ephys_assemblies.pop() base_rig.write_standard_file( - self.input_source.parent, prefix='mismatched') + self.input_source.parent, prefix="mismatched" + ) etl = open_ephys_rig.OpenEphysRigEtl( self.input_source.parent / "mismatched_rig.json", self.output_dir, @@ -58,30 +80,49 @@ def test_etl_mismatched_probe_count(self): ), ], probe_manipulator_serial_numbers=[ - ('Ephys Assembly A', 'SN45356', ), - ('Ephys Assembly B', 'SN45484', ), - ('Ephys Assembly C', 'SN45485', ), - ('Ephys Assembly D', 'SN45359', ), - ('Ephys Assembly E', 'SN45482', ), - ('Ephys Assembly F', 'SN45361', ), + ( + "Ephys Assembly A", + "SN45356", + ), + ( + "Ephys Assembly B", + "SN45484", + ), + ( + "Ephys Assembly C", + "SN45485", + ), + ( + "Ephys Assembly D", + "SN45359", + ), + ( + "Ephys Assembly E", + "SN45482", + ), + ( + "Ephys Assembly F", + "SN45361", + ), ], ) etl.run_job() def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, \ - self.load_updated, self._cleanup = \ - test_utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/" - "open-ephys-rig-inferred.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = test_utils.setup_neuropixels_etl_dirs( + pathlib.Path( + "./tests/resources/neuropixels/" "open-ephys-rig-inferred.json" + ), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_sync_rig.py b/tests/test_neuropixels/test_sync_rig.py index 1c7910b0..c7149054 100644 --- a/tests/test_neuropixels/test_sync_rig.py +++ b/tests/test_neuropixels/test_sync_rig.py @@ -1,6 +1,7 @@ """Tests for Sync rig ETL.""" -import unittest + import pathlib +import unittest from aind_metadata_mapper.neuropixels import sync_rig # type: ignore @@ -22,18 +23,18 @@ def test_etl(self): assert self.load_updated() == self.expected def setUp(self): - """Moves required test resources to testing directory. - """ + """Moves required test resources to testing directory.""" # test directory - self.input_source, self.output_dir, self.expected, self.load_updated, \ - self._cleanup = \ - utils.setup_neuropixels_etl_dirs( - pathlib.Path( - "./tests/resources/neuropixels/sync-rig.json" - ), - ) + ( + self.input_source, + self.output_dir, + self.expected, + self.load_updated, + self._cleanup, + ) = utils.setup_neuropixels_etl_dirs( + pathlib.Path("./tests/resources/neuropixels/sync-rig.json"), + ) def tearDown(self): - """Removes test resources and directory. - """ + """Removes test resources and directory.""" self._cleanup() diff --git a/tests/test_neuropixels/test_utils.py b/tests/test_neuropixels/test_utils.py index 7f3e43c2..145a939f 100644 --- a/tests/test_neuropixels/test_utils.py +++ b/tests/test_neuropixels/test_utils.py @@ -1,12 +1,13 @@ """Tests for the neuropixels rig utils.""" + import unittest + import pydantic from aind_metadata_mapper.neuropixels import utils # type: ignore class Child(pydantic.BaseModel): - """Test model to be nested in parent.""" name: str @@ -14,14 +15,12 @@ class Child(pydantic.BaseModel): class Parent(pydantic.BaseModel): - """Test model to be parent of child.""" children: list[Child] class Utils(unittest.TestCase): - """Tests for the neuropixels rig utils.""" def test_find_replace_append(self): @@ -31,8 +30,7 @@ def test_find_replace_append(self): parent = Parent( children=[ Child(name=name, value=untoggled_value) - for name in [ - "child0", target_child_name, "child2", "child3"] + for name in ["child0", target_child_name, "child2", "child3"] ] ) diff --git a/tests/test_neuropixels/utils.py b/tests/test_neuropixels/utils.py index 5d731a59..52f96833 100644 --- a/tests/test_neuropixels/utils.py +++ b/tests/test_neuropixels/utils.py @@ -1,14 +1,17 @@ """Utilities for neuropixels etl tests.""" + import datetime import pathlib import shutil -import typing import tempfile +import typing from aind_data_schema.core import rig # type: ignore from aind_data_schema.models import ( # type: ignore - coordinates, devices, organizations) - + coordinates, + devices, + organizations, +) COPA_NOTES = ( "The rotation matrix is represented as: a,b,c,d,e,f,g,h,i. Wherein a, b, " @@ -58,16 +61,14 @@ def init_rig() -> rig.Rig: ), coordinates.Axis( name=coordinates.AxisName.Y, - direction=( - "Pointing to the bottom edge of the sensor." - ), + direction=("Pointing to the bottom edge of the sensor."), ), coordinates.Axis( name=coordinates.AxisName.Z, direction=( "Positive moving away from the sensor towards the object." - ) - ) + ), + ), ], "notes": COPA_NOTES, } @@ -106,9 +107,15 @@ def init_rig() -> rig.Rig: device_position_transformations=[ coordinates.Rotation3dTransform( rotation=[ - -0.80914, -0.58761, 0, - -0.12391, 0.17063, 0.97751, - 0.08751, -0.12079, 0.02298, + -0.80914, + -0.58761, + 0, + -0.12391, + 0.17063, + 0.97751, + 0.08751, + -0.12079, + 0.02298, ], ), coordinates.Translation3dTransform( @@ -138,11 +145,11 @@ def init_rig() -> rig.Rig: name=coordinates.AxisName.Z, direction=( "Positive moving away from the screen." - ) - ) + ), + ), ], notes=COPA_NOTES, - ) + ), ), devices.Speaker( name="Speaker", @@ -152,9 +159,15 @@ def init_rig() -> rig.Rig: device_position_transformations=[ coordinates.Rotation3dTransform( rotation=[ - -0.82783, -0.4837, -0.28412, - -0.55894, 0.75426, 0.34449, - 0.04767, 0.44399, -0.89476 + -0.82783, + -0.4837, + -0.28412, + -0.55894, + 0.75426, + 0.34449, + 0.04767, + 0.44399, + -0.89476, ], ), coordinates.Translation3dTransform( @@ -184,13 +197,15 @@ def init_rig() -> rig.Rig: name=coordinates.AxisName.Z, direction=( "Positive moving away from the speaker." - ) - ) + ), + ), ], - notes=COPA_NOTES + ( + notes=COPA_NOTES + + ( " Speaker to be mounted with the X axis pointing to " - "the right when viewing the speaker along the Z axis"), - ) + "the right when viewing the speaker along the Z axis" + ), + ), ), devices.RewardDelivery( reward_spouts=[ @@ -228,7 +243,8 @@ def init_rig() -> rig.Rig: manipulator=devices.Manipulator( name=f"Ephys Assembly {assembly_letter} Manipulator", manufacturer=( - organizations.Organization.NEW_SCALE_TECHNOLOGIES), + organizations.Organization.NEW_SCALE_TECHNOLOGIES + ), model="06591-M-0004", ), probes=[ @@ -237,7 +253,7 @@ def init_rig() -> rig.Rig: probe_model="Neuropixels 1.0", manufacturer=organizations.Organization.IMEC, ) - ] + ], ) for assembly_letter in ["A", "B", "C", "D", "E", "F"] ], @@ -306,17 +322,23 @@ def init_rig() -> rig.Rig: device_position_transformations=[ coordinates.Rotation3dTransform( rotation=[ - -0.17365, 0.98481, 0, - 0.44709, 0.07883, -0.89101, - -0.87747, -0.15472, -0.45399, + -0.17365, + 0.98481, + 0, + 0.44709, + 0.07883, + -0.89101, + -0.87747, + -0.15472, + -0.45399, ] ), coordinates.Translation3dTransform( translation=[0.154, 0.03078, 0.06346], - ) + ), ], - **shared_camera_assembly_relative_position_props - ) + **shared_camera_assembly_relative_position_props, + ), ), devices.CameraAssembly( name=SIDE_CAMERA_ASSEMBLY_NAME, @@ -347,10 +369,10 @@ def init_rig() -> rig.Rig: ), coordinates.Translation3dTransform( translation=[-0.03617, 0.23887, -0.02535], - ) + ), ], - **shared_camera_assembly_relative_position_props - ) + **shared_camera_assembly_relative_position_props, + ), ), devices.CameraAssembly( name=EYE_CAMERA_ASSEMBLY_NAME, @@ -371,7 +393,8 @@ def init_rig() -> rig.Rig: lens=devices.Lens( name="Eye lens", manufacturer=( - organizations.Organization.INFINITY_PHOTO_OPTICAL), + organizations.Organization.INFINITY_PHOTO_OPTICAL + ), focal_length=6.0, focal_length_unit="millimeter", model="213073", @@ -381,18 +404,24 @@ def init_rig() -> rig.Rig: device_position_transformations=[ coordinates.Rotation3dTransform( rotation=[ - -0.5, -0.86603, 0, - -0.366, 0.21131, -0.90631, - 0.78489, -0.45315, -0.42262, + -0.5, + -0.86603, + 0, + -0.366, + 0.21131, + -0.90631, + 0.78489, + -0.45315, + -0.42262, ] ), coordinates.Translation3dTransform( translation=[-0.14259, 0.06209, 0.09576], - ) + ), ], - **shared_camera_assembly_relative_position_props - ) - ) + **shared_camera_assembly_relative_position_props, + ), + ), ], daqs=[ devices.DAQDevice( @@ -473,7 +502,7 @@ def init_rig() -> rig.Rig: coordinates.Axis( name=coordinates.AxisName.Z, direction="Positive pointing up.", - ) + ), ], origin=coordinates.Origin.BREGMA, patch_cords=[ @@ -497,11 +526,11 @@ def init_rig() -> rig.Rig: def setup_neuropixels_etl_dirs( expected_json: pathlib.Path, ) -> tuple[ - pathlib.Path, - pathlib.Path, - rig.Rig, - typing.Callable[[], rig.Rig], - typing.Callable[[], None] + pathlib.Path, + pathlib.Path, + rig.Rig, + typing.Callable[[], rig.Rig], + typing.Callable[[], None], ]: """Sets up a temporary input/output directory context for neuropixels etl.